如何将dataframe按分组把多行指标值转换为各分组独立列
R数据框分组转列实现方法
需求说明
需要对存储分组数据的长表做结构转换:
- 原始数据共两列:
subject.number取值范围1-9,每个编号重复出现多次,重复次数对应该编号关联的sentiment.score的总数量 - 目标结构:每个
subject.number单独作为一列,列内按原有顺序存储对应所有sentiment.score值,不同列长度不一致时,缺失位置填充NA
原始数据样例:
subject.number sentiment.score 1 1 -1.0 2 1 -0.5 3 1 0.0 4 1 0.5 5 1 1.0 6 1 -1.0 7 1 -0.5 8 1 0.0 9 1 0.5 10 1 1.0 11 2 -1.0 12 2 -0.5 13 2 0.0 14 2 0.5 15 2 1.0 16 2 -1.0 17 2 -0.5 18 2 0.0 19 2 0.5 20 3 1.0 21 3 -1.0 22 3 -0.5 23 3 0.0 24 3 0.5 25 3 1.0 26 3 -1.0 27 3 -0.5 28 4 0.0 29 4 0.5 30 4 1.0 31 4 -1.0 32 4 -0.5 33 4 0.0 34 4 0.5 35 5 1.0 36 5 -1.0 37 5 -0.5 38 5 0.0 39 5 0.5 40 5 1.0 41 6 -1.0 42 6 -0.5 43 6 0.0 44 6 0.5 45 6 1.0 46 7 -1.0 47 7 -0.5 48 7 0.0 49 7 0.5 50 8 1.0 51 8 -1.0 52 8 -0.5 53 9 0.0 54 9 0.5
目标输出样例:
X1 X2 X3 X4 X5 X6 X7 X8 X9 1 -1.0 -1.0 1.0 0.0 1.0 -1.0 -1.0 1.0 0.0 2 -0.5 -0.5 -1.0 0.5 -1.0 -0.5 -0.5 -1.0 0.5 3 0.0 0.0 -0.5 1.0 -0.5 0.0 0.0 -0.5 NA 4 0.5 0.5 0.0 -1.0 0.0 0.5 0.5 NA NA 5 1.0 1.0 0.5 -0.5 0.5 1.0 NA NA NA 6 -1.0 -1.0 1.0 0.0 1.0 NA NA NA NA 7 -0.5 -0.5 -1.0 0.5 NA NA NA NA NA 8 0.0 0.0 -0.5 NA NA NA NA NA NA 9 0.5 0.5 NA NA NA NA NA NA NA 10 1.0 NA NA NA NA NA NA NA NA
实现代码
不需要手写复杂循环,以下两种向量化实现方式运行效率更高,代码更易维护:
方法1:tidyverse 方案(代码最简洁)
通过分组加行号做唯一标识,直接调用宽表转换函数即可,缺失值会自动填充为NA:
library(tidyverse) # 假设原始数据框命名为df result <- df %>% group_by(subject.number) %>% # 给每个分组内的得分按原有顺序生成行序号 mutate(rn = row_number()) %>% # 转换为宽表,列名自动加X前缀 pivot_wider(names_from = subject.number, values_from = sentiment.score, names_prefix = "X") %>% # 移除辅助用的行序号列 select(-rn)
方法2:Base R 方案(无需加载第三方包)
先按分组拆分数据,统一长度补NA后合并为数据框:
# 按subject.number拆分得分为列表 score_split <- split(df$sentiment.score, df$subject.number) # 计算所有分组中的最大长度 max_length <- max(lengths(score_split)) # 每个分组向量补NA到统一长度,合并为数据框并设置列名 result <- as.data.frame( lapply(score_split, \(x) c(x, rep(NA, max_length - length(x)))), col.names = paste0("X", names(score_split)) )
参考:for循环实现方式
如果需要用for循环完成,逻辑和base R方案一致,参考代码如下:
sub_num <- sort(unique(df$subject.number)) max_length <- max(table(df$subject.number)) # 初始化全NA的空结果框 result <- as.data.frame(matrix(NA, nrow = max_length, ncol = length(sub_num))) colnames(result) <- paste0("X", sub_num) # 逐列填充对应分组的得分 for (i in seq_along(sub_num)) { current_val <- df$sentiment.score[df$subject.number == sub_num[i]] result[seq_along(current_val), i] <- current_val }
以上三种方式输出结果完全一致,和目标样例匹配。
内容的提问来源于stack exchange,提问作者Eva Bonning
相关产品推荐
相关产品推荐

