data.table中实现unstack()长转宽功能的正确方法是什么?
用data.table实现类似base R unstack()的长转宽操作
问题描述
平时用base R的unstack()可以轻松将长格式数据转成宽格式,比如示例中把包含class(A/B/C重复3次)和value的9行数据转成3行3列的结果,但用data.table的dcast()时得到的是9行的错误结果,还会遇到Aggregate function missing, defaulting to 'length'的提示,导致结果行数不符合预期,且不想使用聚合函数。
示例代码及错误结果:
library(data.table) set.seed(1) df <- data.frame(class = factor(rep(c("A", "B", "C"), times = 3)), value = runif(9)) # 期望的unstack结果 unstack(df, form = value ~ class) #> A B C #> 1 0.2655087 0.3721239 0.5728534 #> 2 0.9082078 0.2016819 0.8983897 #> 3 0.9446753 0.6607978 0.6291140 dt <- data.table(df) # 错误的dcast用法 dcast(dt, formula = value ~ class, value.var = "value") #> value A B C #> 1: 0.2016819 NA 0.2016819 NA #> 2: 0.2655087 0.2655087 NA NA #> 3: 0.3721239 NA 0.3721239 NA #> 4: 0.5728534 NA NA 0.5728534 #> 5: 0.6291140 NA NA 0.6291140 #> 6: 0.6607978 NA 0.6607978 NA #> 7: 0.8983897 NA NA 0.8983897 #> 8: 0.9082078 0.9082078 NA NA #> 9: 0.9446753 0.9446753 NA NA
解决方法
核心是给每个class分组添加行序号,让dcast()能识别同一行对应的各个class的value,避免触发聚合逻辑:
- 先为每个class分组生成递增的序号
idx,标记每个value在组内的位置 - 使用
dcast()时,将idx作为行变量,class作为列变量,即可得到和unstack()一致的结果
修正后的代码
library(data.table) set.seed(1) df <- data.frame(class = factor(rep(c("A", "B", "C"), times = 3)), value = runif(9)) dt <- data.table(df) # 给每个class分组添加行序号 dt[, idx := seq_len(.N), by = class] # 正确的dcast用法 dcast(dt, idx ~ class, value.var = "value") #> idx A B C #> 1: 1 0.2655087 0.3721239 0.5728534 #> 2: 2 0.9082078 0.2016819 0.8983897 #> 3: 3 0.9446753 0.6607978 0.6291140
关键说明
- 之前错误的
dcast(dt, value ~ class)把value作为行分组变量,导致每个value单独成一行,而不是按组内顺序合并 - 添加
idx后,每个(idx, class)组合唯一,dcast()无需聚合即可直接填充对应值,不会再出现Aggregate function missing的提示 - 如果不需要保留
idx列,可以用dcast(...)[, idx := NULL]移除
内容的提问来源于stack exchange,提问作者nukubiho
相关产品推荐
相关产品推荐

