7

我有两个数据框。第一个看起来像这样:

value <- seq(1, 100, length.out=20)
df1 <- data.frame(id=as.character(1:20), 
                  value=value, 
                  stringsAsFactors=F)

我有第二个看起来像这样的数据框

df2 <- data.frame(id=as.character(c(1:5, 21:23)),
                  v2=NA, 
                  stringsAsFactors=F)

我需要将值从 转移df1df2,但仅限于 where df1$id == df2$id。所以我需要的数据框是:

df2Needed <- data.frame(id=as.character(c(1:5, 21:23)),
                      v2=c(value[1:5], NA, NA, NA),
                      stringsAsFactors=F)

有没有办法做到这一点?

4

4 回答 4

5

使用data.table

require(data.table)
dt1 <- data.table(df1, key="id")
dt2 <- data.table(df2)

dt1[dt2$id, value]

#    id     value
# 1:  1  1.000000
# 2:  2  6.210526
# 3:  3 11.421053
# 4:  4 16.631579
# 5:  5 21.842105
# 6: 21        NA
# 7: 22        NA
# 8: 23        NA

或使用 basemerge作为评论下提到的@TheodoreLytras:

# you don't need to have `v2` column in df2
merge(df2, df1, by="id", all.x=T, sort=F)

#   id v2     value
# 1  1 NA  1.000000
# 2  2 NA  6.210526
# 3  3 NA 11.421053
# 4  4 NA 16.631579
# 5  5 NA 21.842105
# 6 21 NA        NA
# 7 22 NA        NA
# 8 23 NA        NA
于 2013-03-09T11:31:57.577 回答
5

一种方法是使用merge()

df2Needed <- merge(df2,df1,by="id",all.x=TRUE, sort=FALSE)
df2Needed <- df2Needed[,c("id","value")]
colNames(df2Needed) <- c("id","v2")

另一个(我认为更优雅)使用match()

df2Needed <- df2
df2Needed$v2 <- df1$value[match(df2$id, df1$id)]
于 2013-03-09T11:46:44.027 回答
4

LEFT join sql_sqldf

library(sqldf)
sqldf('SELECT df2.id , df1.value
      FROM df2
      LEFT JOIN df1
      ON df2.id = df1.id')

 id     value
1  1  1.000000
2  2  6.210526
3  3 11.421053
4  4 16.631579
5  5 21.842105
6 21        NA
7 22        NA
8 23        NA

编辑添加一些基准测试:

正如预期的那样,比赛在这里非常快。sqldf真的很慢!

对 OP 数据进行测试

library(microbenchmark)
microbenchmark(ag(),ar.dt(),ar.me(),tl())

Unit: microseconds
     expr       min         lq     median        uq       max
1    ag() 23071.953 23536.1680 24053.8590 26889.023 34256.354
2 ar.dt()  3123.972  3284.5890  3348.1155  3523.333  7740.335
3 ar.me()   950.807  1015.2815  1095.1160  1128.112  6330.243
4    tl()    41.340    45.8915    68.0785    71.112   187.735

用大数据测试1E6 行数据。

这里我如何生成我的数据:

N <- 1e6
df1 <- data.frame(id=as.character(1:N), 
                  value=seq(1, 100), 
                  stringsAsFactors=F)
n2 <- 1000
df2 <- data.frame(id=sample(df1$id,n2),
                  v2=NA, 
                  stringsAsFactors=F)

惊喜 !!合并比 sqldf 快 16 倍,而data.table 解决方案是最慢的!

Unit: milliseconds
     expr       min        lq    median        uq        max
1    ag() 5678.0580 5865.3063 6034.9151 6214.3664  8084.6294
2 ar.dt() 8373.6083 8612.9496 8867.6164 9104.7913 10423.5247
3 ar.me()  387.4665  451.0071  506.8269  648.3958  1014.3099
4    tl()  174.0375  186.8335  214.0468  252.9383   667.6246

其中函数 ag, ar.dt,ar.me, tl 定义为:

ag <- function(){
require(sqldf)
sqldf('SELECT df2.id , df1.value
      FROM df2
      LEFT JOIN df1
      ON df2.id = df1.id')
}


ar.dt <- function(){
  require(data.table)
  dt1 <- data.table(df1, key="id")
  dt2 <- data.table(df2)
  dt1[dt2$id, value]
}

ar.me  <- function(){
 merge(df2, df1, by="id", all.x=T, sort=F)
}

tl <- function(){
  df2Needed <- df2
 df2Needed$v2 <- df1$value[match(df2$id, df1$id)]
}

编辑 2

似乎在基准测试中包括了 data.table 创建一点点unfair。为了避免任何混淆,我添加了一个新函数,我认为我已经有了 data.table 结构。

ar.dtLight <- function(){
  dt1[dt2$id, value]
}

library(microbenchmark)
microbenchmark(ag(),ar.dt(),ar.me(),tl(),ar.dtLight,times=1)

Unit: microseconds
        expr         min          lq      median          uq         max
1       ag() 7247593.591 7247593.591 7247593.591 7247593.591 7247593.591
2    ar.dt() 8543556.967 8543556.967 8543556.967 8543556.967 8543556.967
3 ar.dtLight       1.139       1.139       1.139       1.139       1.139
4    ar.me()  462235.106  462235.106  462235.106  462235.106  462235.106
5       tl()  201988.996  201988.996  201988.996  201988.996  201988.996

似乎创建键(索引)很耗时。但是一旦创建索引,data.table方法是无与伦比的。

于 2013-03-09T11:44:51.583 回答
0

只需在现有的优秀答案列表中添加另一种方法:

> library(dplyr)
> library(qdapTools)
> mutate(df2, v2 = id %l% df1)
#  id        v2
#1  1  1.000000
#2  2  6.210526
#3  3 11.421053
#4  4 16.631579
#5  5 21.842105
#6 21        NA
#7 22        NA
#8 23        NA
于 2019-05-25T00:43:25.007 回答