【问题标题】:Subsetting character string and returning string子集字符串和返回字符串
【发布时间】:2019-06-20 00:33:03
【问题描述】:

我想知道是否有使用 data.table 解决以下问题的干净解决方案,可能使用其他包,例如 stringr。

假设我有如下数据表

DT <- data.table(name = c("Carlos", "Henry", "John"), 
    ID = c("US115115, CH123232, AB155, US4445", "CH112, BB53", "US57677777"))

这看起来像:

     name                                ID
1: Carlos US115115, CH123232, AB155, US4445
2:  Henry                       CH112, BB53
3:   John                        US57677777

我想做的是创建另一列 ID2,例如,它采用列 ID 并仅提取“美国身份”并创建一个新列,以便最终数据表应如下所示:

     name                                ID              ID2
1: Carlos US115115, CH123232, AB155, US4445 US115115, US4445
2:  Henry                       CH112, BB53               NA
3:   John                        US57677777       US57677777                     

其中每个元素都是一个字符串。我已经能够编写一个版本,它采用第一个“美国身份”并丢弃其余部分,但我无法找到处理多重性的解决方案。

任何帮助将不胜感激!

【问题讨论】:

    标签: r dplyr data.table


    【解决方案1】:

    一种可能的方法:

    DT[, ID2 := sapply(strsplit(ID, ","), 
        function(s) paste(s[grepl("\\s*US", s)], collapse=","))]
    

    输出:

         name                                ID              ID2
    1: Carlos US115115, CH123232, AB155, US4445 US115115, US4445
    2:  Henry                       CH112, BB53                 
    3:   John                        US57677777       US57677777
    

    【讨论】:

    • 如果您将正则表达式更改为 ",\\s*" ,您可以避免使用 trimws ,但这对我来说似乎很好。
    • 我也觉得sapply(strsplit(DT$ID, ","), function(s) toString(grep("^US", trimws(s), value = TRUE)))会短一点?
    • 谢谢,@latemail。已将您的 cmets 纳入解决方案
    • 非常好,@RonakShah。你也应该发布它,我发现它很有用,因为我了解到 toString 也有 string &lt;- paste(x, collapse = ", ")
    【解决方案2】:

    以下是受@thelatemail 和@chinsoon12 启发的一些建议

    DT$ID1 <- sapply(strsplit(DT$ID, ",\\s*"), function(x) 
                                toString(grep("^US", x, value = TRUE)))
    DT
    #     name                                ID              ID1
    #1: Carlos US115115, CH123232, AB155, US4445 US115115, US4445
    #2:  Henry                       CH112, BB53                 
    #3:   John                        US57677777       US57677777
    

    上面我们使用grep进行过滤,我们也可以使用startsWith来做同样的事情

    sapply(strsplit(DT$ID, ",\\s*"), function(x) toString(x[startsWith(x, "US")]))
    

    您可以在dplyr 链中合并上述两个选项,但是使用dplyrtidyr 的另一个选项将使用separate_rows,这对于这个特定的问题可能有点过头了。我们可以使用stringr 中的str_subset,与grep("^US", x, value = TRUE) 相同。

    library(dplyr)
    library(tidyr)
    
    DT %>%
      separate_rows(ID) %>%
      group_by(name) %>%
      summarise(ID1 = toString(ID), 
                ID2 = toString(stringr::str_subset(ID, "^US")))
    

    【讨论】:

      【解决方案3】:

      我们可以使用str_extract 来提取以“US”开头的单词

      library(stringr)
      DT[, ID2 := sapply(str_extract_all(ID, "\\bUS\\S*"), toString)]
      DT
      #     name                                ID               ID2
      #1: Carlos US115115, CH123232, AB155, US4445 US115115,, US4445
      #2:  Henry                       CH112, BB53                  
      #3:   John                        US57677777        US57677777
      

      或使用gsub

      DT[, ID2 := gsub("(\\bUS\\S*)(*SKIP)(*F)|.", "", ID, perl = TRUE)]
      

      或使用tidyverse

      library(tidyverse)
      DT %>%
          mutate(ID2 = str_extract_all(ID, "\\bUS\\S*") %>%
                         map(toString))
      

      或与base R 一起使用gregexpr

      DT$ID2 <- sapply(regmatches(DT$ID, gregexpr("\\bUS\\S*", DT$ID)), toString)
      

      【讨论】:

        猜你喜欢
        • 2012-11-05
        • 1970-01-01
        • 2011-12-30
        • 2016-08-27
        • 1970-01-01
        • 2015-09-18
        • 2021-07-07
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多