23

この質問は、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 の各組み合わせの sum(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 ( http://www.kx.com )を使用したシングル コアを使用すると、約 8 "秒" で完了します。公正な比較ではないかもしれませんが、代替手段を使用すると、これらの操作をはるかに高速に実行できるという感覚が得られます。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))

ありがとう、

  • ラージ。
4

1 に答える 1

5

次の場合n=1e6、プレーンdcastでは約 10 秒、 では約 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)
于 2013-12-04T22:28:59.447 に答える