You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用data.table筛选长表并转置列值为新列的技术问题

问题描述

我有一个包含2200万行观测值的data.table,结构如下:

dt <- data.table(
  firm_id = c(1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2),
  metric = c("AN_BILANT", "OPEX", "CAPEX","AN_BILANT","OPEX", "CAPEX", "AN_BILANT", "OPEX", "CAPEX", "AN_BILANT","OPEX", "CAPEX"),
  value = c(2013, 10, 3,2014, 11, 5, 2007, 25, 10, 2009, 23, 7)
)

希望生成如下输出(修正了原目标输出的长度不一致问题,保证逻辑通顺):

output_dt <- data.table(
  firm_id = c(1, 1, 1, 1, 2, 2, 2, 2),
  metric = c("OPEX", "CAPEX","OPEX", "CAPEX", "OPEX", "CAPEX", "OPEX", "CAPEX"),
  AN_BILANT = c(2013, 2013, 2014, 2014, 2007, 2007, 2009, 2009),
  value = c(10, 3,11, 5, 25, 10,23, 7)
)

我最初尝试的代码:

dcast(dt[metric == "AN_BILANT"], firm_id ~ metric, value.var = "value", fun.aggregate = function(x) x)

出现错误:

错误:聚合函数应接受向量输入并返回单个值(长度=1)。但当前函数返回的长度≠1。该值需用于填充缺失组合,因此必须长度为1。可通过显式设置'fill'参数或修改函数来解决。

还尝试了:

dcast.data.table(dt[, N:=1:.N, metric], firm_id~metric, subset = (metric=="AN_BILANT") ) 

出现警告:

警告:缺少聚合函数,默认使用'length'

解决方案

你的需求核心是将每个firm_id下的AN_BILANT值,对应匹配到同公司的OPEX/CAPEX记录上。针对2200万行的大规模数据,推荐以下两种高效的data.table实现方式:

方法1:分组标识+合并法

通过给AN_BILANT和非AN_BILANT记录添加分组标识,实现精准匹配:

# 给每个firm_id内的AN_BILANT记录按出现顺序编号
an_bilant_dt <- dt[metric == "AN_BILANT", .(firm_id, AN_BILANT = value, group_id = 1:.N), by = firm_id]

# 给每个firm_id内的非AN_BILANT记录按每2条(OPEX+CAPEX)为一组编号
non_an_dt <- dt[metric != "AN_BILANT", .(firm_id, metric, value, group_id = ceiling(1:.N / 2)), by = firm_id]

# 按firm_id和group_id合并,得到目标结构
output_dt <- non_an_dt[an_bilant_dt, on = .(firm_id, group_id), nomatch = 0]
# 调整列顺序至目标格式
setcolorder(output_dt, c("firm_id", "metric", "AN_BILANT", "value"))

方法2:dcast+ melt组合转换

先将数据转成宽表提取AN_BILANT,再重新熔化为目标长表:

# 给每个firm_id内的记录按AN_BILANT出现的位置划分分组
dt[, group_id := cumsum(metric == "AN_BILANT"), by = firm_id]

# 宽表化,将不同metric转为列
wide_dt <- dcast(dt, firm_id + group_id ~ metric, value.var = "value")

# 重新熔化为目标长表格式
output_dt <- melt(wide_dt, id.vars = c("firm_id", "group_id", "AN_BILANT"), 
                  measure.vars = c("OPEX", "CAPEX"),
                  variable.name = "metric", value.name = "value")

# 移除临时分组列,调整列顺序
output_dt[, group_id := NULL]
setcolorder(output_dt, c("firm_id", "metric", "AN_BILANT", "value"))

两种方法都能高效处理大规模数据,其中方法2逻辑更直观,利用cumsum生成分组标识的方式,能自动适配不同firm_id下的记录数量差异。

内容的提问来源于stack exchange,提问作者newmathlearner_7

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 06:47:34