R语言:基于用户分组为type='old'的行填充缺失score值
实现分组填充缺失值的R方案
刚好最近经常处理这类分组填充的需求,给你两种常用的实现方式,都能完美匹配你的需求:
方法一:使用tidyverse的dplyr包(推荐,代码可读性高)
首先我们先确认原始数据,然后通过分组判断+条件填充来实现:
# 加载dplyr包(如果没安装先运行 install.packages("dplyr")) library(dplyr) # 定义原始数据集 user <- c(1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3) score <- c(3, 3, 3, NA, 0, 0, 0, NA, NA, NA, NA, NA) type <- c('new', 'recent', 'recent', 'old', 'recent', 'new', 'new', 'old', 'new', 'new', 'new', 'recent') df <- data.frame(user, score, type) # 执行填充逻辑 df_filled <- df %>% group_by(user) %>% # 按用户分组 mutate( # 提取当前组的第一个非缺失score值(因为用户1/2的非缺失score都是统一值,取第一个即可) group_valid_score = first(score[!is.na(score)]), # 条件填充:仅当type为'old'且score缺失,同时组内有有效值时,替换为组内有效值 score = ifelse(type == 'old' & is.na(score) & !is.na(group_valid_score), group_valid_score, score) ) %>% select(-group_valid_score) %>% # 移除临时辅助列 ungroup() # 取消分组 # 查看最终结果 print(df_filled)
逻辑说明:
group_by(user)把数据按用户拆分成独立的组;group_valid_score提取每组里的有效score值(排除NA),因为用户1的有效score都是3,用户2都是0,所以取第一个非NA值就足够;ifelse精准判断填充条件:只有满足「type是old」「当前score是NA」「组内存在有效值」这三个条件时,才用组内有效值替换NA,其他情况保留原score;- 最后清理临时列并取消分组,得到目标数据集。
方法二:使用Base R(无需额外安装包)
如果你不想加载第三方包,用base R的ave函数也能实现:
# 定义原始数据集(和上面一致) user <- c(1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3) score <- c(3, 3, 3, NA, 0, 0, 0, NA, NA, NA, NA, NA) type <- c('new', 'recent', 'recent', 'old', 'recent', 'new', 'new', 'old', 'new', 'new', 'new', 'recent') df <- data.frame(user, score, type) # 直接在原数据上修改score列 df$score <- with(df, ave(score, user, FUN = function(x) { # 提取当前组的非缺失score值 valid_scores <- x[!is.na(x)] # 如果组内有有效值,就替换type为'old'的NA;否则保留原数据 if (length(valid_scores) > 0) { replace(x, type == 'old' & is.na(x), valid_scores[1]) } else { x } })) # 查看结果 print(df)
逻辑说明:
ave函数会按user分组处理score列,每组内先检查是否存在有效score值:
- 如果有,就用
replace函数定位到「type是old且score是NA」的行,替换为组内第一个有效值; - 如果没有(比如用户3),就直接返回原score列,保持所有NA不变。
两种方法运行后,都能得到你想要的目标数据集:用户1和2的type='old'行的NA会被填充为各自组的有效score,用户3的所有NA保持原样。
内容的提问来源于stack exchange,提问作者juanjedi
相关产品推荐
相关产品推荐

