Отдельный строковый столбец в data.table в нескольких столбцах в R - PullRequest
0 голосов
/ 20 марта 2020

Представьте, что у меня есть 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

Какой быстрый способ сделать это, учитывая, что у меня есть data.table со 100k + строками?

Ответы [ 3 ]

1 голос
/ 20 марта 2020
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"
)
1 голос
/ 20 марта 2020

Мы можем использовать 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")
1 голос
/ 20 марта 2020

В одну сторону, используя 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

data

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))
...