有没有办法通过多列合并(左外连接)数据帧,但是有OR条件?
示例:列df1
有两个数据框df2
和x, y, num
。我希望有一个包含df1
所有行的数据框,但只有df2
中符合条件的行df1$x == df2$x
或df2$y == df2y
。
以下是示例数据:
df1 <- data.frame(x = LETTERS[1:5],
y = 1:5,
num = rnorm(5), stringsAsFactors = F)
df1
x y num
1 A 1 0.4209480
2 B 2 0.4687401
3 C 3 0.3018787
4 D 4 0.0669793
5 E 5 0.9231559
df2 <- data.frame(x = LETTERS[3:7],
y = 3:7,
num = rnorm(5), stringsAsFactors = F)
df2$x[4] <- NA
df2$y[3] <- NA
df2
x y num
1 C NA -0.7160824
2 <NA> 4 -0.3283618
3 E 5 -1.8775298
4 F 6 -0.9821082
5 G 7 1.8726288
然后,结果预计是:
x y num x y num
1 A 1 0.4209480 <NA> NA NA
2 B 2 0.4687401 <NA> NA NA
3 C 3 0.3018787 C NA -0.7160824
4 D 4 0.0669793 <NA> 4 -0.3283618
5 E 5 0.9231559 E 5 -1.8775298
最明显的解决方案是使用sqldf
包:
mergedData <- sqldf::sqldf("SELECT * FROM df1
LEFT OUTER JOIN df2
ON df1.x = df2.x
OR df1.y = df2.y")
不幸的是,这个简单的解决方案非常慢,并且合并每个行数超过100k的数据帧需要很长时间。
另一个选择是分割正确的数据框并按部分合并,但它更优雅甚至是开箱即用的#34;溶液
答案 0 :(得分:1)
以下是使用data.table
的一种方法。对于每一列,我们执行连接,但只提取索引(而不是实现整个连接)。然后,我们可以组合所有列中的这些索引(如果可以有多个匹配,这部分需要进行一些更改)
require(data.table)
setDT(df1)
setDT(df2)
foo <- function(dx, dy, cols) {
ix = lapply(cols, function(col) {
dy[dx, on=col, which=TRUE] # for each row in dx, get matching indices of dy
# by matching on column specified in "col"
})
ix = do.call(function(...) pmax(..., na.rm=TRUE), ix)
}
ix = foo(df1, df2, c("x", "y")) # obtain matching indices of df2 for each row in df1
df1[, paste0("col", 1:3) := df2[ix]] # update df1 by reference
df1
# x y num col1 col2 col3
# 1: A 1 2.09611034 NA NA NA
# 2: B 2 -1.06795571 NA NA NA
# 3: C 3 1.38254433 C 3 1.0173476
# 4: D 4 -0.09367922 D 4 -0.6379496
# 5: E 5 0.47552072 E NA -0.1962038
如果需要,您可以使用setDF(df1)
将其转换回data.frame。