CATI调查脏数据清理求助:多主体文件及列内doublet问题处理
嘿,我来帮你搞定这个CATI数据集的清洗难题!看起来你卡在了两个关键点上:一是家庭成员(受访者、配偶、子女)的数据分散在多份文件里,二是单张表中同一类问题的重复列(比如你举的q_1到q_6对应每个家庭成员的性别)。咱们先从你给出的性别字段例子入手,一步步拆解解决。
第一步:搞定单表内的重复列(Doublet问题)
你的示例里,q_1到q_6本质上是同一个家庭里不同成员的性别值,Household_size则告诉我们这个家庭实际有多少成员,剩下的NA都是无效的占位值。最直观的处理方式是把这种宽格式转成长格式,让数据结构更规整:
用R的tidyverse工具包就能轻松实现,给你写段可直接复用的代码:
library(tidyverse) # 先模拟你的数据(替换成你实际的数据集加载代码就行) cati_data <- tibble( Household_size = c(3,2,5,3,6), q_1 = c(1,2,1,2,2), q_2 = c(2,1,2,2,1), q_3 = c(1,NA,1,1,1), q_4 = c(NA,NA,1,NA,1), q_5 = c(NA,NA,2,NA,1), q_6 = c(NA,NA,NA,NA,1) ) # 宽转长,自动过滤掉无效的NA值 tidy_gender_data <- cati_data %>% pivot_longer( cols = starts_with("q_"), # 选中所有q_开头的性别列 names_to = "member_order", # 把原列名转成"成员序号"字段 values_to = "gender", # 把原列值转成"性别"字段 values_drop_na = TRUE # 直接去掉带NA的无效行 ) %>% mutate(member_order = parse_number(member_order)) # 把q_1转成数字1,更直观 # 看看处理后的结果 print(tidy_gender_data)
如果这些q_1到q_6对应固定的家庭成员角色(比如q_1是受访者、q_2是配偶、q_3起是子女),你还可以给角色做个映射,让数据更易读:
# 定义角色映射表 role_map <- c( q_1 = "respondent", q_2 = "spouse", q_3 = "child_1", q_4 = "child_2", q_5 = "child_3", q_6 = "child_4" ) # 转长时直接替换成角色名 tidy_gender_with_role <- cati_data %>% pivot_longer( cols = starts_with("q_"), names_to = "member_role", values_to = "gender", values_drop_na = TRUE ) %>% mutate(member_role = recode(member_role, !!!role_map))
第二步:整合多文件的家庭成员数据
如果受访者、配偶、子女的数据分别存在不同文件里,核心是要找到所有文件共有的唯一标识(比如Household_ID,每个家庭一个专属ID),这样才能把零散的数据合并到一起。
假设你有三个文件:respondent.csv、spouse.csv、children.csv,每个都带Household_ID,处理步骤如下:
# 1. 分别加载并标记每个文件的成员角色 respondent_df <- read_csv("respondent.csv") %>% mutate(member_role = "respondent") %>% select(Household_ID, member_role, everything()) # 把ID和角色列放前面,方便查看 spouse_df <- read_csv("spouse.csv") %>% mutate(member_role = "spouse") %>% select(Household_ID, member_role, everything()) # 如果子女文件里有多个孩子,直接给每个孩子标记序号 children_df <- read_csv("children.csv") %>% group_by(Household_ID) %>% mutate(member_role = paste0("child_", row_number())) %>% ungroup() %>% select(Household_ID, member_role, everything()) # 2. 把所有文件合并成一个完整的家庭数据集 full_household_df <- bind_rows(respondent_df, spouse_df, children_df) # 3. 可以和之前的家庭规模数据关联,验证数据一致性 full_household_df <- full_household_df %>% left_join(cati_data %>% select(Household_ID, Household_size), by = "Household_ID")
几个实用小技巧
- 统一列名:先检查所有文件的列名,比如有的文件把性别列叫
gender,有的叫q_1,提前用rename()统一命名 - 校验数据逻辑:比如家庭规模是3,那整理后这个家庭的成员数也应该是3,用这段代码检查不一致的情况:
full_household_df %>% group_by(Household_ID) %>% summarise(actual_member_count = n(), expected_count = first(Household_size)) %>% filter(actual_member_count != expected_count) - 处理缺失值:如果某个家庭成员的性别缺失,结合
Household_size判断是真实缺失还是无效占位(比如家庭规模是5,但只有4个成员的数据,那就是真实缺失)
这样一步步处理下来,乱糟糟的脏数据就能变成规整的长格式,后续分析起来就顺手多啦!
内容的提问来源于stack exchange,提问作者Ann
相关产品推荐
相关产品推荐

