在R中按州子集均值替换DataFrame中的NA值
问题描述
原始数据
head(df) #> county state_abr population unemp health_ins poverty SNAP no_comp no_internet home_broad broad_num broad_avail broad_cost price_bbn #> 1 Autauga AL 55869 2.7 7.1 15.4 12.7 NA 20.9 78.9 0 0.0 67.32586 35.00 #> 2 Baldwin AL 223234 2.7 10.2 10.6 7.5 NA 21.3 78.1 0 0.0 67.32586 35.00 #> 3 Barbour AL 24686 3.8 11.2 28.9 27.4 NA 38.9 60.4 4 99.2 74.99000 35.00 #> 4 Bibb AL 22394 3.1 7.9 14.0 12.4 23.7 33.8 66.1 0 0.0 67.32586 35.00 #> 5 Blount AL 57826 2.7 11.0 NA 9.5 21.3 NA 68.5 0 0.0 67.32586 35.00 #> 6 Bullock AL 10101 3.6 10.8 31.4 25.9 27.1 40.1 58.9 1 40.1 57.99000 71.95 tail(df) #> county state_abr population unemp health_ins poverty SNAP no_comp no_internet home_broad broad_num broad_avail broad_cost price_bbn #> 1 Sublette WY 9831 4.4 13.4 8.4 2.2 5.4 17.5 81.7 3 19.5 59.65 35.00 #> 2 Sweetwater WY 42343 3.9 12.0 12.0 5.8 7.7 16.1 82.4 5 95.1 63.30 35.00 #> 3 Teton WY 23464 2.7 10.0 7.1 2.1 4.2 13.6 85.9 6 96.0 69.99 35.00 #> 4 Uinta WY 20226 3.9 12.2 12.5 7.1 6.1 11.5 88.2 5 73.9 63.30 35.00 #> 5 Washakie WY 7805 3.9 15.4 12.4 4.9 12.1 21.5 78.3 5 86.1 64.36 35.00 #> 6 Weston WY 6927 2.9 13.3 17.4 4.7 13.8 26.1 73.3 2 52.0 66.67 35.00
需求
需要按state_abr(州缩写)分组,计算每个州内各数值列的均值,并用该均值填充对应州内该列的NA值,而非使用整列的全局均值。例如AL州no_comp列的NA,仅用AL州该列的均值填充。
解决方案
方法1:使用dplyr包(tidyverse生态)
这是最常用的tidy风格写法,代码简洁易读:
library(dplyr) df_filled <- df %>% group_by(state_abr) %>% mutate(across(where(is.numeric), ~ifelse(is.na(.), mean(., na.rm = TRUE), .))) %>% ungroup()
代码说明:
group_by(state_abr):按州分组across(where(is.numeric), ...):对所有数值列应用后续操作ifelse(is.na(.), mean(., na.rm = TRUE), .):如果当前值是NA,用该组该列的均值(忽略NA)替换,否则保留原值ungroup():取消分组,回到普通数据框
方法2:使用data.table包(适合大数据)
如果数据量很大,data.table的效率更高:
library(data.table) setDT(df) df_filled <- df[, lapply(.SD, function(x) ifelse(is.na(x), mean(x, na.rm = TRUE), x)), by = state_abr]
代码说明:
setDT(df):将普通数据框转为data.table格式by = state_abr:按州分组lapply(.SD, ...):对每个分组内的所有列(.SD表示Subset of Data)应用函数- 函数逻辑和dplyr一致:NA值替换为组内列均值
方法3:基础R实现(无需额外包)
如果不想加载第三方包,可以用基础R的拆分-处理-合并流程:
# 按州拆分数据框 state_groups <- split(df, df$state_abr) # 对每个分组处理NA值 state_groups_filled <- lapply(state_groups, function(group) { # 遍历每个数值列 for(col in names(group)[sapply(group, is.numeric)]) { col_mean <- mean(group[[col]], na.rm = TRUE) group[[col]][is.na(group[[col]])] <- col_mean } return(group) }) # 合并回一个数据框 df_filled <- do.call(rbind, state_groups_filled) # 重置行名 rownames(df_filled) <- NULL
代码说明:
split(df, df$state_abr):把数据框按州拆分成列表,每个元素是一个州的数据lapply遍历每个州的数据,对数值列计算均值并替换NAdo.call(rbind, ...):把处理后的分组数据合并回一个数据框
验证结果
可以用以下代码查看处理后的结果,确认NA已被对应州的均值填充:
# 查看AL州原NA较多的列 df_filled %>% filter(state_abr == "AL") %>% select(county, poverty, no_comp, no_internet)
内容的提问来源于stack exchange,提问作者Jean-Paul Azzopardi
相关产品推荐
相关产品推荐

