【问题标题】:r match data in two data frames then check text in another column for matched rowr 匹配两个数据框中的数据,然后检查另一列中的文本是否匹配行
【发布时间】:2017-07-18 13:23:31
【问题描述】:

我有两个数据框 stu1 和 stu2。两者都有匹配的 ID 列,但其他列中的变量不同。

例如stu1:

ID, Grade, Group, Age
ad1, A, Green, 14
bc1, B, Green, 13
cd1, B, Blue, 14
fs3, C, Red, 13

stu2:

ID, Prog, Loc, Year
bc1, LSC1, Ext, 2013
cd1, LSC1, Ext, 2013
cd1, BSC1, Int, 2013
ad1, BSC2, Int, 2012
rs2, KHL4, Ext, 2014

我要做的是检查stu1 中的学生ID 是否存在于stu2 中,然后检查对应行的另一列中的文本是否与我的字符串匹配,例如Prog =='BSC*' 然后在stu1 中创建一个新列,其中显示“是”或“否”。

所以,stu1 的结果应该是:

ID, Grade, Group, Age, BSCProg
ad1, A, Green, 14, Yes
bc1, B, Green, 13, No
cd1, B, Blue, 14, Yes
fs3, C, Red, 13, No

我尝试了很多不同的方法都没有成功,例如:

stu1$BSCProg <- ifelse(stu2[grepl("BSC", stu2$Prog) & match(paste0(stu1$ID), 
    paste0(stu1$ID)),], "Yes", "No")

stu1$BSCProg <- ifelse(is.na(match(paste0(stu1$ID),
    paste0(stu2$ID) & stu2[grepl("BSC", stu2$Prog),])),"No","Yes")

stu1$BSCProg <- ifelse(stu1$ID %in% stu2$ID & grepl('BSC', stu2$Prog), "Yes", "No")

【问题讨论】:

    标签: r if-statement match grepl


    【解决方案1】:

    我会通过合并两个表来做到这一点,这样您就可以进行列比较。使用data.table

    library(data.table)
    
    setDT(stu1)
    setDT(stu2)
    
    dat <- merge(stu1,
                 stu2[Prog %like% "BSC", .(ID, BSCProg = Prog)],
                 by = "ID",
                 all.x = TRUE)
    
    dat[, BSCProg := ifelse(is.na(BSCProg), "No", "Yes")]
    

    结果:

    #     ID Grade Group Age BSCProg
    # 1: ad1     A Green  14     Yes
    # 2: bc1     B Green  13      No
    # 3: cd1     B  Blue  14     Yes
    # 4: fs3     C   Red  13      No
    

    解压一下,第一步是将IDProg 列从stu2 合并到stu1Prog %like% "BSC" 部分将仅合并 Prog 列将“BSC”作为值的一部分的那些行。 BSCProg = Prog 是将列重命名为你想要的。

    完成此操作后,该列的值将是 NABSC1BSC2 等值。最后的声明 BSCProg := ifelse(is.na(BSCProg), "No", "Yes") 会将任何 NA 更改为“否”,并将其他任何内容更改为“是”。

    【讨论】:

    • 谢谢!那真是太快了,太有帮助了!你太棒了:-)
    • 非常感谢!我现在被要求为每个程序创建新列。只有 5 个程序,所以我每次都可以复制和粘贴代码来更改搜索和添加新列。除了提高我的 R 技能之外,是否有一种更简单、更简洁的方法来添加额外的列来搜索其他程序(LSC、BSC 1 和 2、KHL1:4)?我已经尝试过使用现有的建议,但它们也都失败了。
    • 尝试使用dcast,它位于data.table 包中。它会让您为 Prog 中的每个条目创建一个列。
    • 感谢您的提示!还没有机会尝试,但至少我知道从哪里开始。
    【解决方案2】:

    您可以先通过ID merge,然后创建新列。这是data.table 解决方案:

     library(data.table)
     setDT(stu1, key="ID")
     setDT(stu2, key="ID")
     stu1 = merge(stu1, stu2, all.x=TRUE)
     stu1[, BSCProg:=ifelse(grepl("^BSC", Prog), "Yes", "No")]
    

    【讨论】:

    • 与我的类似,我最初的做法也是如此。问题在于stu2的ID列有cd1的重复,所以合并后stu1得到一行,有两个BSCProg的值。
    • 好收获!我应该尝试使用示例数据!
    • 感谢您也尝试这个!如果我必须向原始数据添加额外的行,这可能会有所帮助(尚未被询问,但如果出现这种情况也不会感到惊讶!)。干杯!
    【解决方案3】:

    dplyrtidyr 解决方案。 stu3 是最终输出。

    library(dplyr)
    library(tidyr)
    
    stu1 <- data_frame(ID = c("ad1", "bc1", "cd1", "fs3"),
                       Grade = c("A", "B", "B", "C"),
                       Group = c("Green", "Green", "Blue", "Red"),
                       Age = c(14, 13, 14, 13))
    
    stu2 <- data_frame(ID = c("bc1", "cd1", "cd1", "ad1", "rs2"),
                       Prog = c("LSC1", "LSC1", "BSC1", "BSC2", "KHL4"),
                       Loc = c("Ext", "Ext", "Int", "Int", "Ext"),
                       Year = c(2013, 2013, 2013, 2012, 2014))
    
    
    stu3 <- stu1 %>%
      full_join(stu2 %>% select(ID, Prog), by = "ID") %>%
      mutate(BSCProg = ifelse(grepl("BSC", Prog), "Yes", "No")) %>%
      drop_na(Grade) %>%
      select(-Prog) %>%
      group_by(ID) %>%
      arrange(desc(BSCProg)) %>%
      slice(1)
    

    【讨论】:

    • left_join 会不会比 full_join 更好?
    • @ChiPak 因为stu2 重复了ID,比如cd1left_join 将丢失那些重复的行。
    • left_join(stu1, select(stu2,ID,Prog), by="ID") 保留cd1。无论如何,只是一个建议。
    • @ChiPak left_join 是我的第一个想法,但它不起作用。
    • 当我尝试full_join 时,它看起来很乱。我认为left_join 可能会稍微清理你的输出,但如果它最终没有保存代码,那么替换它就没有意义了。干杯
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-25
    • 1970-01-01
    • 2022-01-17
    • 1970-01-01
    • 2018-01-16
    相关资源
    最近更新 更多