纵向数据按id和gen分组计算time2-time1的缺失时间点处理咨询
问题描述
我有一份纵向数据库,变量说明:
- id:个体标识
- grup_int:分组分类变量
- gen:待测量变量
- time:测量时间点
- value:测量值
数据示例:
id grup_int gen time value <dbl> <dbl> <chr> <chr> <dbl> 1 60801001 1 adrb2 2 2.11 2 60801001 1 ccl2 1 0.941 3 60801001 1 ccl2 2 0.248 4 60801001 1 ccl3 1 5.65 5 60801001 1 ccl3 2 NA
尝试用以下代码计算time=2与time=1的value差值:
df %>% dplyr::group_by(id, gen) %>% dplyr::mutate(d_post_pre = value [time == 2] - value [time == 1])
运行后报错:
`d_post_pre` must be size 1, not 0. ℹ The error occurred in group 1: id = 60801001, gen = "adrb2".
报错原因是部分组(如adrb2)缺少time=1的条目;另外存在time点齐全但value为NA的情况(如ccl3),这种情况无需特殊处理,保留NA即可。需要修改代码规避报错,缺失必要时间点时返回NA或特定值方便后续过滤。
附数据结构:
df <- structure(list(id = structure(c(60801001, 60801001, 60801001, 60801001, 60801001), label = "Identificador", format.spss = "F9.0", display_width = 14L), grup_int = structure(c(1, 1, 1, 1, 1), format.spss = "F2.0"), gen = c("adrb2", "ccl2", "ccl2", "ccl3", "ccl3"), time = c("2", "1", "2", "1", "2"), value = c(2.1098254, 0.94088, 0.24778089, 5.6529145, 0.06939283)), class = c("tbl_df", "tbl", "data.frame" ), row.names = c(NA, -5L))
解决方案
方法1:用first()提取对应时间点的value
通过first()提取指定time的value,当某个time不存在时会返回NA,差值计算自然得到NA,不会触发报错:
df %>% dplyr::group_by(id, gen) %>% dplyr::mutate( d_post_pre = first(value[time == "2"]) - first(value[time == "1"]) ) %>% dplyr::ungroup()
方法2:转宽格式计算差值(更直观)
先将长格式数据转为宽格式,让time=1和time=2的value各占一列,计算差值后可按需转回长格式:
# 转宽格式并计算差值 df_wide <- df %>% dplyr::pivot_wider( id_cols = c(id, grup_int, gen), names_from = time, values_from = value, names_prefix = "time_" ) %>% dplyr::mutate(d_post_pre = time_2 - time_1) # 如需转回长格式 df_long <- df_wide %>% dplyr::pivot_longer( cols = starts_with("time_"), names_to = "time", values_to = "value", names_prefix = "time_" ) %>% dplyr::select(id, grup_int, gen, time, value, d_post_pre)
方法3:先汇总差值再关联回原数据
如果只需要每个(id, gen)组的差值,先汇总生成差值表,再左连接到原数据:
diff_df <- df %>% dplyr::group_by(id, gen) %>% dplyr::summarise( d_post_pre = first(value[time == "2"]) - first(value[time == "1"]), .groups = "drop" ) df %>% dplyr::left_join(diff_df, by = c("id", "gen"))
以上方法都会在缺少time=1或time=2时返回NA,value本身的NA会保留在差值结果中,符合需求。
内容的提问来源于stack exchange,提问作者Javier Hernando
相关产品推荐
相关产品推荐

