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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 03:36:47