如何将数据框按Grp1分组,将指标列转为行并以Grp2值为列?
数据重塑解决方案:转置指标列并拆分分组列
输入数据
首先确认输入的数据结构:
df <- structure(list(Grp1 = c("A", "A", "B", "B"), Grp2 = c("test", "ctrl", "test", "ctrl"), metric1 = c(10L, 50L, 40L, 30L), metric2 = c(10L, 20L, 45L, 40L), metric3 = c(15L, 20L, 30L, 40L), metric4 = 1:4), class = "data.frame", row.names = c(NA, -4L))
方法一:使用tidyverse(推荐)
通过pivot_longer将宽格式的指标列转成长格式,再用pivot_wider将分组列拆分为单独的列:
library(tidyverse) result <- df %>% # 将metric1至metric4转换为行,生成metric(指标名)和value(指标值)列 pivot_longer( cols = starts_with("metric"), names_to = "metric", values_to = "value" ) %>% # 将Grp2的test/ctrl值转换为独立列,填充对应指标值 pivot_wider( names_from = Grp2, values_from = value ) %>% # 按Grp1和metric排序,匹配期望输出的顺序 arrange(Grp1, metric) # 查看结果 print(result)
步骤解释:
pivot_longer:批量处理所有以metric开头的列,把列名存入metric列,对应数值存入value列,完成宽→长转换。pivot_wider:将Grp2中的不同分组(test、ctrl)转为列名,value列的数值填充到对应位置,完成长→宽转换。arrange:按Grp1和metric排序,确保输出顺序与你提供的期望结果一致(可选操作,若不关心顺序可省略)。
方法二:使用base R
如果不想加载额外包,可以用base R的reshape函数完成:
# 第一步:将指标列转成长格式 melted_df <- reshape( df, varying = paste0("metric", 1:4), v.names = "value", timevar = "metric", times = paste0("metric", 1:4), direction = "long" ) # 第二步:将Grp2分组转为列 result_base <- reshape( melted_df, idvar = c("Grp1", "metric"), timevar = "Grp2", direction = "wide" ) # 整理列名和行顺序 colnames(result_base) <- gsub("value\\.", "", colnames(result_base)) result_base <- result_base[order(result_base$Grp1, result_base$metric), ] row.names(result_base) <- NULL # 查看结果 print(result_base)
验证结果
两种方法得到的结果都与你提供的期望输出结构一致,以tidyverse方法的结果为例,其结构为:
str(result) # 'data.frame': 8 obs. of 4 variables: # $ Grp1 : chr "A" "A" "A" "A" "B" "B" "B" "B" # $ metric: chr "metric1" "metric2" "metric3" "metric4" "metric1" "metric2" "metric3" "metric4" # $ test : int 10 10 15 1 40 45 30 3 # $ ctrl : int 50 20 20 2 30 40 40 4
内容的提问来源于stack exchange,提问作者te time
相关产品推荐
相关产品推荐

