减去两个具有不同行数(匹配 XYZ)的非常大的数据帧的有效方法
efficient way substracting two very large data frames with different number of rows (matching XYZ)
我有一对非常大的 data.frames df1 和 df2(>500,000 行),行数不同,它们都包含相同的 4 列(X、Y、Z 坐标和计数属性)。末日例子:
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 的实现进行比较。我试图包含它,但在调用微基准时出现错误。这是我尝试过的:
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.
我猜测 dplyr
中的 full_join
相对于 merge
会更快(尽管未测试)。在我们完成 full_join
后,'count' 列中的 'NAs' 使用 mutate_each
由 '0' 进行 replace
d,然后我们创建 'countdif' 列使用 mutate
library(dplyr)
dfN <- full_join(df1,df2, by=c('x', 'y', 'z')) %>%
mutate_each(funs(replace(., which(is.na(.)), 0)),
starts_with('count')) %>%
mutate(countdif= count.y-count.x)
dfN
# x y z count.x count.y countdif
#1 3 8 13 10 0 -10
#2 5 5 15 20 0 -20
#3 2 7 12 4 0 -4
#4 4 6 10 12 4 -8
#5 3 9 13 0 7 7
#6 6 8 15 0 3 3
或者使用 data.table
中的 merge.data.table
的可能方法。我们将 'data.frame' 都转换为 'data.table'(setDT(df1)
、setDT(df2)
)。然后,使用 merge.data.table
执行 full-join
。我们在 for
循环中用 set
将 'count' 列中的 'NA' 值替换为 0(这里是第 4 和第 5 列)(set
非常高效,因为它没有 .[data.table
开销。我们分配 (:=
) 新列 'countdif` 作为 'count.y' 和 'count.x'
之间的差异
library(data.table)
setDT(df1)
setDT(df2)
DT <- merge(df1, df2, 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
# x y z count.x count.y countdif
#1: 2 7 12 4 0 -4
#2: 3 8 13 10 0 -10
#3: 3 9 13 0 7 7
#4: 4 6 10 12 4 -8
#5: 5 5 15 20 0 -20
#6: 6 8 15 0 3 3
你必须创建一个像这个例子那样减去的算法:
(如果他们有一个独立的 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 个 'cores'
希望对您有所帮助。
我有一对非常大的 data.frames df1 和 df2(>500,000 行),行数不同,它们都包含相同的 4 列(X、Y、Z 坐标和计数属性)。末日例子:
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 的实现进行比较。我试图包含它,但在调用微基准时出现错误。这是我尝试过的:
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.
我猜测 dplyr
中的 full_join
相对于 merge
会更快(尽管未测试)。在我们完成 full_join
后,'count' 列中的 'NAs' 使用 mutate_each
由 '0' 进行 replace
d,然后我们创建 'countdif' 列使用 mutate
library(dplyr)
dfN <- full_join(df1,df2, by=c('x', 'y', 'z')) %>%
mutate_each(funs(replace(., which(is.na(.)), 0)),
starts_with('count')) %>%
mutate(countdif= count.y-count.x)
dfN
# x y z count.x count.y countdif
#1 3 8 13 10 0 -10
#2 5 5 15 20 0 -20
#3 2 7 12 4 0 -4
#4 4 6 10 12 4 -8
#5 3 9 13 0 7 7
#6 6 8 15 0 3 3
或者使用 data.table
中的 merge.data.table
的可能方法。我们将 'data.frame' 都转换为 'data.table'(setDT(df1)
、setDT(df2)
)。然后,使用 merge.data.table
执行 full-join
。我们在 for
循环中用 set
将 'count' 列中的 'NA' 值替换为 0(这里是第 4 和第 5 列)(set
非常高效,因为它没有 .[data.table
开销。我们分配 (:=
) 新列 'countdif` 作为 'count.y' 和 'count.x'
library(data.table)
setDT(df1)
setDT(df2)
DT <- merge(df1, df2, 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
# x y z count.x count.y countdif
#1: 2 7 12 4 0 -4
#2: 3 8 13 10 0 -10
#3: 3 9 13 0 7 7
#4: 4 6 10 12 4 -8
#5: 5 5 15 20 0 -20
#6: 6 8 15 0 3 3
你必须创建一个像这个例子那样减去的算法:
(如果他们有一个独立的 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 个 'cores'
希望对您有所帮助。