【问题标题】:R reshaping melted data.table with list columnR用列表列重塑融化的data.table
【发布时间】:2013-01-11 11:17:12
【问题描述】:

我在variablevalue 列中有一个大的(数百万行)data.table 与通常的melt 样式展开。我需要以广泛的形式投射表格(向上滚动变量)。问题是数据表还有一个名为data 的列表列,我需要保留它。这使得无法使用reshape2,因为dcast 无法处理非原子列。因此,我需要自己做卷起。

来自previous question 的关于使用融合数据表的答案在此处不适用,因为列表列。

我对我提出的解决方案不满意。我正在寻找更简单/更快实施的建议。

x <- LETTERS[1:3]
dt <- data.table(
  x=rep(x, each=2),
  y='d',
  data=list(list(), list(), list(), list(), list(), list()),
  variable=rep(c('var.1', 'var.2'), 3),
  value=seq(1,6)
  )

# Column template set up
list_template <- Reduce(
  function(l, col) { l[[col]] <- col; l }, 
  unique(dt$variable),
  list())

# Expression set up
q <- substitute({
  l <- lapply(
    list_template, 
    function(col) .SD[variable==as.character(col)]$value)
  l$data = .SD[1,]$data
  l
}, list(list_template=list_template))

# Roll up
dt[, eval(q), by=list(x, y)]

   x y var.1 var.2   data
1: A d     1     2 <list>
2: B d     3     4 <list>
3: C d     5     6 <list>

【问题讨论】:

  • @Arun 完成;我在简化代码并提出一个可重现的示例时发布了。

标签: r data.table bigdata reshape


【解决方案1】:

我有一些作弊方法可以解决问题 - 重要的是,我假设每个 x,y,list 组合都是独一无二的!如果没有,请忽略。

我将创建两个单独的数据表,第一个数据表没有数据列表对象,第二个数据表只有唯一的数据列表对象和一个键。然后只需将它们合并在一起即可获得所需的结果。

require(data.table)
require(stringr)
require(reshape2)

x <- LETTERS[1:3]
dt <- data.table(
  x=rep(x, each=2),
  y='d',
  data=list(list("a","b"), list("c","d")),
  variable=rep(c('var.1', 'var.2'), 3),
  value=seq(1,6)
  )


# First create the dcasted datatable without the pesky list objects:
dt_nolist <- dt[,list(x,y,variable,value)]
dt_dcast <- data.table(dcast(dt_nolist,x+y~variable,value.var="value")
                       ,key=c("x","y"))


# Second: create a datatable with only unique "groups" of x,y, list
dt_list <- dt[,list(x,y,data)]

# Rows are duplicated so I'd like to use unique() to get rid of them, but
# unique() doesn't work when there's list objects in the data.table.
# Instead so I cheat by applying a value to each row within an x,y "group" 
# that is unique within EACH group, but present within EVERY group.
# Then just simply subselect based on that unique value.
# I've chosen rank(), but no doubt there's other options

dt_list <- dt_list[,rank:=rank(str_c(x,y),ties.method="first"),by=str_c(x,y)]

# now keep only one row per x,y "group"
dt_list <- dt_list[rank==1]
setkeyv(dt_list,c("x","y"))

# drop the rank since we no longer need it
dt_list[,rank:=NULL]

# Finally just merge back together
dt_final <- merge(dt_dcast,dt_list)

【讨论】:

    【解决方案2】:

    这个老问题激起了我的好奇心,因为 data.table 自 2013 年以来得到了显着改进。

    但是,即使使用 data.table 版本 1.11.4

    dcast(dt, x + y + data ~ variable)
    

    仍然返回错误

    公式中指定的列不能是列表类型

    解决方法遵循jonsedar's answer 的大致轮廓:

    1. 将非列表列从长格式改成宽格式
    2. 聚合列表列dataxy 分组
    3. xy 上加入两个部分结果

    但使用实际 data.table 语法的特性,例如 on 参数:

    dcast(dt, x + y ~ variable)[
      dt[, .(data = .(first(data))), by = .(x, y)], on = .(x, y)] 
    
       x y var.1 var.2   data
    1: A d     1     2 <list>
    2: B d     3     4 <list>
    3: C d     5     6 <list>
    

    列表列data 通过获取第一个元素进行聚合。这符合OP的代码行

    l$data = .SD[1,]$data
    

    它也选择第一个元素。

    【讨论】:

    • 或者(基本相同)...xdt = dt[, .SD[1L], by=.(x, y), .SDcols="data"]; mdt = dt[, .(x, variable, value)]; merge(xdt, dcast(mdt, x ~ variable), by="x")(我认为OP的输入和输出表都是格式错误的,应该将其拆分到多个表中。)
    猜你喜欢
    • 2020-07-08
    • 2013-08-21
    • 2016-12-31
    • 2016-06-26
    • 1970-01-01
    • 2017-03-30
    • 1970-01-01
    • 2017-11-04
    • 1970-01-01
    相关资源
    最近更新 更多