R语言:如何仅将死亡年份对应的身高体重值设为NA?
问题与解决方案
问题背景
数据集
my_data = data.frame(id = c(1,2,3), status_2017 = c("alive", "alive", "alive"), status_2018 = c("alive", "dead", "alive"), status_2019 = c("alive", "dead", "dead"), height_2017 = rnorm(3,3,3), height_2018 = rnorm(3,3,3), height_2019 = rnorm(3,3,3) , weight_2017 = rnorm(3,3,3), weight_2018 = rnorm(3,3,3), weight_2019 = rnorm(3,3,3))
示例输出:
id status_2017 status_2018 status_2019 height_2017 height_2018 height_2019 weight_2017 weight_2018 weight_2019 1 1 alive alive alive 6.505447 7.328302 4.14945261 2.4715195 7.140026 1.843526 2 2 alive dead dead -2.033761 3.553849 0.09896499 0.4159123 4.340485 1.366350 3 3 alive alive dead 3.107110 2.967456 6.52980219 1.6573734 3.397389 3.116294
需求
若某ID在某年份状态为dead,则将该年份对应的height和weight值替换为NA。
尝试的错误方法
dead_rows <- my_data$status_2018 == "dead" | my_data$status_2019 == "dead" my_data[dead_rows, c("height_2018", "height_2019", "weight_2018", "weight_2019")] <- NA
问题:ID=3在2018年状态为alive,但该年份的身高体重却被设为NA,不符合需求。需要修正该问题,同时希望有无需手动列所有列名的简洁实现方式。
解决方案
一、修正原始索引方法
问题核心是错误地将整行标记为dead后批量替换所有年份列,正确做法是按年份单独匹配:只有对应年份的status为dead时,才替换该年份的指标列。
# 处理2018年:status_2018为dead的行,替换height_2018和weight_2018为NA my_data[my_data$status_2018 == "dead", c("height_2018", "weight_2018")] <- NA # 处理2019年:status_2019为dead的行,替换height_2019和weight_2019为NA my_data[my_data$status_2019 == "dead", c("height_2019", "weight_2019")] <- NA
此方法精准匹配年份,ID=3的2018年数据会保留,仅2019年指标被设为NA。
二、Base R批量实现(无需手动列名)
针对年份较多的场景,可通过提取列名中的年份后缀自动匹配列:
# 提取所有年份后缀(从带年份的列名中解析) years <- unique(sub(".*_(\\d{4})", "\\1", colnames(my_data)[grepl("_\\d{4}", colnames(my_data))])) # 遍历每个年份,自动匹配status列和对应指标列 for (year in years) { status_col <- paste0("status_", year) metric_cols <- paste0(c("height_", "weight_"), year) my_data[my_data[[status_col]] == "dead", metric_cols] <- NA }
此方法无需手动输入列名,可自动适配新增的年份列。
三、tidyverse简洁实现
通过长格式转换,逻辑更直观,适合复杂数据处理:
library(tidyverse) my_data_clean <- my_data %>% # 转为长格式:将年份作为单独列,指标类型(status/height/weight)保留为列名 pivot_longer(cols = -id, names_to = c(".value", "year"), names_sep = "_") %>% # 当status为dead时,将height和weight设为NA mutate(across(c(height, weight), ~ifelse(status == "dead", NA, .))) %>% # 转回宽格式,恢复原数据结构 pivot_wider(names_from = year, values_from = c(status, height, weight))
处理后的数据严格按年份匹配status,自动完成NA替换,无需手动指定列名。
内容的提问来源于stack exchange,提问作者stats_noob
相关产品推荐
相关产品推荐

