我想基于多个条件合并2个数据帧。
DF1 <- data.frame("col1" = rep(c("A","B"), 18),
"col2" = rep(c("C","D","E"), 12),
"value"= (sample(1:100,36)),
"col4" = rep(NA,36))
DF2 <- data.frame("col1" = rep("A",6),
"col2" = rep(c("C","D"),3),
"data" = rep(c(1,3),3),
"min" = seq(0,59,by=10),
"max" = seq(10,69,by=10))
> DF1
col1 col2 value col4
1 A C 22 NA
2 B D 58 NA
3 A E 35 NA
4 B C 86 NA
5 A D 37 NA
6 B E 16 NA
7 A C 46 NA
8 B D 23 NA
9 A E 88 NA
10 B C 3 NA
11 A D 33 NA
12 B E 25 NA
13 A C 19 NA
14 B D 24 NA
15 A E 9 NA
16 B C 76 NA
17 A D 62 NA
18 B E 68 NA
19 A C 97 NA
20 B D 43 NA
21 A E 8 NA
22 B C 84 NA
23 A D 36 NA
24 B E 20 NA
25 A C 57 NA
26 B D 99 NA
27 A E 42 NA
28 B C 64 NA
29 A D 87 NA
30 B E 1 NA
31 A C 78 NA
32 B D 34 NA
33 A E 41 NA
34 B C 32 NA
35 A D 10 NA
36 B E 72 NA
> DF2
col1 col2 data min max
1 A C 1 0 10
2 A D 3 10 20
3 A C 1 20 30
4 A D 3 30 40
5 A C 1 40 50
6 A D 3 50 60
DF1是主表,DF2被视为查找表
如果DF1的col1和col2与DF2的col1和col2匹配,并且&#39;值&#39; DF1的最小值和最大值在DF2之间,然后是列数据&#39;从DF2将添加到DF1。如果不满足条件,数据&#39; DF1的值将为NA。
预期输出(前6行):
col1 col2 value col4 data
1 A C 22 NA 1
2 B D 58 NA NA
3 A E 35 NA NA
4 B C 86 NA NA
5 A D 37 NA 3
6 B E 16 NA NA
我尝试过使用merge(匹配col1 snd col2)然后使用子集(仅过滤min和max之间值的行),但我的目标是维护DF1的所有行。
有人对此有所了解吗?
答案 0 :(得分:3)
使用最新版本的data.table
,可以使用非等联接和更新加入:
library(data.table)
head(setDT(DF1)[setDT(DF2), on = c("col1", "col2", "value>=min", "value<=max"),
data := data])
rn col1 col2 value col4 data 1: 1 A C 22 NA 1 2: 2 B D 58 NA NA 3: 3 A E 35 NA NA 4: 4 B C 86 NA NA 5: 5 A D 37 NA 3 6: 6 B E 16 NA NA
DF1 <- structure(list(rn = 1:36, col1 = c("A", "B", "A", "B", "A", "B",
"A", "B", "A", "B", "A", "B", "A", "B", "A", "B", "A", "B", "A",
"B", "A", "B", "A", "B", "A", "B", "A", "B", "A", "B", "A", "B",
"A", "B", "A", "B"), col2 = c("C", "D", "E", "C", "D", "E", "C",
"D", "E", "C", "D", "E", "C", "D", "E", "C", "D", "E", "C", "D",
"E", "C", "D", "E", "C", "D", "E", "C", "D", "E", "C", "D", "E",
"C", "D", "E"), value = c(22L, 58L, 35L, 86L, 37L, 16L, 46L,
23L, 88L, 3L, 33L, 25L, 19L, 24L, 9L, 76L, 62L, 68L, 97L, 43L,
8L, 84L, 36L, 20L, 57L, 99L, 42L, 64L, 87L, 1L, 78L, 34L, 41L,
32L, 10L, 72L), col4 = c(NA, NA, NA, NA, NA, NA, NA, NA, NA,
NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,
NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA)), .Names = c("rn",
"col1", "col2", "value", "col4"), row.names = c(NA, -36L), class = "data.frame")
DF2 <- structure(list(rn = 1:6, col1 = c("A", "A", "A", "A", "A", "A"
), col2 = c("C", "D", "C", "D", "C", "D"), data = c(1L, 3L, 1L,
3L, 1L, 3L), min = c(0L, 10L, 20L, 30L, 40L, 50L), max = c(10L,
20L, 30L, 40L, 50L, 60L)), .Names = c("rn", "col1", "col2", "data",
"min", "max"), row.names = c(NA, -6L), class = "data.frame")
答案 1 :(得分:2)
您的数据,正在更改stringsAsFactors=F
DF1 <- data.frame("col1" = rep(c("A","B"), 18),
"col2" = rep(c("C","D","E"), 12),
"value"= (sample(1:100,36)),
"col4" = rep(NA,36),
stringsAsFactors=F)
DF2 <- data.frame("col1" = rep("A",6),
"col2" = rep(c("C","D"),3),
"data" = rep(c(1,3),3),
"min" = seq(0,59,by=10),
"max" = seq(10,69,by=10),
stringsAsFactors=F)
使用dplyr
, 1)使用left_join
合并这两个数据, 2)检查ifelse
value
是between
min
和max
rowwise
,然后 3)取消选择min
和max
列... < / p>
library(dplyr)
left_join(DF1, DF2, by=c("col1","col2")) %>%
rowwise() %>%
mutate(data = ifelse(between(value,min,max), data, NA)) %>%
select(-min, -max)
不确定您是否希望执行某种聚合,但这里是上述代码的输出
col1 col2 value col4 data
1 A C 23 NA NA
2 A C 23 NA 1
3 A C 23 NA NA
4 B D 59 NA NA
5 A E 57 NA NA
6 B C 8 NA NA
答案 2 :(得分:0)
您可以分两步完成:
final <- merge(DF1,DF2,by=c("col1","col2"),all.x = T)
final$data <- ifelse(final$data>=final$min & final$data<=final$max,final$data,"NULL")
答案 3 :(得分:0)
使用包装了 fuzzyjoin 函数的软件包safejoin,您可以执行以下操作:
# devtools::install_github("moodymudskipper/safejoin")
library(safejoin)
debugonce(safe_left_join)
safe_left_join(DF1, DF2, ~
X("col1") == Y("col1") &
X("col2") == Y("col2") &
X("value") >= Y("min") &
X("value") <= Y("max"),
conflict = ~.x) %>%
head(15)
# col1 col2 value col4 data min max
# 1 A C 90 NA NA NA NA
# 2 B D 20 NA NA NA NA
# 3 A E 8 NA NA NA NA
# 4 B C 99 NA NA NA NA
# 5 A D 42 NA NA NA NA
# 6 B E 37 NA NA NA NA
# 7 A C 47 NA 1 40 50
# 8 B D 61 NA NA NA NA
# 9 A E 55 NA NA NA NA
# 10 B C 11 NA NA NA NA
# 11 A D 81 NA NA NA NA
# 12 B E 48 NA NA NA NA
# 13 A C 77 NA NA NA NA
# 14 B D 58 NA NA NA NA
# 15 A E 3 NA NA NA NA
此处的conflict
参数告诉函数仅返回lhs中的冲突列(col1
和col2
)。
答案 4 :(得分:0)
通过使用all.x = TRUE保留DF1的所有行,然后按如下所示调整过滤器中的条件:
iMed=merge(DF1,DF2,by.x=c('col1','col2'),by.y=c('col1','col2'),all.x=TRUE)
Res=iMed[is.na(iMed[,'min'])|is.na(iMed[,'max'])|(iMed[,'value']<=iMed[,'max'] & iMed[,'value']>=iMed[,'min'] ),]