2016-07-17 2 views
-2

は、例えば、データ、コードと問題の説明です:この条件付き結合を高速化するには(forループが遅い)?ここ

require(data.table) 
require(dplyr) 
df1 <- read.table(text= " 
     col1  col2 col3 col4 col5 
     123   121 16519 1  4 
     123   121 16519 2  5 
     123   121 16518 3  5 
     123   121 16517 4  6 
     123   121 16512 5  7 
     123   121 16554 6  8 
     124   333 16554 7  9 
     124   333 16552 8  5 
     124   333 16549 1  1 
     124   333 16495 2  2 
     124   555 16573 4  4 
     125   555 16573 5  3 
     125   555 16569 6  5 
     125   555 16567 7  6 
     125   555 16568 8  7 
", header=TRUE, na.strings=NA, stringsAsFactors=FALSE) 

df2 <- distinct(df1[c("col1","col2","col3")]) 
setnames(df2, old=c("col1","col2","col3"), new=c("col11","col22","col33")) 

res <- vector("list", nrow(df2)) 
for(i in 1:nrow(df2)) { 
    one_row <- df2[i,] 
    df <- merge(select(one_row, col11, col22, col33), 
      select(df1,col1,col2,col3,col4,col5),by=NULL)%>% 
      filter((col3 >= (col33-(7))) & (col3 < col33)) 

    res[[i]] = df%>% 
       group_by(col11, col22,col33)%>% 
       summarise(Averagecol4=mean(col4,na.rm=TRUE), Count=n()) 
} 

as.data.frame(do.call("rbind", res)) 
# col11 col22 col33 Averagecol4 Count 
# 1 123 121 16519   4.0  3 
# 2 123 121 16518   4.5  2 
# 3 123 121 16517   5.0  1 
# 4 123 121 16554   4.5  2 
# 5 124 333 16554   4.5  2 
# 6 124 333 16552   1.0  1 
# 7 124 555 16573   7.0  3 
# 8 125 555 16573   7.0  3 
# 9 125 555 16569   7.5  2 
# 10 125 555 16568   7.0  1 
  1. コードがdata.frameを作成します。
  2. は、次に次にDF2の列名の名前を変更する3つの列
  3. の唯一明確な(またはユニーク)の組み合わせを考慮して、そこから別のdata.frameを作成します。
  4. resを作成し、df2の各行に対して、df1で結合を実行し、条件付きフィルタリングを実行し、対応するインデックスresに結果を格納します。
  5. rbind最終結果はdata.frameです。

問題は、nrow(df1) = ~225,000の場合、多くの時間がかかります。どうすればスピードアップできますか?

+0

あなたのコードはすぐにエラーになります。 'setnames'はどこからですか?それは 'setNames'の別のバージョンですか? – alistaire

+0

@alistaire指摘してくれてありがとう。その固定! – KGarg

+0

まだ 'res'がdata.frameとして終わっていないので、エラーが出ています。より良い質問:あなたの希望する出力は何ですか? – alistaire

答えて

1

は、ここで新しい非エクイを使用してdata.tableソリューションはdevelopment version of data.table, v1.9.7で現在利用可能な、機能に参加しています:

をインストール手順については、リンクを参照してください。 (data.frameである)df1から始めて、ここで私が進みたい方法は次のとおりです。

require(data.table) # v1.9.7+ 
df2 = setDT(df1)[, .N, by = col1:col3][, col3_minus_7 := col3 - 7] ## (1) 
ans = df1[df2,              ## (2) 
     on = .(col3 >= col3_minus_7, col3 < col3),     ## (3) 
     .(col1 = i.col1, col2 = i.col2, 
      mean = mean(col4, na.rm=TRUE), count = .N),   ## (4) 
     by = .EACHI,            ## (5) 
     nomatch = 0L,            ## (6) 
     allow.cartesian = TRUE]         ## (7) 
setnames(ans, 1:2, c("col3_minus_7", "col3"))      ## (8) 
#  col3_minus_7 col3 col1 col2 mean count 
# 1:  16512 16519 123 121 4.0  3 
# 2:  16511 16518 123 121 4.5  2 
# 3:  16510 16517 123 121 5.0  1 
# 4:  16547 16554 123 121 4.5  2 
# 5:  16547 16554 124 333 4.5  2 
# 6:  16545 16552 124 333 1.0  1 
# 7:  16566 16573 124 555 7.0  3 
# 8:  16566 16573 125 555 7.0  3 
# 9:  16562 16569 125 555 7.5  2 
# 10:  16561 16568 125 555 7.0  1 

[1]一意の行(col1, col2, col3によってグループ化しながら、間接的にカウントを生成することにより、 - ちょうど別の方法)を取得し、追加します新しい列、col3_minus_7、これは後で結合条件として必要になります。

[2] df1[df2, - df2の各行について、一致する行インデックスを探すのはdf1です。

[3]の条件に基づいて:on = .(col3 >= col3_minus_7, col3 < col3)、即ち、df1$col3 >= df2$col3_minus_7及びdf1$col3 < df2$col3

[4] + [5] df2.EACHI)のための一致する行については、所望の発現を(平均および他のCOLSと一緒にカウント)を計算します。 by=.EACHIhereについて詳しく読む。

[6] に指定された条件に一致する行がない場合、何も返しません。

[7] allow.cartesianは、誤った無効な結合を保護するための引数です。それについてはhereを読んでください。

[8]間隔列の名前を手動で変更してください(今のところ、自動的に間もなく自動的に処理されます)。

+0

あなたのソリューションに感謝します。しかし、次のエラーが表示されます。 '[.data.table'(setDT(df1)、、.N、= col1:col3)のエラー: ' by 'または' keyby 'リストの項目は長さです(16397 )。それぞれは、xの行またはi(15)が返す行の数と同じ長さでなければなりません。また :警告メッセージ:COL1で:最初 2使用:COL3: 数式15個の要素を有する。数式15個の要素を有する :COL1で:COL3 1 最初私は言及しなかった – KGarg

+0

使用されるもの*開発バージョン*が必要で、インストール方法を示すリンクが用意されています。 – Arun

+0

私はv1.9.7を取得するためにこれに従っていますが、まだv1.9.6を取得しています。data.tableの開発版をインストールします。 install.packages( "data.table"、type = "source"、 repos = "http:// ( "data.table") install.packages( "data.table")#その後、再インストールしてください。 CRANバージョン – KGarg

関連する問題