如何在R中依据分组变量拆分数值列并生成精简宽表?
解决R中长表转宽表的问题
需求说明
将长格式数据转换为宽格式:每个entity_name(关联对应的bus_reg_no)对应一行,把TimePeriod的2018/2019/2020取值作为列名,填充对应的market_test数值。
第一步:修正原始数据结构
你用cbind()创建的dat是字符型矩阵,而非数据框,且market_test被强制转换为字符类型,这会导致后续转换函数无法正确识别数值。先修正数据结构:
# 重新构建正确的数据框 bus_reg_no <- c('G01', 'G01', 'G01', 'G02', 'G02', 'G02', 'G03', 'G03' , 'G03') entity_name <- c('A','A','A','B','B','B','C','C','C') TimePeriod <- c('2020','2019','2018','2020','2019','2018','2020','2019','2018') market_test <- c(NA, 0.9330331232, 0.9969181046, 0.9429920482, 0.9689617356, 0.9764825438, NA, 0.2302289569, 0.7762837775) dat <- data.frame( bus_reg_no = bus_reg_no, entity_name = entity_name, TimePeriod = TimePeriod, market_test = market_test, stringsAsFactors = FALSE )
解决方案1:使用dcast函数
全量数据出现"Aggregate function missing, defaulting to 'length'"警告,是因为你的全量数据中存在重复的(entity_name, TimePeriod)分组(同一个实体同一年份有多条记录),dcast默认用length统计数量,所以输出0/1。解决方法是指定聚合函数,明确如何处理重复值:
library(reshape2) # 转换为宽表,取每个分组的第一个非NA值(可根据业务需求替换为mean/sum等) dat_wide_dcast <- dcast( data = dat, formula = bus_reg_no + entity_name ~ TimePeriod, # 行标识 ~ 列名来源 value.var = "market_test", # 要填充的数值列 fun.aggregate = function(x) x[!is.na(x)][1] # 处理重复分组的逻辑 )
解决方案2:使用pivot_wider函数
你之前的报错是因为错误地将entity_name放入names_from参数,导致行标识缺失,触发下标越界。正确用法是指定行标识列、列名来源列和数值列:
library(tidyr) # 转换为宽表,同样处理重复值 dat_wide_pivot <- pivot_wider( data = dat, id_cols = c(bus_reg_no, entity_name), # 行的唯一标识列 names_from = TimePeriod, # 作为列名的变量 values_from = market_test, # 填充列的数值来源 values_fn = function(x) x[!is.na(x)][1] # 重复分组的处理逻辑 )
转换后结果示例
两种方法都会得到如下宽表:
| bus_reg_no | entity_name | 2020 | 2019 | 2018 |
|---|---|---|---|---|
| G01 | A | NA | 0.9330331 | 0.9969181 |
| G02 | B | 0.9429920 | 0.9689617 | 0.9764825 |
| G03 | C | NA | 0.2302290 | 0.7762838 |
内容的提问来源于stack exchange,提问作者daisy
相关产品推荐
相关产品推荐

