如何从数据框每行反向提取首个非NA的收入值?
解决方法:从每行反向选取首个非NA值生成新列
针对你的需求,这里提供几种常用的R语言实现方式:
方法一:R基包原生操作
无需额外安装包,直接用基包函数实现:
# 定义原始数据框 wave <- data.frame(ID=c(1, 2, 3, 4, 5, 6), income_wave_1_2017=c(109, 106, NA, 10, 65, NA), income_wave_2_2018=c(NA, 108, 66, NA, NA, 190), income_wave_3_2019=c(19, NA, NA, NA, NA, NA)) # 提取所有收入相关列 income_cols <- wave[, grep("^income_wave", colnames(wave))] # 逐行反转列顺序,取第一个非NA值生成新列 wave$newest_income_ <- apply(income_cols, 1, function(x) { rev_x <- rev(x) rev_x[!is.na(rev_x)][1] }) # 保留需要的列 wave <- wave[, c("ID", "newest_income_")]
方法二:tidyverse工具包(简洁高效)
推荐使用dplyr+tidyr组合,代码可读性更强:
library(tidyverse) # 定义原始数据框 wave <- data.frame(ID=c(1, 2, 3, 4, 5, 6), income_wave_1_2017=c(109, 106, NA, 10, 65, NA), income_wave_2_2018=c(NA, 108, 66, NA, NA, 190), income_wave_3_2019=c(19, NA, NA, NA, NA, NA)) wave <- wave %>% rowwise() %>% # 提取所有收入列,去掉NA后取最后一个值(即最晚的非NA数据) mutate(newest_income_ = last(na.omit(c_across(starts_with("income_wave"))))) %>% ungroup() %>% select(ID, newest_income_)
注:这里利用收入列按年份从早到晚排列的特性,na.omit后取last等价于从后往前找首个非NA值。
方法三:data.table包(大数据量首选)
如果你的数据量较大,data.table的运行效率会显著高于基包和tidyverse:
library(data.table) # 定义原始数据框并转为data.table格式 wave <- data.frame(ID=c(1, 2, 3, 4, 5, 6), income_wave_1_2017=c(109, 106, NA, 10, 65, NA), income_wave_2_2018=c(NA, 108, 66, NA, NA, 190), income_wave_3_2019=c(19, NA, NA, NA, NA, NA)) setDT(wave) # 指定收入列,逐行处理生成新列 income_cols <- grep("^income_wave", colnames(wave), value = TRUE) wave[, newest_income_ := apply(.SD, 1, function(x) rev(x)[!is.na(rev(x))][1]), .SDcols = income_cols] # 保留需要的列 wave <- wave[, .(ID, newest_income_)]
内容的提问来源于stack exchange,提问作者Max Herre
相关产品推荐
相关产品推荐

