【问题标题】:R, find character string from vector, create new TRUE/FALSE columnsR,从向量中查找字符串,创建新的 TRUE/FALSE 列
【发布时间】:2021-08-04 09:58:39
【问题描述】:

我有一个这样的数据框:

df<-structure(list(MRN = c("53634", "65708", "72122", "40458", "03935", 
"67473", "20281", "52479", "10261", "40945", "40630", "92295", 
"43505", "80719", "39492", "44720", "70691", "21351", "03457", 
"02182"), Outcome_Diagnosis_1 = c(NA, NA, NA, "Seroma of breast [N64.89]", 
"Breast implant capsular contracture [T85.44XA]; Breast implant capsular contracture [T85.44XA]; Breast implant capsular contracture [T85.44XA]", 
NA, NA, NA, "Acquired breast deformity [N64.89]", NA, NA, NA, 
NA, "Acquired breast deformity [N64.89]", NA, NA, NA, NA, NA, 
NA), Outcome_Diagnosis_2 = c(NA, NA, NA, "Extrusion of breast implant, initial encounter [T85.49XA]; Extrusion of breast implant, initial encounter [T85.49XA]; Extrusion of breast implant, initial encounter [T85.49XA]", 
NA, NA, NA, NA, NA, NA, NA, NA, NA, "Capsular contracture of breast implant, subsequent encounter [T85.44XD]; Capsular contracture of breast implant, subsequent encounter [T85.44XD]; Capsular contracture of breast implant, subsequent encounter [T85.44XD]", 
NA, NA, NA, NA, NA, NA), Outcome_Diagnosis_3 = c(NA, NA, NA, 
NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, "Acquired breast deformity [N64.89]; Capsular contracture of breast implant, initial encounter [T85.44XA]; Capsular contracture of breast implant, initial encounter [T85.44XA]; Capsular contracture of breast implant, initial encounter [T85.44XA]", 
NA, NA, NA, NA, NA, NA)), row.names = c(NA, -20L), class = c("tbl_df", 
"tbl", "data.frame"))

我有几个这样的向量:

Infection<-c("L76","L00", "L01","L02","L03","L04", "L05","L08")
Hematoma<-c("N64.89","M79.81")
Seroma<- c("L76.34")
Necrosis<- c("N64.1","T86.821")
CapsularContracture<- c("T85.44")
MechanicalComplications<- c("T85", "T85.4", "T85.41", "T85.42", "T85.43", "T85.49")

我想做的是在数据框中创建新列 TRUE/FALSE 如果在每一行中都找到了该向量。 (即使它在该行中多次出现,它也只是 TRUE,即它不需要“计算”它们)。

所以我想要的输出是这样的:

我苦苦挣扎并寻求帮助的原因是我真的不知道如何结合搜索特定字符串(可能在该列中较长的句子中)和查看多个列。

可能很重要的其他信息:

  • 除了这 3 个结果诊断之外,还有更多列,如果答案查看整行而不考虑有多少列,这将很有用
  • 有时这些代码不够具体,查找“Seroma”等实际单词可能会很有用。我想这只是换掉引号内的字符的情况吧?

【问题讨论】:

    标签: r tidyverse


    【解决方案1】:

    您可以将向量存储在列表中:

    lst <- list(Infection = c("L76","L00", "L01","L02","L03","L04", "L05","L08"),
                Hematoma = c("N64.89","M79.81"),
                Seroma = c("L76.34"),
                Necrosis = c("N64.1","T86.821"),
                CapsularContracture = c("T85.44"),
                MechanicalComplications = c("T85", "T85.4", "T85.41", "T85.42", "T85.43", "T85.49"))
    

    然后,使用 dplyrpurrr 你可以这样做:

    imap(lst,
         ~ df %>%
          mutate(!!.y := reduce(across(Outcome_Diagnosis_1:Outcome_Diagnosis_3, function(y) grepl(paste(sub("\\.", "", .x), collapse = "|"), sub("\\.", "", y))), `|`))) %>%
     reduce(full_join)
    
       MRN   Outcome_Diagnos… Outcome_Diagnos… Outcome_Diagnos… Infection Hematoma Seroma Necrosis CapsularContrac…
       <chr> <chr>            <chr>            <chr>            <lgl>     <lgl>    <lgl>  <lgl>    <lgl>           
     1 53634 <NA>             <NA>             <NA>             FALSE     FALSE    FALSE  FALSE    FALSE           
     2 65708 <NA>             <NA>             <NA>             FALSE     FALSE    FALSE  FALSE    FALSE           
     3 72122 <NA>             <NA>             <NA>             FALSE     FALSE    FALSE  FALSE    FALSE           
     4 40458 Seroma of breas… Extrusion of br… <NA>             FALSE     TRUE     FALSE  FALSE    FALSE           
     5 03935 Breast implant … <NA>             <NA>             FALSE     FALSE    FALSE  FALSE    TRUE            
     6 67473 <NA>             <NA>             <NA>             FALSE     FALSE    FALSE  FALSE    FALSE           
     7 20281 <NA>             <NA>             <NA>             FALSE     FALSE    FALSE  FALSE    FALSE           
     8 52479 <NA>             <NA>             <NA>             FALSE     FALSE    FALSE  FALSE    FALSE           
     9 10261 Acquired breast… <NA>             <NA>             FALSE     TRUE     FALSE  FALSE    FALSE           
    10 40945 <NA>             <NA>             <NA>             FALSE     FALSE    FALSE  FALSE    FALSE
    

    【讨论】:

    • 小心grepl,字符串中有. 点,可能会产生误报。
    • @r2evans 我明白了,我最初认为这是一个棘手的问题 :)
    • 显然 OP 不在乎(不太可能)?
    • @r2evans 我认为他们有,只是他们还没有遇到问题。
    • (在出现问题之前都不是问题。如果他们不认真研究正则表达式的含义,那将很难找到。)
    【解决方案2】:

    前面

    out <- lapply(manythings, function(thing) {
      rowSums(
        do.call(cbind, lapply(df[,2:4], function(col) Vectorize(grepl, vectorize.args = "pattern")(thing, col, fixed = TRUE)))
      ) > 0
    })
    tibble(cbind(df, out))
    # # A tibble: 20 x 10
    #    MRN   Outcome_Diagnosis_1   Outcome_Diagnosis_2   Outcome_Diagnosis_3   Infection Hematoma Seroma Necrosis CapsularContrac~ MechanicalCompl~
    #    <chr> <chr>                 <chr>                 <chr>                 <lgl>     <lgl>    <lgl>  <lgl>    <lgl>            <lgl>           
    #  1 53634 <NA>                  <NA>                  <NA>                  FALSE     FALSE    FALSE  FALSE    FALSE            FALSE           
    #  2 65708 <NA>                  <NA>                  <NA>                  FALSE     FALSE    FALSE  FALSE    FALSE            FALSE           
    #  3 72122 <NA>                  <NA>                  <NA>                  FALSE     FALSE    FALSE  FALSE    FALSE            FALSE           
    #  4 40458 Seroma of breast [N6~ Extrusion of breast ~ <NA>                  FALSE     TRUE     FALSE  FALSE    FALSE            TRUE            
    #  5 03935 Breast implant capsu~ <NA>                  <NA>                  FALSE     FALSE    FALSE  FALSE    TRUE             TRUE            
    #  6 67473 <NA>                  <NA>                  <NA>                  FALSE     FALSE    FALSE  FALSE    FALSE            FALSE           
    #  7 20281 <NA>                  <NA>                  <NA>                  FALSE     FALSE    FALSE  FALSE    FALSE            FALSE           
    #  8 52479 <NA>                  <NA>                  <NA>                  FALSE     FALSE    FALSE  FALSE    FALSE            FALSE           
    #  9 10261 Acquired breast defo~ <NA>                  <NA>                  FALSE     TRUE     FALSE  FALSE    FALSE            FALSE           
    # 10 40945 <NA>                  <NA>                  <NA>                  FALSE     FALSE    FALSE  FALSE    FALSE            FALSE           
    # 11 40630 <NA>                  <NA>                  <NA>                  FALSE     FALSE    FALSE  FALSE    FALSE            FALSE           
    # 12 92295 <NA>                  <NA>                  <NA>                  FALSE     FALSE    FALSE  FALSE    FALSE            FALSE           
    # 13 43505 <NA>                  <NA>                  <NA>                  FALSE     FALSE    FALSE  FALSE    FALSE            FALSE           
    # 14 80719 Acquired breast defo~ Capsular contracture~ Acquired breast defo~ FALSE     TRUE     FALSE  FALSE    TRUE             TRUE            
    # 15 39492 <NA>                  <NA>                  <NA>                  FALSE     FALSE    FALSE  FALSE    FALSE            FALSE           
    # 16 44720 <NA>                  <NA>                  <NA>                  FALSE     FALSE    FALSE  FALSE    FALSE            FALSE           
    # 17 70691 <NA>                  <NA>                  <NA>                  FALSE     FALSE    FALSE  FALSE    FALSE            FALSE           
    # 18 21351 <NA>                  <NA>                  <NA>                  FALSE     FALSE    FALSE  FALSE    FALSE            FALSE           
    # 19 03457 <NA>                  <NA>                  <NA>                  FALSE     FALSE    FALSE  FALSE    FALSE            FALSE           
    # 20 02182 <NA>                  <NA>                  <NA>                  FALSE     FALSE    FALSE  FALSE    FALSE            FALSE           
    

    演练

    与@tmfmnk 相同,我建议将所有模式放入一个命名列表中:

    manythings <- list(
      Infection = c("L76","L00", "L01","L02","L03","L04", "L05","L08"),
      Hematoma = c("N64.89","M79.81"),
      Seroma =  c("L76.34"),
      Necrosis =  c("N64.1","T86.821"),
      CapsularContracture =  c("T85.44"),
      MechanicalComplications =  c("T85", "T85.4", "T85.41", "T85.42", "T85.43", "T85.49"))
    

    另外,我们应该注意,虽然 grepl 对此有好处,但它不会向量化 pattern= 参数,因此我们需要在外部执行此操作。此外,由于您的某些模式具有正则表达式敏感字符(即匹配任何内容的.),我们需要防止正则表达式注入。例如,如果我们不小心,"N64.89" 作为模式将错误地匹配"N64989"。为此,我使用fixed=TRUE 作为保障。不幸的是,这也妨碍了我们塑造模式的能力,以便我们可以一步检查所有模式。相反,我们会将其向量化,搜索一个固定的正则表达式(您的模式向量之一的单个元素)并聚合结果。

    所以让我们对框架的一列做一个模式向量:

    Vectorize(grepl, vectorize.args = "pattern")(manythings[[2]], df[[2]], fixed = TRUE)
    #       N64.89 M79.81
    #  [1,]  FALSE  FALSE
    #  [2,]  FALSE  FALSE
    #  [3,]  FALSE  FALSE
    #  [4,]   TRUE  FALSE
    #  [5,]  FALSE  FALSE
    #  [6,]  FALSE  FALSE
    #  [7,]  FALSE  FALSE
    #  [8,]  FALSE  FALSE
    #  [9,]   TRUE  FALSE
    # [10,]  FALSE  FALSE
    # [11,]  FALSE  FALSE
    # [12,]  FALSE  FALSE
    # [13,]  FALSE  FALSE
    # [14,]   TRUE  FALSE
    # [15,]  FALSE  FALSE
    # [16,]  FALSE  FALSE
    # [17,]  FALSE  FALSE
    # [18,]  FALSE  FALSE
    # [19,]  FALSE  FALSE
    # [20,]  FALSE  FALSE
    

    现在我们可以减少它,以便我们知道在这一列的每个单元格中找到一个模式:

    rowSums(
      Vectorize(grepl, vectorize.args = "pattern")(manythings[[2]], df[[2]], fixed = TRUE)
    ) > 0
    #  [1] FALSE FALSE FALSE  TRUE FALSE FALSE FALSE FALSE  TRUE FALSE FALSE FALSE FALSE  TRUE FALSE FALSE FALSE FALSE FALSE FALSE
    

    现在我们可以在manythings 中的每个模式向量上迭代该过程:

    lapply(manythings, function(thing) {
      rowSums(
        Vectorize(grepl, vectorize.args = "pattern")(thing, df[[2]], fixed = TRUE)
      ) > 0
    })
    # $Infection
    #  [1] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
    # $Hematoma
    #  [1] FALSE FALSE FALSE  TRUE FALSE FALSE FALSE FALSE  TRUE FALSE FALSE FALSE FALSE  TRUE FALSE FALSE FALSE FALSE FALSE FALSE
    # $Seroma
    #  [1] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
    # $Necrosis
    #  [1] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
    # $CapsularContracture
    #  [1] FALSE FALSE FALSE FALSE  TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
    # $MechanicalComplications
    #  [1] FALSE FALSE FALSE FALSE  TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
    

    所有这些都集中在一个列中,df[[2]]。为了在多个(可选)列中应用它,我将使用一些列绑定技巧(在顶部的代码中)。为了打破这一点,

    • lapply(df[,2:4], ...) 子集我们要搜索的数据,所以只有几列。您想要选择列的任何方式都适合这里。这将返回矩阵的list,类似于:

      lapply(df[,2:4], function(col) Vectorize(grepl, vectorize.args = "pattern")(thing, col, fixed = TRUE))
      # $Outcome_Diagnosis_1
      #       N64.89 M79.81
      #  [1,]  FALSE  FALSE
      #  [2,]  FALSE  FALSE
      #  [3,]  FALSE  FALSE
      # ...
      # $Outcome_Diagnosis_2
      #       N64.89 M79.81
      #  [1,]  FALSE  FALSE
      #  [2,]  FALSE  FALSE
      #  [3,]  FALSE  FALSE
      # ...
      # $Outcome_Diagnosis_3
      #       N64.89 M79.81
      #  [1,]  FALSE  FALSE
      #  [2,]  FALSE  FALSE
      #  [3,]  FALSE  FALSE
      # ...
      
    • do.call(cbind, ...) 将采用每个嵌入矩阵并将它们组合成一个矩阵:

      do.call(cbind, lapply(df[,2:4], function(col) Vectorize(grepl, vectorize.args = "pattern")(thing, col, fixed = TRUE)))
      #       N64.89 M79.81 N64.89 M79.81 N64.89 M79.81
      #  [1,]  FALSE  FALSE  FALSE  FALSE  FALSE  FALSE
      #  [2,]  FALSE  FALSE  FALSE  FALSE  FALSE  FALSE
      #  [3,]  FALSE  FALSE  FALSE  FALSE  FALSE  FALSE
      #  [4,]   TRUE  FALSE  FALSE  FALSE  FALSE  FALSE
      # ...
      

      这允许我们使用rowSums(.) &gt; 0 来确定每一行是否满足任何模式(在每一列中)。

    【讨论】:

    • 以前从未使用过函数Vectorize,我看到在这个设置中它可以节省一些代码行:)
    【解决方案3】:

    这是另一个您可以使用的 base R 解决方案,尽管在某种程度上类似。正如亲爱的@r2evans 巧妙地指出的那样,我还将我的模式匹配更改为fixed = TRUE,这是我一开始不知道的:

    cbind(df, as.data.frame(do.call(cbind, lst |>
                                      lapply(function(a) {
                                        sapply(a, function(b) {
                                          apply(df[-1], 1, function(c) as.logical(Reduce(`+`, grepl(b, c, fixed = TRUE))))
                                        }) |>  rowSums() |> as.logical()
                                      }))))
    
       Infection Hematoma Seroma Necrosis CapsularContracture MechanicalComplications
    1      FALSE    FALSE  FALSE    FALSE               FALSE                   FALSE
    2      FALSE    FALSE  FALSE    FALSE               FALSE                   FALSE
    3      FALSE    FALSE  FALSE    FALSE               FALSE                   FALSE
    4      FALSE     TRUE  FALSE    FALSE               FALSE                    TRUE
    5      FALSE    FALSE  FALSE    FALSE                TRUE                    TRUE
    6      FALSE    FALSE  FALSE    FALSE               FALSE                   FALSE
    7      FALSE    FALSE  FALSE    FALSE               FALSE                   FALSE
    8      FALSE    FALSE  FALSE    FALSE               FALSE                   FALSE
    9      FALSE     TRUE  FALSE    FALSE               FALSE                   FALSE
    10     FALSE    FALSE  FALSE    FALSE               FALSE                   FALSE
    11     FALSE    FALSE  FALSE    FALSE               FALSE                   FALSE
    12     FALSE    FALSE  FALSE    FALSE               FALSE                   FALSE
    13     FALSE    FALSE  FALSE    FALSE               FALSE                   FALSE
    14     FALSE     TRUE  FALSE    FALSE                TRUE                    TRUE
    15     FALSE    FALSE  FALSE    FALSE               FALSE                   FALSE
    16     FALSE    FALSE  FALSE    FALSE               FALSE                   FALSE
    17     FALSE    FALSE  FALSE    FALSE               FALSE                   FALSE
    18     FALSE    FALSE  FALSE    FALSE               FALSE                   FALSE
    19     FALSE    FALSE  FALSE    FALSE               FALSE                   FALSE
    20     FALSE    FALSE  FALSE    FALSE               FALSE                   FALSE
    

    为了适应结果,我只把新创建的列的输出放在这里,但是代码将它们绑定到原始数​​据集。

    lst <- list(Infection = c("L76", "L00", "L01", "L02", "L03", "L04", 
    "L05", "L08"), Hematoma = c("N64.89", "M79.81"), Seroma = "L76.34", 
        Necrosis = c("N64.1", "T86.821"), CapsularContracture = "T85.44", 
        MechanicalComplications = c("T85", "T85.4", "T85.41", "T85.42", 
        "T85.43", "T85.49"))
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-09-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-05-08
      相关资源
      最近更新 更多