2016-06-28 11 views
3

私は次のようである持っているサンプルデータ、チェック

main_data = data.frame(var1 = c('abd_cde', 'BPCS', 'POIU', 'CDRD', 'UPqw', 'qwer')), 

main_data

 var1 
1 abd_cde 
2 BPCS 
3 POIU 
4 CDRD 
5 UPqw 
6 qwer 

私はいくつかの条件を確認したい、次のコードを持っていますある変数に別の変数を出力します。以下は、それがBまたはCで始まる場合、出力2にしたい、私は変数iが出力1にしたい、「_」が含まれている場合、コードの要点を与えるために、

main_data$var2 = 0 

for (i in 1:nrow(main_data)) { 
    if(grepl("_", main_data$var1[i]) == TRUE){ 
    main_data$var2[i] = "1" 
    } 
    else if((substr(main_data$var1[i], 1, 1) == 'B') | (substr(main_data$var1[i], 1, 1) == 'C')){ 
    main_data$var2[i] = "2" 
    } 
    else if((substr(main_data$var1[i], 1, 1) == 'P') | (substr(main_data$var1[i], 1, 1) == 'U')){ 
    main_data$var2[i] = "3" 
    } 

} 

を書かれているコードですPまたはUで始まる場合は3を出力したい。

しかし、このコードは実行に約200万のレコードがあるので、実行には多くの時間がかかります。これを効率化できる方法はありますか?

私の理想的な出力は次のようになり、

 var1 var2 
1 abd_cde  1 
2 BPCS  2 
3 POIU  3 
4 CDRD  2 
5 UPqw  3 
6 qwer  0 

は、誰もがこれを行うに私を助けることができますか?

おかげ

あなたは(例えば、複数の ifelse文を使用して)単一の式にこれを組み合わせることができ、これは読み非常に簡単ですし、ループよりも高速である必要があり
+0

これを再現可能な例にすることはできますか?お読みください:http://stackoverflow.com/help/mcve –

+0

あなたのリストのどの条件も満たされない場合はどうなりますか? – Psidom

+0

@Psidom私は基底として0を持っています、それらのどれも満足されなければ、それは0 – haimen

答えて

3

> x <- c("foo_bar", "x_y", "Bxx", "Cxx", "Pzz", "Uzz") 
> x[grepl('_', x)] <- 1 
> x[grepl('^[BC]', x)] <- 2 
> x[grepl('^[PU]', x)] <- 3 

> x 
[1] "1" "1" "2" "2" "3" 

あなただけたい場合1文字で始まる文字列をテストするには、startsWith関数も機能します。

3

スピードが必要な場合、Rcppはオプションです。 RcppライブラリとC++標準ライブラリを組み合わせて、多くのことを達成できます。例えば、ここでは、アンダースコア、いくつかの配列のインデックス、文字の比較、および三元チェーンを見つけるために、std::strchr()を使用して、あなたの要件を実装することができます方法は次のとおりです。

library(Rcpp); 
cppFunction(includes='#include <cstring>',' 
    IntegerVector f1(CharacterVector x) { 
     IntegerVector res(x.size()); 
     char c; 
     for (int i = 0; i < x.size(); ++i) 
      res[i] = 
       std::strchr(x[i],\'_\') ? 1 : 
       (c = x[i][0])==\'B\' || c==\'C\' ? 2 : 
       c==\'P\' || c==\'U\' ? 3 : 
       0 
      ; 
     return res; 
    } 
'); 

f1(main_data$var1); 
## [1] 1 2 3 2 3 0 
3

dplyrの最新バージョン(0.5.0)は、新しい付属していますcase_when厄介なネストをifelse構造体が不要にする関数。あなたはstartsWith(HT @Psidom)や昔ながらgreplでそれを実装することができます

library(dplyr) 

       # string functions don't like factors 
main_data %>% mutate(var1 = as.character(var1)) %>% 
    # for each case (in order), if the left side is true, return the right side 
    mutate(var2 = case_when(grepl('_', .$var1, fixed = TRUE) ~ 1, 
          startsWith(.$var1, 'B') | startsWith(.$var1, 'C') ~ 2, 
          startsWith(.$var1, 'P') | startsWith(.$var1, 'U') ~ 3, 
          TRUE ~ 0)) 

#  var1 var2 
# 1 abd_cde 1 
# 2 BPCS 2 
# 3 POIU 3 
# 4 CDRD 2 
# 5 UPqw 3 
# 6 qwer 0 

# or with grepl (results are identical) 
main_data %>% mutate(var1 = as.character(var1)) %>% 
    mutate(var2 = case_when(grepl('_', .$var1, fixed = TRUE) ~ 1, 
          grepl('^[BC]', .$var1) ~ 2, 
          grepl('^[PU]', .$var1) ~ 3, 
          TRUE ~ 0)) 

dplyr奇数ですが、いくつかの理由のために必要であるように思わ.$var1表記。

これもかなりうんざりしているようです。 dplyrはここにあるようにCでたくさん動こうとします。ただ、@ bgoldstのRcppに対して、コメントからPsidomのdata.table @(明らかに現実的ではない)テストセット上で実行します。

Unit: microseconds 
     expr  min  lq  mean median  uq  max neval 
startsWith 1285.372 1384.862 1593.404 1478.276 1689.269 6547.404 100 
     grepl 1260.778 1395.494 1575.984 1509.890 1752.506 2258.982 100 
     rcpp 3783.274 4101.735 4562.076 4361.927 4637.183 10818.012 100 
data.table 913.635 1069.397 1180.042 1135.440 1290.791 1567.259 100 

100,000行にリサンプリング(おそらくまだ代表ではない、ボンネットの下に何が起こっているかに依存します) Rcppは予想通り引き離さ、:

Unit: milliseconds 
     expr  min   lq  mean  median   uq  max neval 
startsWith 21.288367 27.555653 30.904011 29.611775 34.269493 40.80770 100 
     grepl 57.025665 60.209641 63.748722 62.204733 66.900175 73.81332 100 
     rcpp 8.090686 8.545949 9.419899 8.764327 9.567707 24.65368 100 
data.table 92.093603 100.449884 107.358620 104.229641 107.24.52098 100 

タイムズ紙は関係なく、var1が要因かな文字であるかどうかの類似しています。

1

これは、Rで文字列関数を使用するより簡単な方法です。これは、Keithが言及したのと同様です。

main_data = data.frame(var1 = c('abd_cde', 'BPCS', 'POIU', 'CDRD', 'UPqw', 'qwer')) 
main_data$var2<-ifelse(grepl("_",main_data$var1),1,ifelse(grepl("B.*|C.*",main_data$var1),2,ifelse(grepl("P.*|U.*",main_data$var1),3,0))) 

ここでは、ifelse()を使用してすべての行を調べ、必要な結果を得ました。