R语言:无for循环重格式化并合并多份宽格式气候数据框
问题描述
我有4份宽格式的气候数据框,结构为第一列为年份(Year),第2至13列分别对应1-12月的气候变量均值。需要将它们转换合并为长格式数据框,列结构为:年份、月份、各数据框对应的气候变量(示例如下)。
现有数据示例(共4份)
| 年份 | 1月 | 2月 |
|---|---|---|
| 1991 | 33.3 | 30.1 |
| 1992 | 32.1 | 29.7 |
目标数据格式示例
| 年份 | 月份 | 最高温(Tmax) | 最低温(Tmin) |
|---|---|---|---|
| 1991 | 1月 | 33.3 | 22.1 |
| 1991 | 2月 | 30.1 | 20.1 |
目前用嵌套for循环实现,但处理大数据集效率低,求更高效的重塑方法。
现有for循环代码
rainvec <- c() for (i in 42:nrow(rain)) { for (j in 2:13) { rainvec <- c(rainvec, rain[[i,j]]) } } tminvec <- c() for (i in 1:nrow(tmin)) { for (j in 2:13) { tminvec <- c(tminvec, tmin[[i,j]]) } } tmaxvec <- c() for (i in 1:nrow(tmax)) { for (j in 2:13) { tmaxvec <- c(tmaxvec, tmax[[i,j]]) } } tmeanvec <- c() for (i in 1:nrow(tmean)) { for (j in 2:13) { tmeanvec <- c(tmeanvec, tmean[[i,j]]) } } years <- sort(rep(tmean[[1]], 12)) months <- rep(1:12, nrow(tmin)) clim <- data.frame(years, months, rainvec, tminvec, tmaxvec, tmeanvec)
高效解决方案:使用tidyverse工具包
循环拼接向量的方式效率极低(每次c()都会重新分配内存),推荐用tidyr的pivot_longer()函数完成宽转长,再通过dplyr的inner_join()合并数据,全程向量化操作,处理大数据集速度会快很多。
步骤说明
- 给每个数据框的气候变量指定明确名称;
- 对每个数据框执行宽转长,将月份列转为行记录;
- 按
年份和月份合并所有长格式数据框。
完整代码示例
# 加载工具包 library(tidyverse) # 假设4个数据框分别为rain, tmin, tmax, tmean # 逐个处理宽转长 rain_long <- rain %>% pivot_longer(cols = -年份, names_to = "月份", values_to = "降水量(Rain)") tmin_long <- tmin %>% pivot_longer(cols = -年份, names_to = "月份", values_to = "最低温(Tmin)") tmax_long <- tmax %>% pivot_longer(cols = -年份, names_to = "月份", values_to = "最高温(Tmax)") tmean_long <- tmean %>% pivot_longer(cols = -年份, names_to = "月份", values_to = "平均温(Tmean)") # 合并所有数据框 clim_final <- rain_long %>% inner_join(tmin_long, by = c("年份", "月份")) %>% inner_join(tmax_long, by = c("年份", "月份")) %>% inner_join(tmean_long, by = c("年份", "月份")) # 查看结果 head(clim_final)
批量处理优化
如果需要简化代码,可将数据框放入列表,用批量函数处理:
# 批量处理示例 data_list <- list( 降水量(Rain) = rain, 最低温(Tmin) = tmin, 最高温(Tmax) = tmax, 平均温(Tmean) = tmean ) clim_final <- data_list %>% imap(function(df, var_name) { df %>% pivot_longer(cols = -年份, names_to = "月份", values_to = var_name) }) %>% reduce(inner_join, by = c("年份", "月份"))
补充说明
- 若月份列是纯数字(如
1而非1月),可通过mutate(月份 = str_c(月份, "月"))转换格式; - 若各数据框年份范围不一致,可改用
full_join()替代inner_join()保留所有年份记录。
内容的提问来源于stack exchange,提问作者The_Tams
相关产品推荐
相关产品推荐

