【问题标题】:Matching multiple values for a variable to one value to from another dataframe将变量的多个值与另一个数据帧的一个值匹配
【发布时间】:2019-11-19 19:17:06
【问题描述】:

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

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 匹配,这当然没有任何值(Natalie,Nat 一起) .我希望 R 读取这两个名称并查看它是否都在 dt2 中,然后返回文本值“正确的名称”。

有什么想法吗?

【问题讨论】:

  • 通过使用模糊匹配,您有可能返回比任一框架拥有的更多的行,这是故意的吗?
  • 感谢 R2evans。不,这不是我的本意。我上面的代码是这样做的吗?对不起,我应该说我完全是一个新手(试图成为程序员的医生)。但是有没有办法做我上面问的?
  • 好吧,我想我看错了。您打算如何处理多名称行?这是allany 操作吗? (我这么说是因为Natalie, Nat 不在dt2 中,但您的输出表明它在。)
  • 这就是我遇到问题的地方...我不确定如何在一个单元格中处理多个名称。如何让 R 分别读取这两个名称并将其与 dt2 进行比较并确定它们是否在 dt2 中?当单元格中只有一个名称时,代码可以正常工作,但当单元格中有两个或更多名称时,代码会失败。
  • 错字...我已经编辑过了...

标签: r matching


【解决方案1】:

这是一个蛮力方法:

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,以便您没有逗号分隔的字段。


另类

从数据效率的角度来看,在一个单元格中使用逗号分隔的独立类别可能会很烦人。我建议我们扩展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$id重新聚合dt1

【讨论】:

  • 评论不用于扩展讨论;这个对话是moved to chat
  • 非常感谢!我会在明天之后试一试,然后回复你。最好的。
  • 不,其他用户没有 20 个代表。当帖子上有 25 个 cmets 时,Mod 会自动标记。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-05-12
  • 1970-01-01
  • 1970-01-01
  • 2022-11-02
  • 2021-08-02
  • 2022-10-23
  • 1970-01-01
相关资源
最近更新 更多