【问题标题】:Merging dataframes with NA's efficiently有效地将数据帧与 NA 合并
【发布时间】:2017-09-08 13:47:33
【问题描述】:

我该怎么做,来自以下两个数据框:

df1:

cat1        cat2
a           NA
b           NA
c           NA
d           NA
e           NA

df2:

cat1        cat2
c           1
d           2

尽可能尽可能高效产生以下结果?

cat1        cat2
a           NA
b           NA
c           1
d           2
e           NA

当我这样做时:

df3 <- rbind(df2,df1[!(df1$cat1 %in% df2$cat1),])
merge(df1,df3,all.y=TRUE)

我得到了所需的数据框。但是,难道没有一种更整洁、或许更有效的方法来做到这一点吗? (这只是虚拟数据 - 我实际上有 700k 行数据

【问题讨论】:

  • 您应该编写代码以生成足够大的示例,可能是行数或类似的函数,并注意cat1 值是否唯一。
  • Fwiw,这可能是最快的方法:stackoverflow.com/q/14720923 如果可行,我们可以关闭问题。

标签: r performance dataframe merge


【解决方案1】:

这个怎么样:

df1 <-read.table(text="cat1        cat2
a           NA
b           NA
c           NA
d           NA
e           NA",header=TRUE,stringsAsFactors=FALSE)

df2<-read.table(text="cat1        cat2
c           1
d           2",header=TRUE, stringsAsFactors=FALSE)

df1[df1$cat1%in%df2$cat1,] <-df2

  cat1 cat2
1    a   NA
2    b   NA
3    c    1
4    d    2
5    e   NA

编辑

我在您的解决方案、我的解决方案和另一个答案中的data.table 解决方案上运行了microbenchmark,而我的解决方案是迄今为止最快的。

df1[df1$cat1%in%df2$cat1,] &lt;-df2 进行 1000 次计算的平均时间是 80 微秒。相比之下,data.table 解决方案需要 690 微秒,而您的解决方案总共需要 1062 微秒。如此有效,我的解决方案快了一个数量级。

library(microbenchmark)
res <- microbenchmark(
rbind(df2,df1[!(df1$cat1 %in% df2$cat1),]),
merge(df1,df3,all.y=TRUE),
df1[df1$cat1%in%df2$cat1,] <-df2,
dat1[dat][,1:2,with=T],
times=1000L)

> print(res)
Unit: microseconds
                                         expr     min       lq    *mean*   median       uq      max neval
 rbind(df2, df1[!(df1$cat1 %in% df2$cat1), ]) 242.395 260.3555 279.3699 268.3550 277.5615 2817.263  1000
                merge(df1, df3, all.y = TRUE) 679.488 724.1640 783.2416 740.1625 761.5940 6756.541  1000
         df1[df1$cat1 %in% df2$cat1, ] <- df2  63.392  72.1450  80.0050  75.1640  80.5975 2017.334  1000
                   dat1[dat][, 1:2, with = T] 602.816 649.6040 690.9846 665.3010 691.2615 3264.319  1000

EDIT2

另一个microbenchmark 有100,000 个数据点,包括data.tablesetkeyv 步骤。基本索引(df[df$cat1 %in% df1$cat1, ] &lt;- df)比data.table 的总步数(7.4 毫秒)略快(平均 7 毫秒),但并不快。效率取决于OP的实际数据集。

library(data.table)
dat <- data.table(cat1=c(paste0("a",1:100000)),cat2=rep(NA,100000))
dat1 <- data.table(cat1=c(paste0("a",sample(1:100000,10001))),cat2=1:10001)
setkeyv(dat,"cat1")
setkeyv(dat1,"cat1")
df <- data.frame(dat)
df1 <- data.frame(dat1)

library(microbenchmark)
res <- microbenchmark(
   merge(df,df1,all.y=TRUE),
   df[df$cat1 %in% df1$cat1, ] <- df1,
   setkeyv(dat,"cat1"),
   setkeyv(dat1,"cat1"),
   dat1[dat][,1:2,with=T],
   times=100L)
print(res)
Unit: microseconds
                               expr       min        lq       mean    median         uq       max neval  cld
       merge(df, df1, all.y = TRUE) 96573.600 98317.435 115509.544 102872.81 130325.979 195910.42   100    d
 df[df$cat1 %in% df1$cat1, ] <- df1  4329.293  4785.601   7059.100   5054.74   5632.501  40521.16   100   c 
               setkeyv(dat, "cat1")  1166.073  1568.211   1928.071   1766.36   1913.329  14256.59   100 ab  
              setkeyv(dat1, "cat1")   215.253   296.935    434.589    443.05    506.629   1279.54   100 a   
         dat1[dat][, 1:2, with = T]  3531.004  4020.242   5024.882   4195.72   4587.026  34787.45   100  bc 

【讨论】:

  • 如果您在此处显示的微小数据集上进行了基准测试,则不一定有意义。
  • @Frank 你是对的。我添加了另一个编辑,在其中重新运行了包含 100,000 个数据点的微基准测试,并包含了 data.table 开销 setkeyv 步骤。在这种情况下,基本的df[df$cat1 %in% df1$cat1, ] &lt;- df1 索引仍然更快,但只是稍微快一点。这将取决于 OP 的实际数据集。
  • 好的,谢谢。我已经将我的基准与 data.table 更新加入聊天:chat.stackoverflow.com/transcript/message/36605566#36605566 它不需要排序/键入,并且将正确处理df1$cat1 中的查找不出现在df$cat1 中、出现多次等情况.
  • 谢谢!稍微快一点。标记答案
猜你喜欢
  • 1970-01-01
  • 2016-01-31
  • 2017-09-12
  • 1970-01-01
  • 2013-09-21
  • 2016-12-08
  • 1970-01-01
  • 2018-06-25
  • 2018-04-08
相关资源
最近更新 更多