有效的方法减去两个具有不同行数的非常大的数据帧(匹配XYZ)

时间:2015-08-14 11:22:25

标签: r dataframe parallel-processing large-data

我有一对非常大的data.frames df1& df2(> 500,000行)具有不同的行数,两者都包含相同的4列(X,Y,Z坐标和计数属性)。 Doomie的例子:

df1<-data.frame(x=c(3,5,2,4),y=c(8,5,7,6),z=c(13,15,12,10),
      count=c(10,20,4,12))
df2<-data.frame(x=c(4,3,6),y=c(6,9,8),z=c(10,13,15),count=c(4,7,3))

我想仅为匹配XYZ(相同空间点)的行减去计数列(df1$count - df2$count)。我找到了一种方法,通过使用函数merge() {base}来实现它,但它很慢并且df非常大。

任何提示我怎么能让它更快?我应该尝试引入并行处理吗?任何提示如何与这样的例子并行执行它而不需要在块中切割​​df?

感谢。

我的实施:

df3<-merge(df1,df2,by.x=c("x","y", "z"),by.y=c("x","y", "z"),all.x=T,all.y=TRUE)
df3[is.na(df3$count.x),4]<-0
df3[is.na(df3$count.y),5]<-0
df3$countdif<-df3$count.y-df3$count.x

新编辑。 答案: Akrun的答案中的2条建议工作正常。第一个在微基准测试中的速度提高了2倍,并且也适用于我的大型数据帧。这里是他们的基准:

使用dplyr {}

dodplyr<- function (a,b){
    dfN<- full_join(a,b, by=c('x', 'y', 'z')) %>%
        mutate_each(funs(replace(., which(is.na(.)), 0)), 
                starts_with('count')) %>%  
        mutate(countdif= count.y-count.x)
    dfN<-select(dfN,-count.x,-count.y)
    return(dfN)
}

并使用data.table {}

dodata.table<-function(a,b){
    setDT(a)
    setDT(b)
    DT <- merge(a,b, by=c('x', 'y', 'z'), all=TRUE)
    for(j in 4:5){set(DT, i=which(is.na(DT[[j]])), j=j, value=0)}
    DT[, countdif:= count.y-count.x]
    DT[,c("count.x","count.y"):=NULL]
    return(DT)
}

微基准测试:

times <- microbenchmark( dodplyr(df1,df2), dodata.table(df1,df2), times=1e3)
> times
Unit: milliseconds
                   expr      min       lq     mean   median       uq      max neval
      dodplyr(df1, df2) 2.374164 2.489710 2.978814 2.590829 2.704017 18.15356  1000
 dodata.table(df1, df2) 5.094271 5.308994 6.458764 5.534259 5.675328 37.23370  1000

但是我无法将它们与使用merge {base}和dfs的实现进行比较。我尝试包含它,但在调用microbenchmark时遇到错误。在这里我尝试了:

domerge<- function(a,b){
  dfm<-merge(a,b,by.x=c("x","y", "z"),by.y=c("x","y", "z"),all.x=T,all.y=TRUE)
  dfm[is.na(dfm$count.x),4]<-0
  dfm[is.na(dfm$count.y),5]<-0
  dfm$countdif<-dfm$count.y-dfm$count.x
  dfm<-dfm[,c(1:3,6)]
  return(dfm)
}

在调用时可以正常工作,例如df3<-domerge(df1,df2)但是在微基准测试时会出错:

> times <- microbenchmark(domerge(df1,df2), dodplyr(df1,df2), dodata.table(df1,df2), times=1e3)

Show Traceback

 Rerun with Debug
 Error in merge.data.table(a, b, by.x = c("x", "y", "z"), by.y = c("x",  : 
  Can not match keys in x and y to automatically determine appropriate `by` parameter. Please set `by` value explicitly.

1 个答案:

答案 0 :(得分:0)

你必须创建一个像这个例子一样减去的算法:

(如果他们有一个独立的ALU)

y=1
while y <= "end.of.y"
 Core one > df1={1,1,y} - df2={1,1,y}
 //you subtract the y until the end of y column is reached 
 //saving in another matrix called as you want, then
 Core two > df1={1,1,y+1} - df2={1,1,y+1}
 ...
 Core eight > df1={1,1,y+7} - df2={1,1,y+7}
 y=y+8 
endwhile

对另一个轴x和z(嵌套循环循环)执行相同操作。直到他们的目的结束。

如果您只在处理器中有4个ALU,则必须执行相同操作,但仅使用4个核心&#39;

我希望这会有所帮助。