如何计算面板数据中初始记录后的样本缺失(Dropout)数量?
面板数据中计算样本首次记录后的缺失案例数(样本流失检测)
需要在data.table格式的面板数据中,统计每个id在**首次出现有效记录(非NA)**之后的缺失案例数量,以此检测样本流失情况。以下是示例数据、期望输出及错误尝试代码,提供正确实现方案。
示例数据
library(data.table) library(tibble) dt <- tibble( `id` = c("id1", "id2","id3"), `2018` = c(NA,NA,"id3"), `2019` = c(NA,"id2","id3"), `2020` = c(NA, "id2",NA), `2021` = c("id1", NA,"id3"), `2022` = c("id1", NA,"id3"), `2023` = c(NA, "id2","id3") ) %>% as.data.table() dt
输出:
id 2018 2019 2020 2021 2022 2023 <char> <char> <char> <char> <char> <char> <char> 1: id1 <NA> <NA> <NA> id1 id1 <NA> ---> 首次记录2021 2: id2 <NA> id2 id2 <NA> <NA> id2 ---> 首次记录2019 3: id3 id3 id3 <NA> id3 id3 id3 ---> 首次记录2018
期望输出
需要生成每个年份是否为首次记录后的缺失(1表示缺失,0表示有效),并统计总缺失数n_dropOut:
output <- tibble( `id` = c("id1", "id2","id3"), `2018` = c(0,0,0), `2019` = c(0,0,0), `2020` = c(0, 0,1), `2021` = c(0, 1,0), `2022` = c(0, 1,0), `2023` = c(1, 0,0), n_dropOut = c(1,2,1) ) %>% as.data.table() output
输出:
id 2018 2019 2020 2021 2022 2023 n_dropOut <char> <num> <num> <num> <num> <num> <num> <num> 1: id1 0 0 0 0 0 1 1 2: id2 0 0 0 1 1 0 2 3: id3 0 0 1 0 0 0 1
错误尝试代码
直接对所有年份的缺失值求和,会把首次记录前的缺失也计入,结果不符合需求:
dt[, n_dropOut := `2018` + `2019` + `2020` + `2021` + `2022` + `2023`, by = "id"] dt
错误输出:
id 2018 2019 2020 2021 2022 2023 n_dropOut <char> <num> <num> <num> <num> <num> <num> <num> 1: id1 1 1 1 0 0 1 4 2: id2 1 0 0 1 1 0 3 3: id3 0 0 1 0 0 0 1
正确实现方案
核心思路:先确定每个id的首次有效记录年份,再只统计该年份之后的缺失值。用data.table的长格式转换+分组处理更高效:
# 1. 将宽格式转为长格式,保留id、年份、值 dt_long <- melt(dt, id.vars = "id", variable.name = "year", value.name = "value") # 2. 按id分组,计算每个id的首次有效记录年份 dt_long[, first_year := min(year[!is.na(value)]), by = id] # 3. 标记:首次年份之后且值为NA的记为1,其余为0 dt_long[, drop_flag := as.integer(year > first_year & is.na(value))] # 4. 转回宽格式,并计算总流失数 result <- dcast(dt_long, id ~ year, value.var = "drop_flag") result[, n_dropOut := rowSums(.SD), .SDcols = paste0("20", 18:23)] # 查看结果 result
输出:
id 2018 2019 2020 2021 2022 2023 n_dropOut <char><int><int><int><int><int><int> <int> 1: id1 0 0 0 0 0 1 1 2: id2 0 0 0 1 1 0 2 3: id3 0 0 1 0 0 0 1
代码解释
melt:将宽表转长表,方便按年份逐个处理每个id的记录first_year := min(year[!is.na(value)]):筛选每个id的非NA记录,取最小的年份作为首次有效记录年份drop_flag:判断当前年份是否在首次年份之后,且值为NA,满足则标记为1dcast:将长表转回宽表,恢复原年份列的结构rowSums(.SD):对每个id的所有年份drop_flag求和,得到总流失数
内容的提问来源于stack exchange,提问作者cdcarrion
相关产品推荐
相关产品推荐

