我想知道是否有一个使用data.table的干净解决方案来解决以下问题,可能使用其他程序包(例如stringer)。
假设我有以下数据表
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
,其中每个元素都是一个字符串。我已经能够编写一个代码,该版本使用第一个“美国身份”并丢弃其余的,但我却找不到能够处理多重性的解决方案。
任何帮助将不胜感激!
答案 0 :(得分:4)
一种可能的方法:
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
答案 1 :(得分: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
链中同时包含上述两个选项,但是使用dplyr
和tidyr
的另一个选项将使用separate_rows
,这对于这个特定问题可能是过大的了。我们可以使用str_subset
中的stringr
与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")))
答案 2 :(得分:0)
我们可以使用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
的{{1}}
gregexpr