R语言中使用spread()转置数据时为何出现NA缺失值?
问题描述
我有如下数据:
dataA= data.frame( Location = rep(c("East", "West", "North"), each = 12 * 2), Season = rep(rep(c(2021, 2022), each = 6), 3), Genotype = rep(rep(c("CV1", "CV2"), each = 6), 3), Iron_ton_ha = rep(c(21.7127, 16.9369, 30.7798, 14.0833, 13.2023, 11.1327, 15.0424, 9.6616, 5.8569, 6.1881, 8.0127, 6.0291), each = 6), Stage = rep(c("Vegetative", "Reproductive", "Maturity"), each = 12), Fe = rep(c(0.44, 0.36, 0.31, 0.28, 0.79, 0.38, 0.59, 0.35, 0.41, 0.4, 0.29, 0.27, 0.37, 0.3, 0.31, 0.28, 0.16, 0.24, 0.57, 0.27, 0.23, 0.26, 0.26, 0.27, 0.13, 0.15, 0.04, 0.06, 0.03, 0.23, 0.52, 0.06, 0.08, 0.11, 0.1, 0.04), each = 2) )
我希望将Stage列中的每个变量转为单独列,使用了以下代码,但结果出现大量NA缺失值,请问为何该代码无法正常工作?
使用的代码及结果:
library(dplyr) library(tidyverse) dataB= dataA %>% group_by(Location, Season, Genotype, Iron_ton_ha, Stage) %>% summarise(Fe = mean(Fe, na.rm = TRUE)) %>% spread(key = Stage, value = Fe) dataB # A tibble: 12 × 7 # Groups: Location, Season, Genotype, Iron_ton_ha [12] Location Season Genotype Iron_ton_ha Maturity Reproductive Vegetative <chr> <dbl> <chr> <dbl> <dbl> <dbl> <dbl> 1 East 2021 CV1 21.7 NA NA 0.37 2 East 2021 CV1 30.8 NA 0.45 NA 3 East 2022 CV2 14.1 NA 0.32 NA 4 East 2022 CV2 16.9 NA NA 0.483 5 North 2021 CV1 5.86 NA 0.107 NA 6 North 2021 CV1 8.01 0.22 NA NA 7 North 2022 CV2 6.03 0.0833 NA NA 8 North 2022 CV2 6.19 NA 0.107 NA 9 West 2021 CV1 13.2 0.327 NA NA 10 West 2021 CV1 15.0 NA NA 0.357 11 West 2022 CV2 9.66 NA NA 0.263 12 West 2022 CV2 11.1 0.227 NA NA
问题原因及解决方案
原因分析
核心问题出在group_by的参数里——你把Stage也加入了分组条件。这会导致每个分组只对应单个Stage值,后续用spread转置时,每个分组自然只有当前Stage的列有计算结果,其他Stage列只能填充NA。
比如East-2021-CV1-21.7-Vegetative这个分组只计算了Vegetative阶段的Fe均值,转置后Maturity和Reproductive列没有对应数据,只能显示NA。
正确代码
方法1:用pivot_wider(tidyverse推荐替代spread的函数)
先按除Stage外的维度分组统计,再转置:
library(tidyverse) dataB <- dataA %>% group_by(Location, Season, Genotype, Iron_ton_ha, Stage) %>% summarise(Fe = mean(Fe, na.rm = TRUE), .groups = "drop") %>% # 取消分组避免后续问题 pivot_wider(names_from = Stage, values_from = Fe)
方法2:修正spread的用法
如果坚持用spread,必须先取消分组,否则spread会在每个子分组内单独转置,依然会出现NA:
library(dplyr) library(tidyr) dataB <- dataA %>% group_by(Location, Season, Genotype, Iron_ton_ha, Stage) %>% summarise(Fe = mean(Fe, na.rm = TRUE)) %>% ungroup() %>% # 关键步骤:取消分组 spread(key = Stage, value = Fe)
结果说明
修正后,每个Location, Season, Genotype, Iron_ton_ha组合对应一行数据,三个Stage列(Maturity、Reproductive、Vegetative)都会显示对应阶段的Fe均值,不会再出现大量NA。
内容的提问来源于stack exchange,提问作者J.K Kim
相关产品推荐
相关产品推荐

