R data.table 使用 tstrsplit 分解列

R data.table explode column using tstrsplit

我以下面的data.table为例

df = data.table(id = c(1, 2, 3), val=c("['hello', 'world']", "['hi']", "['so', 'there']"))

我想将类似对象的列表拆分为单独的行,并重复 id。所以我想要的预期data.table是下面的

df2 = data.table(id = c(1, 1, 2, 3, 3), val=c("hello", "world", "hi", "so", "there"))

我尝试了以下方法

df[, c("test") := tstrsplit(val, ",", fixed=TRUE)]

但是,我得到了以下错误

Error in [.data.table(df, , :=(c("test"), tstrsplit(val, ",", fixed = TRUE))) : Supplied 2 items to be assigned to 3 items of column 'test'. If you wish to 'recycle' the RHS please use rep() to make this intent clear to readers of your code.

有人可以指出我在这里做错了什么吗?提前致谢。

这是一种方法,

df[, .(val = tstrsplit(gsub("[][']", "", val), ",", fixed=TRUE)), by = id]
#       id    val
#    <num> <list>
# 1:     1  hello
# 2:     1  world
# 3:     2     hi
# 4:     3     so
# 5:     3  there

它删除了所有方括号和单引号,然后将所有 val 字符串连接成一个字符串(,-折叠),然后 tstrsplit 按原意将它们连接起来. by=id 确保我们不会无意中组合不同的 val,并且 id 保留在输出中。

如果你想看到分组,组合,然后拆分的步骤,那么可以做到

df1[, .(val = paste(gsub("[][']", "", val), collapse = ",")), by = id]
#       id          val
#    <num>       <char>
# 1:     1 hello, world
# 2:     2           hi
# 3:     3    so, there
df1[, .(val = paste(gsub("[][']", "", val), collapse = ",")), by = id
  ][, .(val = tstrsplit(val, ",", fixed = TRUE)), by = id]
#       id    val
#    <num> <list>
# 1:     1  hello
# 2:     1  world
# 3:     2     hi
# 4:     3     so
# 5:     3  there

请注意 rep(id,...) 的错误建议很好,只是您需要做更多的工作才能知道每个 id 重复多少次;将它用作分组变量可以减轻这种需要,但会花费少量的执行时间(因为它对每个组执行一次 tstrsplit 而不是一起执行)。

tidyverse,我们可以用str_extract_allunnest

library(dplyr)
library(tidyr)
library(stringr)
df %>% 
  mutate(val = str_extract_all(val, '\w+')) %>%
  unnest(val)
# A tibble: 5 x 2
     id val  
  <dbl> <chr>
1     1 hello
2     1 world
3     2 hi   
4     3 so   
5     3 there

从您拥有的数据结构来看,您似乎拥有一个 python 数据集。您可以为此使用 reticulate

library(reticulate)
ast <- import('ast')

df_python <- r_to_py(df)
df_python$assign(val = df_python$val$transform(ast$literal_eval))$explode('val')

    id    val
0  1.0  hello
0  1.0  world
1  2.0     hi
2  3.0     so
2  3.0  there

你可以直接做:

df[, .(val = tstrsplit(gsub('[^a-z,]', '',val), ',')), by = 'id']
   id   val
1:  1 hello
2:  1 world
3:  2    hi
4:  3    so
5:  3 there

我想你可以使用 eval + str2lang

> df[, .(val = eval(str2lang(gsub("\[(.*)\]", "c(\1)", val)))), id]
   id   val
1:  1 hello
2:  1 world
3:  2    hi
4:  3    so
5:  3 there