将变量的多个值与另一个数据帧的一个值匹配

时间:2019-11-19 19:17:06

标签: r matching

我有两个要匹配的数据帧,然后让它根据此匹配返回一个值。

dt1
Name
Matt
John
Steven
Natalie, Nat
Unknown

 dt2
 Names           Grade

Matt              A
John              B
Steven            C
Natalie           D
 Nat              D
Unknown           NA

我想要R做的是将dt1匹配到dt2,然后再返回一个值。我使用了以下代码:

Merge_df$"Match_name" <- ifelse(df1$"Name" %in% df2$"Names","Right Name",ifelse(grepl    ("Unknown", dt1$"Name", ignore.case = FALSE), "Unknown", "NA"))

所需的输出

Merge_df
A
B
C
D
E
Unknown

但是我得到的不是这个。在其中有两个名称的单元格中,它返回NA,因为它不读取两个名称,它只是尝试将整个值与dt2匹配,而dt2当然没有任何值(Natalie和Nat都在一起) 。我希望R读取两个名称,然后查看是否都在dt2中,然后返回文本值“ Right name”。

有什么想法吗?

1 个答案:

答案 0 :(得分:0)

这是一种蛮力方法:

dt1 <- read.table(header=TRUE, stringsAsFactors=FALSE, sep="|", text="
Name
Matt
John
Steven
Natalie, Nat
Unknown")

dt2 <- read.table(header=TRUE, stringsAsFactors=FALSE, text="
Names
Matt
John
Steven
Natalie
Nat
Unknown")

(我应该注意,我使用sep="|"只是为了快速将数据输入到此示例中。sep=的某些替代方法是必需的,因为其中一个字段中有空格。也可以使用readLines。)

首先,您不确定如何使用逗号分隔的名称。 split可以在这里使用:

strsplit(dt1$Name, "[ ,]+")
# [[1]]
# [1] "Matt"
# [[2]]
# [1] "John"
# [[3]]
# [1] "Steven"
# [[4]]
# [1] "Natalie" "Nat"    
# [[5]]
# [1] "Unknown"

sapply(strsplit(dt1$Name, "[ ,]+"), function(s) any(s %in% dt2$Names))
# [1] TRUE TRUE TRUE TRUE TRUE

这意味着嵌套的ifelse看起来像这样:

ifelse(grepl("Unknown", dt1$Name, ignore.case = FALSE), "Unknown",
       ifelse(sapply(strsplit(dt1$Name, "[ ,]+"), function(s) any(s %in% dt2$Names)),
              "Right Name", "NA"))
# [1] "Right Name" "Right Name" "Right Name" "Right Name" "Unknown"   

(并将其分配给列)。

我希望您的问题不会再复杂了……一旦我开始嵌套ifelse,我真的在考虑可以用merge简化的数据结构。为此,您需要重塑{嵌入}到dt1,以便没有逗号分隔的字段。


替代

从数据效率的角度来看,

在一个单元格中具有逗号分隔的 independent 类别可能很烦人。我建议我们展开dt1,以便每行有一个Name。但是,为了“记住”每个分组的来源,我们将为其分配一个ID。

从那里开始,简单地将它们合并/合并即可。我将演示如何使用dplyr,尽管几乎可以直接在base或data.table中完成相同的步骤。

library(dplyr)
library(tidyr) # unnest


dt1 <- read.table(header=TRUE, stringsAsFactors=FALSE, sep="|", text="
Name
Matt
John
Steven
Natalie, Nat
Unknown")
dt2 <- read.table(header=TRUE, stringsAsFactors=FALSE, text="
Names Grade
Matt A
John B
Steven C
Natalie D
Nat D
Unknown NA 
")

dt1 %>%
  mutate(
    id = row_number(),
    Name = strsplit(Name, "[ ,;]+")
  ) %>%
  unnest(cols = Name) %>%
  left_join(dt2, by = c(Name = "Names"))
# # A tibble: 6 x 3
#   Name       id Grade
#   <chr>   <int> <chr>
# 1 Matt        1 A    
# 2 John        2 B    
# 3 Steven      3 C    
# 4 Natalie     4 D    
# 5 Nat         4 D    
# 6 Unknown     5 <NA> 

以此为依据,您可以选择以根据dt1重新汇总dt1$id