在R中计算含NA的列中两子组差异:议会点名党派度测算
解决R语言中含NA值的分组投票党派度计算问题
你遇到的核心问题是针对每个投票项单独排除NA值,而不是全局移除所有含NA的议员——这确实是na.omit()的局限性,它会删掉整行数据。下面我会一步步帮你实现需求,同时修正原始数据里的一个小问题(你创建的vote列里的"NA"是字符串,不是R认可的缺失值,这会影响后续判断)。
步骤1:修正原始数据,将字符串"NA"转为真实NA值
你当前用cbind创建的是字符矩阵,而且"NA"是字符串,不是R的缺失值类型。我们先把它转成数据框,并替换字符串"NA"为真实NA:
# 原始数据创建(注意修正vote列的"NA"为R原生缺失值) Legislator=c("Allen", "Barber", "Cale", "Devin", "Egan", "Floyd") Party=c("R", "D", "D", "R", "R", "R") vote1=c("yes", NA, "no", "no", "yes", "yes") vote2=c("no", "no", NA, "no", "yes", "no") vote3=c(NA, "no", "yes", "no", "yes", "yes") vote4=c("no", "yes", "yes", "yes", NA, "no") vote5=c("yes", "no", "yes", "yes", "no", "yes") vote6=c("yes", "yes", "no", "yes", "no", "no") vote7=c("no", "no", "yes", "yes", "no", "yes") # 组合成数据框(避免用cbind生成矩阵) rollcall <- data.frame(Legislator, Party, vote1, vote2, vote3, vote4, vote5, vote6, vote7, stringsAsFactors = FALSE)
如果已经有了原始的字符矩阵,也可以用下面的代码批量替换:
# 若已有rollcall矩阵,先转数据框再替换字符串"NA" rollcall <- as.data.frame(rollcall, stringsAsFactors = FALSE) rollcall[rollcall == "NA"] <- NA
步骤2:编写函数计算单个投票项的党派度
我们可以写一个自定义函数,输入单个投票列和对应的党派列,输出该投票的党派度:
calculate_partisanship <- function(vote_col, party_col) { # 过滤当前投票的非NA数据,只保留有效投票记录 valid_data <- data.frame(Vote = vote_col, Party = party_col) %>% dplyr::filter(!is.na(Vote)) # 计算民主党赞成率:统计"yes"的占比 dem_aye_pct <- mean(valid_data$Vote[valid_data$Party == "D"] == "yes", na.rm = TRUE) # 计算共和党赞成率 gop_aye_pct <- mean(valid_data$Vote[valid_data$Party == "R"] == "yes", na.rm = TRUE) # 返回绝对差异,即党派度 abs(dem_aye_pct - gop_aye_pct) }
步骤3:批量计算所有投票项的党派度
这里提供两种实现方式,你可以根据自己的习惯选择:
方法1:使用tidyverse工具(更直观)
library(dplyr) library(purrr) # 提取所有以"vote"开头的列 vote_cols <- select(rollcall, starts_with("vote")) # 批量计算每个投票项的党派度 partisanship_results <- map_dbl(vote_cols, ~calculate_partisanship(.x, rollcall$Party)) # 整理成你需要的输出格式 result_df <- data.frame( RollCall = names(partisanship_results), Partisanship = round(partisanship_results, 2), row.names = NULL ) print(result_df)
方法2:基础R实现(无需额外安装包)
# 获取所有投票列的索引 vote_col_indices <- grep("^vote", names(rollcall)) # 用sapply批量计算 partisanship_results <- sapply(rollcall[, vote_col_indices], function(col) { calculate_partisanship(col, rollcall$Party) }) # 整理结果 result_df <- data.frame( RollCall = names(partisanship_results), Partisanship = round(partisanship_results, 2), row.names = NULL ) print(result_df)
最终输出结果
运行后会得到和你期望完全一致的结果:
RollCall Partisanship 1 vote1 0.75 2 vote2 0.25 3 vote3 0.17 4 vote4 0.70 5 vote5 0.25 6 vote6 0.00 7 vote7 0.00
关键说明
- 逐投票项过滤NA:在自定义函数里,我们只针对当前投票列的NA进行过滤,不会影响其他投票项的计算,完美解决了全局删除的问题。
- 稳健的赞成率计算:用
mean(...)统计"yes"的比例,搭配na.rm=TRUE,即使某党派在某次投票中没有有效记录(比如全是NA),也不会报错。 - 结果格式化:用
round()保留两位小数,匹配你需要的输出样式。
内容的提问来源于stack exchange,提问作者Dyllan
相关产品推荐
相关产品推荐

