この質問は、reshape2 の dcast を使用して作成できるテーブルに似た「ワイド」テーブルの作成に関するものです。これはこれまで何度も議論されてきたことですが、私の質問はプロセスをより効率的にする方法に関するものです。以下にいくつかの例を挙げましたが、質問が長くなるかもしれませんが、そのほとんどはベンチマーク用のテスト コードです。
簡単な例から始めましょう。
> z <- data.table(col1=c(1,1,2,3,4), col2=c(10,10,20,20,30),
col3=c(5,2,2.3,2.4,100), col4=c("a","a","b","c","a"))
> z
col1 col2 col3 col4
1: 1 10 5.0 a # col1 = 1, col2 = 10
2: 1 10 2.0 a # col1 = 1, col2 = 10
3: 2 20 2.3 b
4: 3 20 2.4 c
5: 4 30 100.0 a
col4 列の値を列名として持ち、col1 と col2 の各組み合わせの合計 (col3) の値を持つ「ワイド」テーブルを作成する必要があります。
> ulist = unique(z$col4) # These will be the additional column names
# Create long table with sum
> z2 <- z[,list(sumcol=sum(col3)), by='col1,col2,col4']
# Pivot the long table
> z2 <- z2[,as.list((sumcol[match(ulist,col4)])), by=c("col1","col2")]
# Add column names
> setnames(z2[],c("col1","col2",ulist))
> z2
col1 col2 a b c
1: 1 10 7 NA NA # a = 5.0 + 2.0 = 7 corresponding to col1=1, col2=10
2: 2 20 NA 2.3 NA
3: 3 20 NA NA 2.4
4: 4 30 100 NA NA
私が抱えている問題は、上記の方法は小さなテーブルには適していますが、非常に大きなテーブルでは実行することが事実上不可能であるということです (おそらく x 時間待つことに問題がない限り)。
これは、ピボットされたワイド テーブルのサイズが元のテーブルよりもはるかに大きいという事実に関係していると思われます。ワイド テーブルの各行には、そのセルに対応する値があるかどうかに関係なく、ピボット列の一意の値に対応する n 列があるためです (これらは上記の NA 値です)。したがって、新しいテーブルのサイズは、元の「長い」テーブルの 2 倍以上になることがよくあります。
元のテーブルには約 5 億行、約 20 個の一意の値があります。500 万行のみを使用して上記を実行しようとしましたが、R では永遠に時間がかかります (完了するまで待つには長すぎます)。
ベンチマークの目的で、この例 (500 万行を使用) は、マルチスレッドで稼働している実稼働 RDBMS システムを使用して約 1 分で完了します。KDB+/Q を使用したシングル コアでは約 8 秒で完了します (http://www.kx.com) 公平な比較ではないかもしれませんが、別の手段を使用すればこれらの操作をはるかに高速に実行できるという印象を受けます。KDB+ にはスパース行がないため、すべてのセルにメモリを割り当てており、それでも私が試した他のどの方法よりもはるかに高速です。
しかし、私が必要としているのはRソリューションです:) そして今のところ、同様の操作を効率的に実行する方法を見つけていません。
経験があり、代替案やより最適な解決策について考えることができる場合は、ぜひ教えてください。サンプル コードを以下に示します。結果をシミュレートするには、n の値を変えることができます。ピボット列 (列 c3) の一意の値は 25 に固定されています。
n = 100 # Increase this to benchmark
z <- data.table(c1=sample(1:10000,n,replace=T),
c2=sample(1:100000,n,replace=T),
c3=sample(1:25,n,replace=T),
price=runif(n)*10)
c3.unique <- 1:25
z <- z[,list(sumprice=sum(price)), by='c1,c2,c3'][,as.list((sumprice[match(c3.unique,c3)])), by='c1,c2']
setnames(z[], c("c1","c2",c3.unique))
ありがとう、
- ラジ。
ベストアンサー1
n=1e6
以下の場合、プレーンテキストでは約 10 秒、dcast
では約 4 秒かかりますdcast.data.table
。
library(reshape2)
dcast(z[, sum(price), by = list(c1, c2, c3)], c1 + c2 ~ c3)
# or with 1.8.11
dcast.data.table(z, c1 + c2 ~ c3, fun = sum)