使用 Tidyverse 清洗 CFPS 数据(一)

R
SPSS
数据处理
一些尝试
tidyverse
Author

Rui

Published

September 22, 2022

初步筛选变量

处理 CFPS 数据的难点:

  • 变量繁多,变量名称眼花缭乱。而且各年份的数据中的变量并不完全相同,同一变量在不同年份的表中的名称也不一样;

  • 数据文件名称不统一。即”xxx.sav”没有一个统一的标准,读取数据时可能没有办法使用循环,需要手工读取并导入;

  • 最后一点也是最重要的一点。CFPS 数据为关系型数据,同一年份下的文件夹包含多张表,各个表所反映的信息侧重点不同,且表与表之间变量关系错综复杂。在此基础上衍生出来的问题也五花八门,如:如何准确匹配记录、重组变量?如何根据需要将多张表的信息凝聚在一张表中?如何将表整理为截面数据?如何跨年份将不同的表合并为面板数据?如何处理缺失值和异常值?

明确需求

抛开实际需求进行数据处理如同空中楼阁,只有确定需求才能为数据分析工作打好地基。本文以复现一篇论文中的基准回归为目标,希望准确匹配记录、提取出相关变量整合在一张表中供建模使用。

潘敏和刘知琪(2018)在《居民家庭”加杠杆”能促进消费吗?》一文中建立了如下的基准回归(后续的模型本文不考虑):

\[ \Delta\ln exp_i=\alpha+\beta_1lev_i+\beta_2\Delta\ln inc_i+\beta_3\ln asset_i+\gamma_1\Delta X_i^a+\gamma_2X_i^b+\mu_p+\varepsilon_i \]

Note

论文中使用的是 2014 年和 2016 年的数据,而本篇教程使用的是 2016 年和 2018 年的数据。官网提供多种文件格式的下载,这里使用 SPSS 中的数据文件,即后缀为 .sav 的文件。

变量名称 含义
\(exp_i\) 第 i 个家庭的家庭总支出
\(lev_i\) 第 i 个家庭的杠杆率,杠杆率为家庭总负债除以家庭总资产
\(inc_i\) 第 i 个家庭的家庭纯收入
\(asset_i\) 第 i 个家庭的家庭总资产
\(X_i^a\) 第 i 个家庭的家庭人口数量
\(X_i^b\) 第 i 个家庭的家庭特征,包括户主年龄、年龄的平方、性别、婚姻状况、健康状况等
\(\mu_p\) 省份固定效应,是一系列虚拟变量, p 表示不同省份

必要说明:

  • 本文在变量选取时未能像论文中那样严谨、全面,很多细节没有考虑进去,主要分享思路,处理方法仅供参考。

  • 数据分散在两张表中:一张是”家庭表”(“xxx_famecon_xxx.sav”),主要以家庭为单位记录家庭经济信息;另一张表为”个人表”(“xxx_person_xxx.sav”),主要记录个人基本信息、经济、社交、心理等信息。这两张表侧重点不一样,但是跨表间变量的联系千丝万缕。根据逻辑可以认为:同一个家庭只能被调查一次,同一个个人也只能被调查一次,家庭与个人的关系为一对多的关系。

  • 论文中以家庭为单位,所以应该以家庭数据为主,兼顾个人数据。这个思想将会贯穿整个数据处理工作。

  • 家庭总负债论文中没有明确提及,由于中国家庭的负债中大多是房贷,所以这里认为是家庭总负债是家庭总房贷与非房贷的金融负债之和。

  • 家庭总资产包括土地、房产、金融资产、生产性固定资产和耐用消费品。

  • 论文中家庭特征包含很多变量,这里为方便展示,只考虑户主年龄、年龄的平方、性别、婚姻状况、健康状况等。

  • CFPS 数据中没有明确户主,这里采用论文中的方法:在问卷调查中对生活支出方面做出实际回答人的为户主。

  • \(\Delta\) 代表 2018 年与 2016 年数据的差值。

  • 本文主要使用 tidyverse 进行数据处理,一些函数除特别重要以外不做说明。若有兴趣学习 tidyverse 相关用法,请参阅 R for Data Science

导入数据并初步筛选变量

需要同时使用 SPSS 和 R 语言。其中 SPSS 可以直观感受数据,并且能够了解各变量含义和可能的取值,R 主要用于编程实现。

tidyverse 生态中的 haven 包可以读取多种其他统计软件的数据,使用 write_sav() 可以读取 SPSS 数据。

打开 SPSS 后的直观感受就是变量太多了!家庭表有 300 多个变量,个人表有 1000 多个变量。如果想从这么多变量中挑出自己需要(或者可能需要,或者以后可能需要)的变量,不是一件容易的事。但是反过来想问题就简单多了:因为要研究的是经济问题,所以那些心理、健康、社交、出行等方面的变量可以优先剔除。

幸好,tidyverse 的强大功能可以大大简化我们的工作,我们可以按照某种规则剔除变量而不是将那些变量的名字一个一个打出来。 比如,借款被拒经历一系列变量名称以 ft 开头,做饭用水用燃气等一系列变量名称以 fa 开头,自我评价等一系列变量名称以 qs 开头……按照这种规则可以提取出一系列希望剔除的变量名称(有点类似于正则表达式),将这种变量名称的规则保存在变量 del_col1 中,再使用 select(-starts_with(del_col1)) 将符合这种规则的变量一次性删除。

处理 2018 年家庭表:

Code

library(tidyverse)

file_path <- "./data/CFPS2018/CFPS2018-SPSS/cfps2018famecon_家庭经济.sav"

del_col1 <- c("fa", "fl1pid", "fl2pid", "fm2", "fm3", "fo2", "fo6", "fp101pid", 
              "fp2", "fq1", "fq2", "fq3", "fq4", "fq5", "fs1", "fs8", "ft7", 
              "ft8", "fz", "interv", "release") # 要剔除的变量的部分名称
df_2018_famecon <- haven::read_sav(file_path) %>% 
  as_tibble() %>%
  select(-starts_with(del_col1)) # 剔除变量名称以del_col1中字符为开头的变量

haven::write_sav(df_2018_famecon, "./data/operated_data/2018famecon.sav") # 保存初筛后的数据

处理 2018 年个人表:

Code
file_path <- "./data/CFPS2018/CFPS2018-SPSS/cfps2018person_个人库.sav"

del_col1 <- c("wl", "wm", "wv", "kw", "kr", "kg", "ks", "pd", "pt", "pn", "pm",
              "eb", "qb", "qc", "pd", "qf", "qi", "qg", "qk", "qm", "qn", "qu", 
              "qp", "qq", "qx", "qr", "qs")
del_col2 <- c("eeb", "egc", "qa1", "qa6", "qga", "kgd", "xch", "qeb")
del_col3 <- c("ear1", "ear3", "ear4", "ear5", "ear6", "ear7", "qea2", "yincome", 
              "mincome", "jobclass", "lastyjob", "qint", "qext", "ear202y", 
              "ear202m", "qg303code_", "qea210code", "interv", "relea", "which", 
              "math", "word")

df_2018_person <- haven::read_sav(file_path) %>% 
  as_tibble() %>%
  select(-starts_with(del_col1)) %>%
  select(-starts_with(del_col2)) %>%
  select(-starts_with(del_col3)) # 剔除不需要的变量

haven::write_sav(df_2018_person, "./data/operated_data/2018person.sav") # 保存初筛后的数据

2016 年的家庭表和个人表的处理也是如此,这里不再赘述。至此,对 CFPS 数据的变量初次提取完毕,将家庭表中的变量减少到 200 多个,将个人表中的变量减少到 100 多个。 本次变量初步筛选去除了原数据中与经济相关性不大的变量,日后如需进行经济方面的研究,可以直接访问初筛后的数据(“2018person.sav”等数据)而不用打开原数据。

Note

各年数据的变量个数并不相同。即便是同一个变量在,不同年份的表中的名称也不一定相同。筛选变量时需要注意,复制粘贴代码的同时也需要结合 SPSS 的变量视图做一定的修改。