2013-02-20 10 views
13

私のdata.tableに新しい列を追加したいと思います。この列には、特定の条件を満たすすべての行の別の列の合計が含まれている必要があります。例:( - T [X] Tが[i])と< = 10、私は条件のdata.tableを自己結合する方法

を計算したいすべての行xと行ごとに

require(data.table) 
DT <- data.table(n=c("a", "a", "a", "a", "a", "a", "b", "b", "b"), 
      t=c(10, 20, 33, 40, 50, 22, 25, 34, 11), 
      v=c(20, 15, 16, 17, 11, 12, 20, 22, 10) 
      ) 
DT 
    n t v 
1: a 10 20 
2: a 20 15 
3: a 33 16 
4: a 40 17 
5: a 50 11 
6: a 22 12 
7: b 25 20 
8: b 34 22 
9: b 11 10 

私、ABSは、ここで私のdata.tableは、このようになります

foo = sum(v[i] * abs(t[i] - t[x])) 

SQLでは、自己結合を使用してこれを解決します。

for (i in 1:nrow(DT)) 
    DT[i, foo:=DT[n==DT[i]$n & abs(t-DT[i]$t)<=10, sum(v * abs(t-DT[i]$t))]] 

DT 
    n t v foo 
1: a 10 20 150 
2: a 20 15 224 
3: a 33 16 119 
4: a 40 17 222 
5: a 50 11 170 
6: a 22 12 30 
7: b 25 20 198 
8: b 34 22 180 
9: b 11 10 0 

は、残念ながら、私はかなり頻繁にこれをしなければならないと私が一緒に仕事表がかなり大きい:Rで私は、forループを使用して、これを行うことができました。 forループアプローチは機能しますが、遅すぎます。私は本当のブレークスルーを伴わずにsqldfパッケージを使いました。私はいくつかのdata.table魔法を使ってこれをやりたいと思います。あなたの助けが必要です:-)。私は、必要とされるのは、t値の差が閾値より小さいという条件で、何らかの自己結合であると思います。

フォローアップ: フォローアップの質問があります。私のアプリケーションでは、この結合は何度も何度も繰り返されています。 vの変化ですが、tとnは常に同じです。だから私は何とか一緒に属している行を格納することを考えています。どのように賢い方法でこれを行うための任意のアイデア?

+0

出力から、 'i!= x'という条件も正しいように見えますか? –

+0

いいえ。項abs(t-DT [i] $ t)== 0であるため、行9 foo = 0の場合。しかし、私のアプリケーションでの計算がこの例のようにもう少し複雑で、そこにx行が必要なので、i!= xは除外すべきではありません。 – uuazed

答えて

5

次のことを試してみてください:上記の行ため

unique(merge(DT, DT, by="n")[abs(t.x - t.y) <= 10, list(n, sum(v.x * abs(t.x - t.y))), by=list(t.x, v.x)]) 

内訳:あなたは自分自身でテーブルをマージすることができます

、出力もdata.tableになります。あなただけフィルタリングし、任意のDT

# this will give you your desired rows 
[abs(t.x - t.y), ] 

# this is the expression you outlined 
[ ... , sum(v.x * abs(t.x - t.y)) ] 

# summing by t.x and v.x 
[ ... , ... , by=list(t.x, v.x)]) ] 

と同様に計算することができます...列名が.xの接尾辞と.y

merge(DT, DT, by="n") 

を与えられることに注意してくださいそして、最終的に削除するためにuniqueでそれをすべてを包みます複製された行。


UPDATE:これは、コメントすることなく、以下の行は、あなたの出力に一致するものです

長すぎるすべきです。これとこの回答の先頭にある唯一の違いは、v.yという語がsum(v.y * ...)にありますが、byの文はまだv.xです。それは意図的なのでしょうか?

unique(merge(DT, DT, by="n")[abs(t.x - t.y) <= 10, list(n, sum(v.y * abs(t.x - t.y))), by=list(t.x, v.x)]) 
+0

ありがとう!これは、サンプルのforループアプローチの約6倍高速です。今実際のデータでこれを試してみましょう... – uuazed

+0

面白いことに、私は 'v.x'を使用しています。あなたは' v.y'を使用しているようです。どちらがあなたの計算を期待していますか? –

+0

マージについて。標準のマージ関数を使用しています。 DT [DT]のようなdata.tableマージは速くなければなりませんか? – uuazed

11

偉大な質問です。この答えは、実際にはリカルドの答えと一緒にテイスターに過ぎません。

理想的には、効率のために大きなデカルト自己結合を避けたいと考えています。残念ながらrange joins (FR#203)はまだ実装されていません。その間、非常に最新のv1.8を使用します。7(未テスト):FR#203が行われる

setkey(DT,n,t) 
DT[,from:=DT[.(n,t-10),which=TRUE,roll=-Inf,rollends=TRUE]] 
DT[,to:=DT[.(n,t+10),which=TRUE,roll=+Inf,rollends=TRUE]] 
DT[,foo:=0L] 
for (i in 1:nrow(DT)) { 
    s = seq.int(DT$from[i],DT$to[i]) 
    set(DT, i, "foo", DT[,sum(v[s]*abs(t[s]-t[i]))]) 
} 

と、上記ロジックが内蔵されるであろう、そしてそれは、一のライナーなるべき:そこiテーブルの

setkey(DT,n,t) 
DT[.(n,.(t-10,t+10),t), foo:=sum(v*abs(t-i.t))] 

第二カラム2列の列です(の間を示します)。いつものように、jは、巨大デカルト・セルフ・ジョイン・テーブルを作成することなく、iの各行に対して評価されるため、速くなければなりません。

これは、とにかく現在の考えです。

+0

data.table v1.8.7がリリースされたら、それを試してみます – uuazed

+0

FR#203は既に実装されていますか?私はSOで次のような質問をしました。あなたの提案から恩恵を受けると思います。 http://stackoverflow.com/questions/29100911/r-data-table-self-join-on-condition-using-a-matrix – Picarus