R语言中为DF1添加对应ID的DF2 Amount列NA计数失败求助
问题描述
我有两个数据框DF1和DF2:DF2是考勤记录系统,包含IDs、Dates和Amounts列;DF1包含IDs及其他不重叠列。当员工缺勤时,DF2中会记录ID和日期,但Amount标记为R语言的NA值。我想在DF1中新增一列,统计每个ID在DF2的Amount列中对应的NA值数量。使用的代码如下:
df1$na_count <- sum(df2$id == df1$id & is.na(df2$amount))
原本以为这段代码能通过匹配DF2与DF1的ID、判断Amount是否为NA生成布尔数组,求和得到计数,但结果始终为0,求排查问题。
问题原因
- 向量长度不匹配的循环补齐问题:R中当执行
df2$id == df1$id时,如果两个数据框行数不同,R会自动循环补齐较短的向量。比如DF1有10行、DF2有100行,df1$id会被重复10次去匹配DF2的100行,导致匹配逻辑完全混乱,根本无法按每个ID单独统计。 - sum函数的作用范围错误:直接调用
sum()会对整个布尔向量求和,得到一个单一值,再循环补齐到DF1的每一行,而非按DF1的每个ID分别计算对应NA数量,结果自然不符合预期。
解决方法
以下是几种常用的正确实现方式:
方法1:dplyr包(tidyverse风格)
这是最直观的tidyverse处理方式,先分组统计再关联:
library(dplyr) df1 <- df2 %>% group_by(IDs) %>% summarise(na_count = sum(is.na(Amounts))) %>% right_join(df1, by = "IDs") %>% mutate(na_count = replace_na(na_count, 0)) # 对DF1存在但DF2无记录的ID,将NA转为0
方法2:base R的ave函数
用base R原生函数实现分组统计,再匹配到DF1:
# 在DF2中按ID分组统计NA数量 na_counts <- with(df2, ave(is.na(Amounts), IDs, FUN = sum)) # 去重得到ID与计数的映射表 id_na_map <- unique(data.frame(IDs = df2$IDs, na_count = na_counts)) # 匹配映射表到DF1 df1$na_count <- id_na_map$na_count[match(df1$IDs, id_na_map$IDs)] # 匹配不到的ID(DF1有但DF2无记录)设为0 df1$na_count[is.na(df1$na_count)] <- 0
方法3:base R的table函数
通过统计NA行的ID频次来实现:
# 筛选DF2中Amount为NA的行,统计每个ID的出现次数 na_table <- table(df2$IDs[is.na(df2$Amounts)]) # 匹配到DF1,无记录的ID填0 df1$na_count <- as.integer(na_table[as.character(df1$IDs)]) df1$na_count[is.na(df1$na_count)] <- 0
内容的提问来源于stack exchange,提问作者x0nar
相关产品推荐
相关产品推荐

