如何统计数据框每行首个数值前的NA个数并添加为新列?
问题:统计每行首个非NA值前的NA个数并添加为新列
虚拟数据集
df <- data.frame( K=c(NA, NA, 3, 4,0,2,NA, NA), A=c(NA, NA, NA, 4,0,3,NA, NA), B=c(NA, 2, NA, NA,0,NA,NA,0), C=c(0, 3, 5, NA,0,5,NA,5), D=c(NA, 3, 1, 2,0,10,NA,3) )
输出:
K A B C D 1 NA NA NA 0 NA 2 NA NA 2 3 3 3 3 NA NA 5 1 4 4 4 NA NA 2 5 0 0 0 0 0 6 2 3 NA 5 10 7 NA NA NA NA NA 8 NA NA 0 5 3
需求说明
需要为每行统计首个非NA值出现前的NA个数,并将结果作为nn列添加到数据框末尾:
- 若行首就是非NA值,结果为0
- 全NA行标记为1000
- 最终期望结果:
df2 <- data.frame( K=c(NA, NA, 3, 4,0,2,NA, NA), A=c(NA, NA, NA, 4,0,3,NA, NA), B=c(NA, 2, NA, NA,0,NA,NA,0), C=c(0, 3, 5, NA,0,5,NA,5), D=c(NA, 3, 1, 2,0,10,NA,3), nn=c(3,2,0,0,0,0,1000,2) )
输出:
K A B C D nn 1 NA NA NA 0 NA 3 2 NA NA 2 3 3 2 3 3 NA NA 5 1 0 4 4 4 NA NA 2 0 5 0 0 0 0 0 0 6 2 3 NA 5 10 0 7 NA NA NA NA NA 1000 8 NA NA 0 5 3 2
现有代码问题
原代码:
DD<-apply(df,1,function(x) which(!is.na(x))) unlist(map(DD, 1) , use.names=FALSE)-1
输出缺失了全NA的行:3 2 0 0 0 0 2,原因是全NA行的which(!is.na(x))返回空向量,map(DD,1)会自动忽略空元素,导致结果行数不匹配。
解决方案
1. Base R 高效向量化方案(适合大数据集)
利用向量化操作替代逐行循环,效率更高,适配20万行+500列的数据集:
# 生成每行首个非NA值的列索引 first_non_na_pos <- max.col(!is.na(df), ties.method = "first") # 判断全NA行,赋值nn列 df$nn <- ifelse(rowSums(!is.na(df)) == 0, 1000, first_non_na_pos - 1)
2. dplyr 高效向量化方案
无需rowwise,同样用向量化操作保证效率:
library(dplyr) df <- df %>% mutate( # 找到每行首个非NA的列索引 first_non_na_pos = max.col(!is.na(cur_data()), ties.method = "first"), # 计算nn值,全NA行设为1000 nn = ifelse(rowSums(!is.na(cur_data())) == 0, 1000, first_non_na_pos - 1) ) %>% select(-first_non_na_pos) # 可选:删除中间临时列
3. 兼容所有情况的逐行处理方案(适合小数据集)
如果需要更直观的逐行逻辑,可保留apply但处理全NA情况:
df$nn <- apply(df, 1, function(x) { first_idx <- which(!is.na(x))[1] if (is.na(first_idx)) 1000 else first_idx - 1 })
以上方案均可得到符合要求的结果,其中前两种向量化方案在大数据集上的运行效率远高于逐行循环。
内容的提问来源于stack exchange,提问作者newfinder
相关产品推荐
相关产品推荐

