如何不使用dcast将data.table的列表类型列展开为宽格式
更简洁地将data.table的列表列转为宽格式列
你的思路是对的——先转长再转宽确实能解决问题,但确实有更直接的方式,不用绕弯子处理行ID和后续关联,还能直接保留原表的所有列。
先看你的示例数据
library(data.table) dt = data.table( list_col = list(c(404, 444), c(404, 444), c(444,484), c(444, 484), c(364, 404)), other_col = c('A', 'B', 'D', 'E', 'A') )
最直接的实现方式:用transpose一步转宽
因为你的列表列中每个元素的长度是固定的(都是2),可以直接用data.table的transpose()函数把列表列拆成多列,然后直接添加到原表中:
# 直接新增宽格式列,自动命名为col_1、col_2,同时保留原所有列 dt[, paste0("col_", seq_along(list_col[[1]])) := transpose(list_col)]
执行后你的dt会变成这样:
list_col other_col col_1 col_2 1: 404,444 A 404 444 2: 404,444 B 404 444 3: 444,484 D 444 484 4: 444,484 E 444 484 5: 364,404 A 364 404
这个方法的优势:
- 不需要额外创建行ID、分组ID,一步完成转换
- 直接保留原表的
list_col和other_col,不需要后续关联恢复 - 代码简洁,效率也更高
如果列表元素长度不一致?
如果你的列表列里元素长度不固定,可以先统一长度(比如用padNA补全),再用上面的方法:
# 补全列表元素到最长长度 max_len = max(lengths(dt$list_col)) dt[, list_col := lapply(list_col, function(x) c(x, rep(NA, max_len - length(x))))] # 再转宽 dt[, paste0("col_", 1:max_len) := transpose(list_col)]
简化你原来的长转宽思路
如果你还是倾向于用长转宽的方式,也可以简化代码,避免手动复制行:
# 生成长格式表 long_dt = dt[, .(unlist_col = unlist(list_col)), by = .(row_id = .I, other_col)] # 添加分组内ID long_dt[, group_row_id := rowid(row_id)] # 转宽并合并回原列表列 wide_dt = dcast(long_dt, row_id + other_col ~ group_row_id, value.var = "unlist_col") wide_dt = wide_dt[dt, on = "row_id"]
这样也能得到同样的结果,代码比你原来的版本更简洁一些。
内容的提问来源于stack exchange,提问作者ira
相关产品推荐
相关产品推荐

