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

R语言半长型数据转宽型数据 pivot_wider函数使用问题求解

R数据框长转宽实现方案

问题背景

当前需要将按NAME+YEAR存储的长格式成绩表转为宽格式,要求每个NAME仅占一行,不同年份对应的YEAR/MARKS/MAXIMUM字段展开为独立列。之前使用for循环实现性能较差,尝试tidyr::pivot_wider未得到预期结果。

示例原始数据结构如下:

NAME <- c("ABC", "ABC", "ABC", "DEF", "GHI", "GHI", "JKL", "JKL", "JKL", "MNO")
YEAR <- c(2012, 2013, 2014, 2012, 2012, 2013, 2012, 2014, 2016, 2013)
MARKS <- c(45, 75, 95, 91, 75, 76, 85, 88, 89, 77)
MAXIMUM <- c(95, NA, NA, 91, 76, NA, 89, NA, NA, 77)

DF <- data.frame(
  NAME,
  YEAR,
  MARKS,
  MAXIMUM
)

原始数据预览:

NAME YEAR MARKS MAXIMUM
1   ABC 2012    45      95
2   ABC 2013    75      NA
3   ABC 2014    95      NA
4   DEF 2012    91      91
5   GHI 2012    75      76
6   GHI 2013    76      NA
7   JKL 2012    85      89
8   JKL 2014    88      NA
9   JKL 2016    89      NA
10  MNO 2013    77      77

实现代码

不需要写for循环,正确配置pivot_wider参数即可高效完成转换,两种常用输出形式的代码如下:

  • 按年份顺序序号命名列(适配不同NAME年份数量不一致的场景,不会出现冗余空列)
library(dplyr)
library(tidyr)

wide_df <- DF %>%
  group_by(NAME) %>%
  mutate(seq = row_number()) %>%
  pivot_wider(
    id_cols = NAME,
    names_from = seq,
    values_from = c(YEAR, MARKS, MAXIMUM),
    names_sep = ""
  )

输出列名格式为YEAR1/MARKS1/MAXIMUM1/YEAR2/MARKS2……对应每个NAME下按年份升序排列的第n条记录。

  • 按实际年份值命名列
wide_df <- DF %>%
  pivot_wider(
    id_cols = NAME,
    names_from = YEAR,
    values_from = c(MARKS, MAXIMUM),
    names_sep = "_"
  )

输出列名格式为MARKS_2012/MAXIMUM_2012/MARKS_2013……对应各年份的成绩值,无对应年份记录的位置自动填充NA。

两种实现均为向量化运算,数据量较大时性能远高于手写for循环。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.01 05:09:31