R 将海量数据从长格式改为宽格式的有效方法-类似于dcast

R 将海量数据从长格式改为宽格式的有效方法-类似于dcast,r,parallel-processing,data.table,R,Parallel Processing,Data.table,这个问题与创建“宽”表有关,类似于您可以从Reforma2使用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(

这个问题与创建“宽”表有关,类似于您可以从Reforma2使用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
>z
col1 col2 col3 col4
1:1105.0A#col1=1,col2=10
2:1102.0A#col1=1,col2=10
3:2202.3B
4:3202.4摄氏度
5:430100.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
>ulist=unique(z$col4)#这些将是附加的列名
#使用sum创建长表
>z2 z2集合名(z2[],c(“col1”,“col2”,ulist))
>z2
col1 col2 a b c
1:1107NaNa#a=5.0+2.0=7对应于col1=1,col2=10
2:220NA 2.3NA
3:320Na2.4
4:430100NA
我遇到的问题是,虽然上述方法适用于较小的表,但实际上不可能在非常大的表上运行它们(除非您可以等待x小时)

我认为这可能与以下事实有关:数据透视/宽表的大小比原始表大得多,因为宽表中的每一行都有n列对应于数据透视列的唯一值,而不管是否有任何值对应于该单元格(这些是上面的NA值)。因此,新表的大小通常是原始“长”表的2倍

我的原始表有大约5亿行,大约20个唯一值。我曾尝试只使用500万行运行上面的代码,但在R中需要花费很长时间(等待它完成的时间太长)

出于基准测试的目的,该示例(使用500万行)使用运行多线程的生产rdbms系统在大约1分钟内完成。使用单核KDB+/Q()大约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))
n=100#将其增加到基准

z对于
n=1e6
,使用普通
dcast
大约需要10秒,使用
dcast.data.table大约需要4秒:

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)

你能把你的KDB代码包括进来吗?顺便说一句,@Arun已经在用C编写一个快速dcast了。@xbsd,是的,正如@MatthewDowle提到的,我正在用C实现
dcast
。完成后,我会用基准更新帖子。@Arun--文件:code:R时间:27.759秒,Q时间:11.543秒。应该添加——这些操作可以使用不同的方法在Q中并行化。我尝试过使用R进行类似的操作,通常是使用并行、多核、doMC等包,还尝试过分块数据,以map reduce方式顺序处理数据集的段。不幸的是,这些几乎“总是”导致seg故障。这些测试中的数据集大小约为35 GB+。@xbsd,好吧,我刚刚在当前的C版本的cast上进行了基准测试。。。好消息!您的数据在C-version上以12秒的时间运行,而在我的(慢速)笔记本电脑上以40秒的时间运行data.table代码。因此,基本上它看起来像是3.3倍的加速(大致)。希望这会比KDB方法更快。希望我能进一步优化它。。。我会尽快总结并提交,然后发布/更新答案。@Arun。。。哇,我能说什么!:)这样的表演会让很多人非常高兴(革命R的人也不会那么高兴…)。让我知道一旦你有它在svn。想在原始数据集上试用。@Arun我不明白你的第1点-为什么要花时间将
数据.table
转换为
数据.frame
?关于第2点-你说得对,大约快了20%(所以我改为编辑了该版本)