如何用dplyr处理家庭面板数据,生成grandparent与became_grandparent变量?
祖父母身份标记与首次成为祖父母年份计算
问题背景
样本数据
id <- c(10020,10020,10020,10020,10020,10020,10020,10020,10021,10021,10021,10021, 10021,10021,10022,10022,10022,20020,20020,20020,20020,20020,20020,20021, 20021,20021) family_id<- c(1002,1002,1002,1002,1002, 1002, 1002, 1002, 1002, 1002, 1002, 1002, 1002, 1002, 1002, 1002, 1002, 2002, 2002, 2002, 2002, 2002, 2002, 2002, 2002, 2002 ) child_id<- c(NA, NA, NA, NA, NA, NA, NA, NA, 1, 1, 1, 1, 1, 2, 2, 2, 2, NA, NA, NA, NA, NA, NA, 1, 1, 1 ) year<- c(2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2002, 2003, 2004, 2005, 2006, 2004, 2005, 2006, 2007, 2002, 2003, 2004, 2005, 2006, 2007, 2004, 2005, 2006 ) number_of_children<- c(2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 2, 2, 2, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0 ) child1_birthyear<- c(1980, 1980, 1980, 1980, 1980, 1980, 1980, 1980, 2001, 2001, 2001, 2001, 2001, NA, NA, NA, NA, 1990, 1990, 1990, 1990, 1990, 1990, NA, NA, NA ) child2_birthyear<- c(1984, 1984, 1984, 1984, 1984, 1984, 1984, 1984, 2004, 2004, 2004, 2004, 2004, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA ) sample<- data.frame(id,family_id,child_id,year,number_of_children, child1_birthyear,child2_birthyear)
数据规则
- id最后一位为0代表父母数据,大于0代表子女数据;
- 以家庭ID1002为例:10020是父母数据,10021、10022分别为1980年、1984年出生的子女;父母的子女10021在2006年有2个孩子(出生于2001年、2004年),10022无子女。
需求
生成两个变量:
grandparent:标识变量,父母为祖父母时取值1,否则0;became_grandparent:父母成为祖父母的年份,即其子女首次生育的最早年份(孙辈最早出生年份)。
尝试的代码(未得到正确结果)
sample<-sample%>% arrange(year,id)%>% group_by(family_id)%>% mutate( became_grandparent=min(tail(child1_birthyear,-1),na.rm=TRUE) )%>% arrange(id,year)
解决方案
原代码未区分父母与子女行,且仅提取child1_birthyear的部分值,逻辑不符合需求。以下是基于dplyr的正确实现:
library(dplyr) sample_processed <- sample %>% # 标记当前行是否为父母行(id最后一位为0) mutate(is_parent = substr(as.character(id), nchar(as.character(id)), nchar(as.character(id))) == "0") %>% group_by(family_id) %>% mutate( # 收集当前家庭所有子女行的孙辈出生年份(child1和child2) grandchild_births = list(c( child1_birthyear[!is_parent], child2_birthyear[!is_parent] )), # 计算首次成为祖父母的年份:取孙辈最早的出生年份,无孙辈则为NA became_grandparent = ifelse(length(na.omit(unlist(grandchild_births))) > 0, min(na.omit(unlist(grandchild_births))), NA), # 标记祖父母身份:父母行有孙辈则为1,无则为0;子女行设为NA grandparent = case_when( is_parent & !is.na(became_grandparent) ~ 1L, is_parent & is.na(became_grandparent) ~ 0L, TRUE ~ NA_integer_ ) ) %>% # 清理临时变量 select(-is_parent, -grandchild_births) %>% ungroup() %>% # 按id和年份排序,还原原顺序 arrange(id, year)
代码解释
- 标记父母行:通过提取id最后一位判断是否为父母数据;
- 收集孙辈出生年份:按家庭分组后,收集所有子女行的
child1_birthyear和child2_birthyear,形成列表; - 计算首次成为祖父母年份:如果有非NA的孙辈出生年份,取最小值作为首次成为祖父母的年份,无孙辈则设为NA;
- 标记祖父母身份:仅对父母行赋值,有孙辈则为1,无则为0;子女行设为NA;
- 清理与排序:移除临时变量,按id和年份排序还原原数据顺序。
验证结果
- 家庭1002的父母行(id=10020):
grandparent=1,became_grandparent=2001(对应孙辈最早出生年份); - 家庭2002的父母行(id=20020):
grandparent=0,became_grandparent=NA(无孙辈); - 所有子女行的
grandparent和became_grandparent均为NA,符合需求。
内容的提问来源于stack exchange,提问作者Ludwig Gershwin
相关产品推荐
相关产品推荐

