You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何计算面板数据中初始记录后的样本缺失(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,满足则标记为1
  • dcast:将长表转回宽表,恢复原年份列的结构
  • rowSums(.SD):对每个id的所有年份drop_flag求和,得到总流失数

内容的提问来源于stack exchange,提问作者cdcarrion

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 08:30:56