按组条件替换数据框中NA值的R语言实现问题求助
按组条件替换数据框中NA值的R语言实现问题求助
问题描述
我手头有这么一个R数据框:
dataset2_long <- read.table(text=" IDM time_point smoking_status 1 smoking6m 0 1 smoking5y NA 1 smoking9y 0 1 smoking13y 0 2 smoking6m 0 2 smoking5y 2 2 smoking9y 0 2 smoking13y NA 3 smoking6m 1 3 smoking5y 2 3 smoking9y 0 3 smoking13y NA", header=TRUE)
我的需求很明确:只在某个IDM分组里,所有非NA的smoking_status值都是0的情况下,把这个组里的NA替换成0。但我自己写的ifelse代码出问题了——它把IDM=2和IDM=3分组里的NA也改成了0,完全不符合我想要的结果。
我期望的输出应该是这样的:
IDM time_point smoking_status 1 smoking6m 0 1 smoking5y 0 1 smoking9y 0 1 smoking13y 0 2 smoking6m 0 2 smoking5y 2 2 smoking9y 0 2 smoking13y NA 3 smoking6m 1 3 smoking5y 2 3 smoking9y 0 3 smoking13y NA
我尝试的代码是这样的:
dataset2_long <- dataset2_long %>% group_by(IDM) %>% mutate(smoking_status = ifelse(all(is.na(smoking_status) | smoking_status == 0), replace(smoking_status, is.na(smoking_status), 0), smoking_status))
问题原因与解决办法
你之前的代码之所以失效,是因为ifelse是逐元素进行判断的,但我们的判断条件是整个分组的属性(这个组是不是只有0和NA),直接用ifelse会把分组级别的判断逻辑套用到每个元素上,自然会出错。
这里给你两种靠谱的解决思路,都能精准实现你的需求:
方法一:用case_when配合分组标记
先给每个分组打个标记,判断它是否符合“只有0和NA”的条件,再根据标记替换NA:
library(dplyr) dataset2_long <- dataset2_long %>% group_by(IDM) %>% mutate( # 临时标记当前分组是否符合条件 is_only_0_na = all(smoking_status %in% c(0, NA)), # 只对符合条件的分组里的NA替换为0 smoking_status = case_when( is_only_0_na & is.na(smoking_status) ~ 0, TRUE ~ smoking_status ) ) %>% # 删掉临时标记列 select(-is_only_0_na) %>% ungroup()
方法二:直接用if做分组级判断
既然是分组级别的条件,直接用if语句判断整个分组的属性,再决定是否替换:
library(dplyr) dataset2_long <- dataset2_long %>% group_by(IDM) %>% mutate( smoking_status = if (all(smoking_status %in% c(0, NA))) { replace(smoking_status, is.na(smoking_status), 0) } else { smoking_status } ) %>% ungroup()
这两种方法都只会处理IDM=1这个符合条件的分组,其他分组的NA会保持原样,完全符合你的预期输出。
备注:内容来源于stack exchange,提问作者Komal Mehta
相关产品推荐
相关产品推荐

