将列表字符串向量解析为多列data.table

时间:2018-04-12 17:35:24

标签: r data.table

我正在尝试转换格式数据:

dt <- data.table(foo = c(c('a=a1|b=b1'),c('a=a2|b=b2|c=c2'),c('a=a3|d=d3')))

形成:

data.table(a=c('a1','a2','a3'),b=c('b1','b2',NA),c=c(NA,'c2',NA),d=c(NA,NA,'d3'))

我尝试使用以下方法解析第一步:

lapply(dt$foo, function(x) unlist(strsplit(x, split = '|', fixed = T)))

但无法继续前进。有什么指针吗?

3 个答案:

答案 0 :(得分:4)

如果提供更多案例,将会更新。这不是data.table,因为我没有使用它,但是afaik应该仍然可以使用吗?也许如果先被强迫data.frame

library(tidyverse)
dt <- tibble(foo = c(c('a=a1|b=b1'),c('a=a2|b=b2|c=c2'),c('a=a3|d=d3')))
tibble(a=c('a1','a2','a3'),b=c('b1','b2',NA),c=c(NA,'c2',NA),d=c(NA,NA,'d3'))
#> # A tibble: 3 x 4
#>   a     b     c     d    
#>   <chr> <chr> <chr> <chr>
#> 1 a1    b1    <NA>  <NA> 
#> 2 a2    b2    c2    <NA> 
#> 3 a3    <NA>  <NA>  d3

dt %>%
  mutate(foo = str_split(foo, pattern = "\\|")) %>%
  rowid_to_column() %>% 
  unnest() %>%
  separate(foo, into = c("col", "val"), sep = "=") %>%
  spread(col, val)
#> # A tibble: 3 x 5
#>   rowid a     b     c     d    
#>   <int> <chr> <chr> <chr> <chr>
#> 1     1 a1    b1    <NA>  <NA> 
#> 2     2 a2    b2    c2    <NA> 
#> 3     3 a3    <NA>  <NA>  d3

reprex package(v0.2.0)创建于2018-04-12。

答案 1 :(得分:3)

将我的评论转换为答案,您可以尝试:

library(splitstackshape)
cSplit(dt[, row := .I], "foo", "|", "long")[
  , cSplit(.SD, "foo", "=")][
    , dcast(.SD, row ~ foo_1, value.var = "foo_2")]
#    row  a    b    c    d
# 1:   1 a1   b1 <NA> <NA>
# 2:   2 a2   b2   c2 <NA>
# 3:   3 a3 <NA> <NA>   d3

您当然也可以只使用strsplittstrsplitdcast的组合。

dt[, unlist(strsplit(foo, "|", TRUE)), 1:nrow(dt)][
  , c("col", "val") := tstrsplit(V1, "=", fixed = TRUE)][
    , dcast(.SD, nrow ~ col, value.var = "val")]
#    nrow  a    b    c    d
# 1:    1 a1   b1 <NA> <NA>
# 2:    2 a2   b2   c2 <NA>
# 3:    3 a3 <NA> <NA>   d3

答案 2 :(得分:1)

一个选项是使用read.table函数将值读取为key-value对,然后最终转换为data.frame。 dplyr::bind_rows可以帮助您加入不同的行。

dt <- data.table(foo = c(c('a=a1|b=b1'),c('a=a2|b=b2|c=c2'),c('a=a3|d=d3')))

library(dplyr)
bind_rows(mapply(function(x){
  t <- read.table(text = gsub("\\|","\n",x), sep=c("="), stringsAsFactors=FALSE)
  t <- as.data.frame(t(t), stringsAsFactors = FALSE)
  colnames(t) <- t[1,]
  t <- t[-1,]
  }, dt$foo))
#    a    b    c    d
# 1 a1   b1 <NA> <NA>
# 2 a2   b2   c2 <NA>
# 3 a3 <NA> <NA>   d3
@abhiieor建议的

更新: data.table解决方案如下:

library(data.table)
rbindlist(mapply(function(x){
  t <- read.table(text = gsub("\\|","\n",x), sep=c("="), stringsAsFactors=FALSE)
  t <- as.data.frame(t(t), stringsAsFactors = FALSE)
  colnames(t) <- t[1,]
  t <- t[-1,]
  }, dt$foo), use.names = T, fill = T)