【问题标题】:Matching strings in a column of a data frame with the strings in a column of another data frame using R or Python使用 R 或 Python 将数据框列中的字符串与另一个数据框列中的字符串匹配
【发布时间】:2018-07-10 04:51:44
【问题描述】:

我正在尝试将数据框列中的字符串与另一个数据框列中的字符串进行匹配,并映射相应的值。两个数据框的行数不同

df1 = data.frame(name = c("(CKMB)Creatinine Kinase Muscle & Brain", "24 Hours Urine for Sodium", "Antistreptolysin O Titer", "Blood group O", lonic_code = c("27816-8-O", "27816-8-B", "1869-7", "33914-3")
df2 = data.frame(Testcomponents = c("creatinine", "blood", "potassium"))

预期输出

Test Components          lonic_code
creatinine                27816-8-O
 blood                      1869-7
potassium                    NA

【问题讨论】:

  • 可以查看?grep
  • 如果您能帮助我编写代码,我将不胜感激?我在一个数据框中有一个包含 342 个名称的列表,我需要从另一个具有大约 1000 个名称的数据框中映射 lonic_code 值。
  • 你能给出你给出的例子的预期结果吗?
  • 正如@Onyambu 所说,最好也为其他人显示预期输出以更好地帮助您
  • @Onyambu 我已经用预期结果更新了我的问题。

标签: python r string string-matching


【解决方案1】:

这是一个可能的解决方案。可能不是最漂亮的,所以很想看看其他解决方案。

df1 = data.frame(name = c("(CKMB)Creatinine Kinase Muscle & Brain", "24 Hours Urine for Sodium", "Antistreptolysin O Titer", "Blood group O"), lonic_code = c("27816-8-O", "27816-8-B", "1869-7", "33914-3"))
df2 = data.frame(Testcomponents = c("creatinine", "blood", "potassium"))

result = lapply(sapply(df2$Testcomponents,function(x) {
  which(sapply(df1$name,function(y) {grepl(x,y,ignore.case = T)}))}),function(z) {df1$lonic_code[z]})

df2$Ionic_code= result

输出:

  Testcomponents Ionic_code
1     creatinine          3
2          blood          4
3      potassium           

【讨论】:

  • 谢谢弗洛里安。我将运行代码并通知您。感谢您的宝贵时间。
  • 我将它应用于我拥有的数据集,但 lonic_code 列显示所有 NULL 值。
  • 这很奇怪,因为它确实重现了您的预期输出?您在此处给出的样本数据是否与您的真实数据相同?是否存在大小写不匹配?在这种情况下,您可以使用grepl(x,y,ignore.case = T。否则,请添加更好的reproducible example
  • 我已经编辑了添加预期输出的问题。
  • 更新了答案,根据您之前的示例切换了 df1 和 df2 ,并添加了 ignore.case 参数。希望这会有所帮助!
【解决方案2】:

这比弗洛里安的答案多一点代码,但是,我认为它通过更易于阅读来弥补:

df1 = data.frame(Testcomponent = c("Albumin", "HDL Cholesterol",
                                   "Erythrocyte Sedimentation Rate (ESR)", "Thyroid-stimulating Hormone (TSH)"))

df2 = data.frame(Names = c("Micro Albumin", "Serum Globulin", "CMV Antibody (IgG)"), lonic_code = c("10501-5", "5196", "EKC 1"))

get.test.component <- function(component.name) {
  component <- grep(component.name, df2$Names)
  if (length(component) == 0) {
    return (NA)
  } else {
    return (as.character(df2$lonic_code[component]))
  }
}

new.ionic.codes <- Reduce(c, lapply(df1$Testcomponent, function(x) get.test.component(x)))
df1.new <- cbind(df1, new.ionic.codes)

【讨论】:

    【解决方案3】:

    regex_right_join 在这种情况下可能会很方便。

    library(fuzzyjoin)
    library(dplyr)
    
    df1 %>%
      mutate(name = as.character(name)) %>%
      regex_right_join(df2 %>%
                         mutate(Testcomponents = as.character(Testcomponents)), 
                       by = c(name = "Testcomponents"), ignore_case = T) %>%
      select(Testcomponents, lonic_code)
    

    输出是:

      Testcomponents lonic_code
    1     creatinine  27816-8-O
    2          blood    33914-3
    3      potassium       <NA>
    

    样本数据:

    df1 <- structure(list(name = structure(1:4, .Label = c("(CKMB)Creatinine Kinase Muscle & Brain", 
    "24 Hours Urine for Sodium", "Antistreptolysin O Titer", "Blood group O"
    ), class = "factor"), lonic_code = structure(c(3L, 2L, 1L, 4L
    ), .Label = c("1869-7", "27816-8-B", "27816-8-O", "33914-3"), class = "factor")), .Names = c("name", 
    "lonic_code"), row.names = c(NA, -4L), class = "data.frame")
    
    df2 <- structure(list(Testcomponents = structure(c(2L, 1L, 3L), .Label = c("blood", 
    "creatinine", "potassium"), class = "factor")), .Names = "Testcomponents", row.names = c(NA, 
    -3L), class = "data.frame")
    

    【讨论】:

    • 但是,使用上面的代码我无法映射一些 lonic_code 值。
    • 如果您可以将麻烦的(示例)“lonic_code”更新为dput(df1)dput(df2),那么我们可以调查一下。
    • 感谢您的宝贵时间!真的很感激!剩下的我都知道了!!
    • 太棒了!很高兴它有帮助!
    【解决方案4】:

    您可以使用sapply 循环测试组件:

    df2$lonic_code <- sapply(tolower(df2$Testcomponents), function(x) 
                         df1$lonic_code[grep(x, tolower(df1$name), fixed = TRUE)[1L]])
    
    df2
    #  Testcomponents lonic_code
    #1     creatinine  27816-8-O
    #2          blood    33914-3
    #3      potassium       <NA>
    

    如果有多个匹配项,这将始终只返回第一个匹配项。

    这应该相当快,因为​​它只使用一个循环并且因为我们在grep 中指定了fixed = TRUE。为了进一步提高速度,您可以使用 stringi 包的正则表达式函数。

    【讨论】:

      猜你喜欢
      • 2021-11-15
      • 1970-01-01
      • 2022-01-17
      • 1970-01-01
      • 1970-01-01
      • 2020-11-25
      • 2021-05-30
      • 2022-01-07
      • 2018-09-13
      相关资源
      最近更新 更多