想象一下我有一个带有以下字符串列的R data.table:
string
a1; b: b1, b2, b3; c: c1, c2, c3
a1; b: b2, b3, b4; c: c1, c2, c3; d: d1, d2, d3
a2; b: b1, b2, b3; c: c2, c5, c6; d: d1, d2, d3; e: e2, e3, e4
a5; b: b5, b6, b7; c: c1, c2, c3; d: d1, d2, d3
a6; b: b1, b2, b3; c: c1, c4, c5; d: d1, d2, d3; e: e1, e2, e3; f: f1, f2, f3
我想用分号分隔每个字符串,然后像这样将其写入新列(a, b, c, d, e, f
):
a b c d e f
a1 b1, b2, b3 c1, c2, c3 NA NA NA
a1 b2, b3, b4 c1, c2, c3 d1, d2, d3 NA NA
a2 b1, b2, b3 c2, c5, c6 d1, d2, d3 e2, e3, e4 NA
a5 b5, b6, b7 c1, c2, c3 d1, d2, d3 NA NA
a6 b1, b2, b3 c1, c4, c5 d1, d2, d3 e1, e2, e3 f1, f2, f3
考虑到我有一个具有100k +行的data.table,这样做的斋戒方法是什么?
DT <- DT[, tstrsplit(string, "; [a-z]:")]
# If data is in alphabetical order
setnames(DT, letters[1:6])
# Otherwise smth like this:
setnames(
DT,
DT[, sapply(.SD, function(x) stringr::str_extract(x[!is.na(x)], "[a-z]")[[1]])]
)
a b c d e f
1: a1 b1, b2, b3 c1, c2, c3 <NA> <NA> <NA>
2: a1 b2, b3, b4 c1, c2, c3 d1, d2, d3 <NA> <NA>
3: a2 b1, b2, b3 c2, c5, c6 d1, d2, d3 e2, e3, e4 <NA>
4: a5 b5, b6, b7 c1, c2, c3 d1, d2, d3 <NA> <NA>
5: a6 b1, b2, b3 c1, c4, c5 d1, d2, d3 e1, e2, e3 f1, f2, f3
可复制数据:
DT <- fread(
"string
a1; b: b1, b2, b3; c: c1, c2, c3
a1; b: b2, b3, b4; c: c1, c2, c3; d: d1, d2, d3
a2; b: b1, b2, b3; c: c2, c5, c6; d: d1, d2, d3; e: e2, e3, e4
a5; b: b5, b6, b7; c: c1, c2, c3; d: d1, d2, d3
a6; b: b1, b2, b3; c: c1, c4, c5; d: d1, d2, d3; e: e1, e2, e3; f: f1, f2, f3",
sep = "\n"
)
使用dplyr
和tidyr
的一种方法
library(dplyr)
library(tidyr)
df %>%
mutate(row = row_number()) %>%
separate_rows(string, sep = ";") %>%
separate(string, into = c('column', 'value'), sep = ":\\s+", fill = 'left') %>%
mutate(column = replace_na(column, 'a')) %>%
pivot_wider(names_from = column, values_from = value) %>%
select(-row)
# a ` b` ` c` ` d` ` e` ` f`
# <chr> <chr> <chr> <chr> <chr> <chr>
#1 a1 b1, b2, b3 c1, c2, c3 NA NA NA
#2 a1 b2, b3, b4 c1, c2, c3 d1, d2, d3 NA NA
#3 a2 b1, b2, b3 c2, c5, c6 d1, d2, d3 e2, e3, e4 NA
#4 a5 b5, b6, b7 c1, c2, c3 d1, d2, d3 NA NA
#5 a6 b1, b2, b3 c1, c4, c5 d1, d2, d3 e1, e2, e3 f1, f2, f3
数据
df <- structure(list(string = c("a1; b: b1, b2, b3; c: c1, c2, c3",
"a1; b: b2, b3, b4; c: c1, c2, c3; d: d1, d2, d3", "a2; b: b1, b2, b3; c: c2, c5, c6; d: d1, d2, d3; e: e2, e3, e4",
"a5; b: b5, b6, b7; c: c1, c2, c3; d: d1, d2, d3", "a6; b: b1, b2, b3; c: c1, c4, c5; d: d1, d2, d3; e: e1, e2, e3; f: f1, f2, f3"
)), class = "data.frame", row.names = c(NA, -5L))
我们可以使用cSplit
中的splitstackshape
library(splitstackshape)
out <- cSplit(DT, "string", sep=";\\s*", fixed = FALSE)
names(out) <- letters[seq_along(out)]
out
# a b c d e f
#1: a1 s*b: b1, b2, b3 s*c: c1, c2, c3 <NA> <NA> <NA>
#2: a1 s*b: b2, b3, b4 s*c: c1, c2, c3 s*d: d1, d2, d3 <NA> <NA>
#3: a2 s*b: b1, b2, b3 s*c: c2, c5, c6 s*d: d1, d2, d3 s*e: e2, e3, e4 <NA>
#4: a5 s*b: b5, b6, b7 s*c: c1, c2, c3 s*d: d1, d2, d3 <NA> <NA>
#5: a6 s*b: b1, b2, b3 s*c: c1, c4, c5 s*d: d1, d2, d3 s*e: e1, e2, e3 s*f: f1, f2, f3
DT <- structure(list(string = c("a1; b: b1, b2, b3; c: c1, c2, c3",
"a1; b: b2, b3, b4; c: c1, c2, c3; d: d1, d2, d3", "a2; b: b1, b2, b3; c: c2, c5, c6; d: d1, d2, d3; e: e2, e3, e4",
"a5; b: b5, b6, b7; c: c1, c2, c3; d: d1, d2, d3", "a6; b: b1, b2, b3; c: c1, c4, c5; d: d1, d2, d3; e: e1, e2, e3; f: f1, f2, f3"
)), row.names = c(NA, -5L), class = "data.frame")