我正试图找到一种方法来在数据框中查找多个值并返回一个值。简化示例:
df1 <- read.table(text="chk1 chk2 chk3 value
xx aa;bb;cc jj 1
xx;yy dd;ee;ff kk 2
zz gg;hh;ii ll;nn 3", header=T)
df2 <- read.table(text="val1 val2 val3
xx bb jj
xx dd kk
yy ee kk
zz hh jj
", header=T)
在val1
的{{1}}中查找值val2
,val3
和df2
,并从df1
返回值。
所需结果:
df1
尝试df2 <- read.table(text="
val1 val2 val3 value
xx bb jj 1
xx dd kk 2
yy ee kk 2
zz hh jj NA
")
并在各行中循环,无法使其正常工作。
答案 0 :(得分:0)
这里是一种可能性:
library(tidyverse)
df3 <- df2 %>% rowwise %>%
mutate(rowmatch=which(grepl(val1, df1$chk1) &
grepl(val2, df1$chk2) &
grepl(val3, df1$chk3))[1],
value=df1$value[rowmatch])
结果:
# A tibble: 4 x 5
val1 val2 val3 rowmatch value
<chr> <chr> <chr> <int> <int>
1 xx bb jj 1 1
2 xx dd kk 2 2
3 yy ee kk 2 2
4 zz hh jj NA NA
注意:
[1]
是为了确保仅使用匹配的第一行。rowmatch
和value
是相同的,但这仅是因为df1$value
等于行号。tibble
的行为类似于data.frame,但是如果您真的更喜欢数据框,请添加%>% as.data.frame
对于基数R也可以这样做并应用:
df2$rowmatch <- with(df1, apply(df2, 1, function(x)
which(grepl(x["val1"], chk1) &
grepl(x["val2"], chk2) &
grepl(x["val3"], chk3))[1]))
df2$value <- df1$value[df2$rowmatch]
答案 1 :(得分:0)
另一个选择是先分割值:
df1 <- df1 %>%
splitstackshape::cSplit("chk1", ";", fixed = TRUE, direction = "long", drop = FALSE, type.convert = FALSE) %>%
splitstackshape::cSplit("chk2", ";", fixed = TRUE, direction = "long", drop = FALSE, type.convert = FALSE) %>%
splitstackshape::cSplit("chk3", ";", fixed = TRUE, direction = "long", drop = FALSE, type.convert = FALSE)
然后使用加入
答案 2 :(得分:0)
您还可以使用两个嵌套的for循环来完成此操作。逻辑是采用df2
的第一行,然后开始遍历df1
的行以查看df2$val1
是否匹配df1$chk
,df2$val2
是否匹配{{1} }和df1$chk2
匹配df2$val3
。如果每列至少有一个匹配项,那么我认为所有值都是匹配项。需要注意的是,如果df1$chk3
没有唯一的行,则df2
的最后一个匹配行将被写入df1
。但这可以通过找到匹配项后立即跳出循环来更改。
df2
输出:
for (i in 1:nrow(df2)) {
for (j in 1:nrow(df1)) {
# Take i-th row and split by ;. Result is a vector of strings against
# which we'll use match.
i.split <- strsplit(as.character(unlist(df1[j, , drop = TRUE][-4])), ";")
# Pairwise check columns from df1 and df2.
all.ok <- all(mapply(FUN = function(x, y) {
any(x %in% y)
}, x = i.split, y = as.list(df2[i, 1:3])
))
if (all.ok) {
# If a match is found, write the value to df2.
df2[i, "value"] <- df1[j, "value"]
}
}
}