1. 引言
在数据分析工作中,数据重塑(Data Reshaping)是最常见也最基础的操作之一。无论是从数据库导出的原始记录,还是从 Excel 手工整理的数据,往往都需要经过长表(Long Format)与宽表(Wide Format)之间的转换,才能满足后续建模、可视化和报表输出的需求。R 语言凭借其强大的数据处理生态,提供了多种灵活的工具来完成这类任务。本文将从基础函数讲起,逐步过渡到 tidyverse 体系下的现代写法,并通过丰富的代码实例帮助读者快速上手。
2. 长表与宽表的基本概念
在开始写代码之前,先明确两个核心概念:
- 宽表(Wide Format):每一行代表一个观测主体,每个变量占据一列。例如,每个城市一行,不同年份的 GDP 分别作为独立列。
- 长表(Long Format):每一行代表一个观测值,变量名和取值被拆分成两列。例如,每个城市-年份组合一行,GDP 作为一列,年份作为另一列。
宽表便于阅读和展示,长表则更适合分组计算、ggplot2 绘图以及多数统计模型。理解两者的差异,是掌握数据重塑的第一步。
3. 使用基础函数进行数据重塑
R 基础包中提供了reshape()函数,虽然语法略显繁琐,但在不依赖外部包的情况下依然可用。下面通过一个简单的示例演示其用法。
# 创建一个宽表数据 wide_data <- data.frame( city = c("北京", "上海", "广州"), gdp_2020 = c(3610, 3870, 2500), gdp_2021 = c(4020, 4320, 2820), gdp_2022 = c(4160, 4460, 2880) ) print(wide_data) 使用 reshape 将宽表转为长表 long_data <- reshape( wide_data, direction = "long", varying = c("gdp_2020", "gdp_2021", "gdp_2022"), v.names = "gdp", timevar = "year", times = c(2020, 2021, 2022), idvar = "city" ) print(long_data)运行上述代码后,long_data中每一行对应一个城市-年份组合,year列标识年份,gdp列存放对应的数值。可以看到,基础函数的参数较多,理解成本较高,因此在实际项目中更推荐使用 tidyverse 体系下的工具。
4. 使用 tidyr 包进行数据重塑
tidyr是 tidyverse 生态中专门用于数据清洗和重塑的包,其核心函数pivot_longer()和pivot_wider()语法直观、易读,是目前最主流的做法。下面分别演示长表和宽表之间的双向转换。
4.1 宽表转长表:pivot_longer()
library(tidyr) 继续使用上面的宽表数据 long_data2 <- wide_data %>% pivot_longer( cols = starts_with("gdp_"), names_to = "year", values_to = "gdp", names_prefix = "gdp_" ) print(long_data2)这里cols指定需要转换的列,names_to指定新生成的列名,values_to指定取值列名,names_prefix用于去除列名中的公共前缀。相比reshape(),代码意图一目了然。
4.2 长表转宽表:pivot_wider()
# 将长表转回宽表 wide_data2 <- long_data2 %>% pivot_wider( names_from = "year", values_from = "gdp", names_prefix = "gdp_" ) print(wide_data2)names_from指定由哪一列的值生成新列名,values_from指定取值来源列。经过转换后,数据又恢复为每个城市一行、不同年份作为独立列的结构。
5. 实战案例:销售数据重塑
下面通过一个更贴近业务的案例,完整演示从原始数据到分析就绪数据的全过程。假设我们有一份各门店各季度的销售额数据,需要先转为长表进行汇总计算,再转为宽表输出报表。
library(dplyr) library(tidyr) 原始宽表数据 sales_wide <- data.frame( store = c("A店", "B店", "C店"), q1 = c(120, 98, 150), q2 = c(135, 110, 160), q3 = c(142, 105, 175), q4 = c(158, 130, 190) ) print(sales_wide) 转为长表,便于按季度汇总 sales_long <- sales_wide %>% pivot_longer( cols = q1:q4, names_to = "quarter", values_to = "sales" ) print(sales_long) 按季度汇总总销售额 quarter_summary <- sales_long %>% group_by(quarter) %>% summarise(total_sales = sum(sales)) print(quarter_summary) 再转回宽表,输出各门店各季度报表 sales_report <- sales_long %>% pivot_wider( names_from = "quarter", values_from = "sales", names_prefix = "季度_" ) print(sales_report)通过这个案例可以看到,长表在分组计算时非常方便,而宽表在最终展示时更直观。实际工作中常常需要在这两种形态之间来回切换,掌握pivot_longer()和pivot_wider()就能应对绝大多数场景。
6. 处理重复值与缺失值
在数据重塑过程中,经常会遇到重复记录或缺失值。例如,同一门店同一季度出现多条记录时,pivot_wider()会报错或产生列表列。此时需要先对数据进行去重或聚合处理。
# 构造包含重复记录的长表 dup_long <- data.frame( store = c("A店", "A店", "B店"), quarter = c("q1", "q1", "q1"), sales = c(120, 125, 98) ) 先按门店和季度去重(取平均值) dedup <- dup_long %>% group_by(store, quarter) %>% summarise(sales = mean(sales), .groups = "drop") print(dedup) 再转为宽表 dedup_wide <- dedup %>% pivot_wider( names_from = "quarter", values_from = "sales" ) print(dedup_wide)对于缺失值,可以在pivot_wider()中使用values_fill参数指定填充值,例如用 0 填充缺失的销售额。
# 使用 values_fill 填充缺失值 filled_wide <- sales_long %>% pivot_wider( names_from = "quarter", values_from = "sales", values_fill = list(sales = 0) ) print(filled_wide)7. 多变量同时重塑
当数据中包含多个需要同时转换的变量时,pivot_longer()和pivot_wider()同样可以优雅处理。例如,数据中同时记录了销售额和利润额,需要将两者都转为长表。
# 包含多个指标列的宽表 multi_wide <- data.frame( store = c("A店", "B店"), sales_q1 = c(120, 98), sales_q2 = c(135, 110), profit_q1 = c(30, 22), profit_q2 = c(35, 28) ) print(multi_wide) 同时转换销售额和利润额 multi_long <- multi_wide %>% pivot_longer( cols = -store, names_to = c("metric", "quarter"), names_sep = "_", values_to = "value" ) print(multi_long)这里通过names_sep将列名拆分为metric和quarter两列,从而在一次操作中完成多变量的重塑,避免了多次转换的繁琐。
8. 总结
数据重塑是 R 数据分析流程中的关键环节。本文从基础函数reshape()讲起,重点介绍了 tidyverse 体系下tidyr包的pivot_longer()和pivot_wider()两个核心函数,并通过销售数据实战案例演示了长表与宽表之间的双向转换,以及重复值、缺失值、多变量等常见问题的处理方法。掌握这些技巧后,读者可以更高效地完成数据清洗和准备工作,为后续的建模与可视化打下坚实基础。