知识点
- 单数据整理
- 探索
- 梳理
- 筛选
- 修改
- 跨数据整理
- 直接合并
- 索引合并
演示数据
我们从已故政治学教授Ronald Inglehart创立的World Values
Survey第七波数据(WVS7)的一个样本进行演示。
这个样本是WVS7中2%的数据,包含24个变量。
具体变量信息可通过?drhur::wvs7
查看。
数据探索
数据探索指对陌生数据的数据构成、结构、形式、内容的初步了解,是数据分析的第一步,也是关键一步。
概览原始数据
wvs7
- Tidy data(
tibble
)- 行:观测单元
- 列:变量
- 单元:数值
了解数据结构
- 观测量
- 变量名及数量
- 数据结构
wvs7
nrow(wvs7) # 获取数据的行数
ncol(wvs7) # 获取数据的列数
names(wvs7) # 获取变量名/列名
str(wvs7) # 获取变量名、变量名类型、行数、列数
变量提取
基于数据讨论变量特征,首先要了解如何表达数据和变量的从属关系。 包括R在内的OOP系统非常擅长多数据、多变量的协同使用和分析。 换言之,与一些常见数据分析软件不同,R可以同时加载和综合使用多个数据——只要将他们存入不同的对象即可。
OOP → 多数据分析 → 数据信息 + 变量信息
wvs7[, "country"]
wvs7$country
变量特征
变量信息提取与上一节中的向量信息提取完全一致。
我们也可以通过table
命令获得变量分布,通过summary
命令获得常见变量信息。
当然,R也支持获取年龄变量的总和、平均数、中位数、最小值、最大值、方差、IQR等,这些方法我们会在下一节仔细讨论。
table(wvs7$age)
summary(wvs7$age)
对于非数值型变量,我们可以通过总结表的形式获取他们的信息
table(wvs7$female)
##
## FALSE TRUE
## 588 676
table(wvs7$marital)
##
## Married Cohabitant Divoiced Separated Widowed Single
## 698 82 55 35 78 306
对于基于factor的变量,我们还能提取他们的层级信息
levels(wvs7$religious)
## [1] "Religious" "Non-religious" "Atheist"
levels(wvs7$marital)
## [1] "Married" "Cohabitant" "Divoiced" "Separated" "Widowed" "Single"
变量属性
变量可能由于其类不同而具有不同的特征,比如定类向量就没法求平均值,因此mean
对于他们就是无意义的。
但所有变量都具有一些属性特征,比如变量的长度、类别、特征值等。
而对这些特征的提取命令也是共通的。
length(wvs7$age) #求取年份的长度(此处为行数)
## [1] 1264
unique(wvs7$age)
## [1] 66 34 47 51 45 61 50 48 52 42 53 33 49 57 63 68 56 19 35 28 38 67 24 30 62 79 72 37
## [29] 54 75 55 60 78 64 41 23 31 69 83 18 70 58 25 40 26 36 39 32 20 22 21 73 44 59 17 27
## [57] 46 29 65 77 43 82 85 74 NA 81 71 76 94
summary(wvs7$age) #获取年份的上述所有信息
## Min. 1st Qu. Median Mean 3rd Qu. Max. NA's
## 17.00 28.00 40.00 41.93 54.00 94.00 6
class(wvs7$age) #查看年份结构:vector、matrix、array、dataframe、list
## [1] "numeric"
typeof(wvs7$age) #查看年份元素类型
## [1] "double"
变量总览
summary(wvs7$age)
## Min. 1st Qu. Median Mean 3rd Qu. Max. NA's
## 17.00 28.00 40.00 41.93 54.00 94.00 6
summary(wvs7)
## country female age education religious
## Length:1264 Mode :logical Min. :17.00 Min. :0.000 Religious :842
## Class :character FALSE:588 1st Qu.:28.00 1st Qu.:2.000 Non-religious:310
## Mode :character TRUE :676 Median :40.00 Median :3.000 Atheist : 79
## Mean :41.93 Mean :3.394 NA's : 33
## 3rd Qu.:54.00 3rd Qu.:5.000
## Max. :94.00 Max. :8.000
## NA's :6 NA's :40
## marital incomeLevel equalIncentive equalFreedom corruption_state
## Married :698 Min. : 1.000 Min. : 1.000 Min. :1.000 None: 74
## Cohabitant: 82 1st Qu.: 3.000 1st Qu.: 4.000 1st Qu.:1.000 Few :476
## Divoiced : 55 Median : 5.000 Median : 7.000 Median :1.000 Most:427
## Separated : 35 Mean : 4.697 Mean : 6.284 Mean :1.433 All :178
## Widowed : 78 3rd Qu.: 6.000 3rd Qu.: 9.000 3rd Qu.:2.000 NA's:109
## Single :306 Max. :10.000 Max. :10.000 Max. :2.000
## NA's : 10 NA's :39 NA's :23 NA's :23
## corruption_local corruption_civil trust_family trust_neighbor trust_stranger
## None: 78 None: 92 Min. :1.00 Min. :1.000 Min. :1.000
## Few :531 Few :558 1st Qu.:4.00 1st Qu.:2.000 1st Qu.:1.000
## Most:392 Most:365 Median :4.00 Median :3.000 Median :2.000
## All :144 All :132 Mean :3.72 Mean :2.803 Mean :1.896
## NA's:119 NA's:117 3rd Qu.:4.00 3rd Qu.:3.000 3rd Qu.:2.000
## Max. :4.00 Max. :4.000 Max. :4.000
## NA's :4 NA's :16 NA's :28
## trust_foreigner confidence_armedForce confidence_policy confidence_court
## Min. :1.000 Min. :1.000 Min. :1.000 Min. :1.000
## 1st Qu.:1.000 1st Qu.:2.000 1st Qu.:2.000 1st Qu.:2.000
## Median :2.000 Median :3.000 Median :3.000 Median :3.000
## Mean :2.125 Mean :2.862 Mean :2.611 Mean :2.527
## 3rd Qu.:3.000 3rd Qu.:4.000 3rd Qu.:3.000 3rd Qu.:3.000
## Max. :4.000 Max. :4.000 Max. :4.000 Max. :4.000
## NA's :54 NA's :69 NA's :45 NA's :66
## confidence_gov confidence_parliament confidence_civil confidence_parties
## Min. :1.000 Min. :1.000 Min. :1.000 Min. :1.000
## 1st Qu.:1.000 1st Qu.:1.000 1st Qu.:2.000 1st Qu.:1.000
## Median :2.000 Median :2.000 Median :2.000 Median :2.000
## Mean :2.342 Mean :2.164 Mean :2.376 Mean :2.022
## 3rd Qu.:3.000 3rd Qu.:3.000 3rd Qu.:3.000 3rd Qu.:3.000
## Max. :4.000 Max. :4.000 Max. :4.000 Max. :4.000
## NA's :61 NA's :64 NA's :55 NA's :60
## confidence_tv
## Min. :1.000
## 1st Qu.:2.000
## Median :2.000
## Mean :2.372
## 3rd Qu.:3.000
## Max. :4.000
## NA's :26
数据梳理
如果说数据探索是从数据中看变量,那么数据梳理就是以变量为索引来了解数据。
从实用角度出发,我们这里直接介绍如何使用tidyverse
进行数据梳理。
但其实绝大部分数据梳理都是可以通过R的自带语句完成的。
我们也将自带语句对于同一任务的操作放置在“提示”单元中。
安装
install.packages("tidyverse")
library("tidyverse")
dplyr
包
tidyverse
中专门负责数据清理的组件,贯彻一个函数做一件事的风格。
通道
在逐一介绍dplyr
的主要命令前,我们要先说明一下“通道”(pipe)。
通道在R中可以直接使用|>
表示,在叫起dplyr
后还可以使用功能更强的%>%
。
我们后面的例子直接使用后者。
在R中,通道起到连接对于同一个对象的连续动作,相当于动作游戏中“搓”一个连续技。
另一方面,通道也能让每个命令排布更加明确、易读。 再举一个例子,如果我们用代码来模拟煮饺子的全过程,大体是这样:
eat_dumpling <-
eat(
dip(
cook(
fill(
mix(
meat,
with = c(salt, soy_sauce, green_onion, ginger)
),
with = wrapper
),
in = boilled_water
),
in = vinegar)
)
使用通道后,可以写成这样
eat_dumpling <-
mix(meat, with = c(salt, soy_sauce, green_onion, ginger)) %>%
fill(with = wrapper) %>%
cook(in = boilled_water) %>%
dip(in = vinegar) %>%
eat
%>%
的快捷键:
- Ctrl + Shift + M (Win)
- Cmd + Shift + M (Mac)
变量筛选
select(<data>, <var1>, <var2>, ...)
现在数据中有24个变量,有一些有意思的变量排在后面不方便看到,我们希望看到一个只有国家、年龄、教育水平和对政府信心的数据框:
select(wvs7, country, age, education, confidence_gov)
# 如果我们想看到关于信心的所有变量,除了逐个列出来以外还能怎么做?
select(wvs7, country, age, education, starts_with("confidence"))
和starts_with
类似的还有ends_with
和matches
。
提示:注意第三人称变单数😝
删除变量可以通过-
实现:
select(wvs7, -(country:education))
一个select
衍生体是rename
,语法为new.name = old.name
rename(wvs7, nationality = country)
数据排序
arrange(<data>,...)
比如我们好奇最年轻的人群对国家机关的信心,并对应他们的教育水平、收入水平等信息。
select(wvs7, age, confidence_gov, education, incomeLevel)
select(wvs7, age, confidence_gov, education, incomeLevel) %>%
arrange(age)
那最年长的那群人呢?
select(wvs7, age, confidence_gov, education, incomeLevel) %>%
arrange(desc(age))
## 如果我们想知道最年轻又教育最高的人呢?
select(wvs7, age, confidence_gov, education, incomeLevel) %>%
arrange(age, desc(education))
变量值筛选
前面提到select
是对数据库变量的筛选,filter
则基于变量值的筛选。
延续上面的例子,如果我们好奇美国最年轻的一群人对国家机关的信心以及他们的教育水平和收入水平。
select(wvs7, age, confidence_gov, education, incomeLevel) %>%
arrange(age)
select(wvs7, age, confidence_gov, education, incomeLevel, country) %>%
filter(country == "United States") %>%
arrange(age)
select(wvs7, age, confidence_gov, education, incomeLevel, country) %>%
filter(country == "United States") %>%
filter(age == min(age, na.rm = TRUE))
数据修改
在数据分析中,我们常常要将数据进行调整和再加工,mutate
可以帮你做到这一点。
英文中“mutate”表示“变异”,也就是说这个函数可以实现的并不是无中生有,而是改头换面。
如果我们关心教育水平对收入水平差异的影响,我们可以建立一个比例变量
mutate(wvs7, ratio_incomeEdu = incomeLevel / (education + 1)) %>%
select(country, incomeLevel, education, ratio_incomeEdu) %>%
arrange(desc(ratio_incomeEdu))
# 如果要把`ratio_incomeEdu`变成一个百分数,怎么办?
mutate(wvs7,
ratio_incomeEdu = incomeLevel / (education + 1),
ratio_incomeEdu = as.numeric(ratio_incomeEdu) %>%
scales::percent()) %>%
select(country, ratio_incomeEdu)
dplyr
还允许批量修改
如何对变量进行批量修改?dplyr
和它的朋友tidyselect
提供了across
和where
函数。
比如出于某种需要,我们要给每个数字变量都取对数。
流程: 判断 → 筛选 → 修改
wvs7 %>%
mutate(across(where(is.numeric), log))
# 是否能使用这套技巧将所有人际信任变量都倒叙?
wvs7 %>%
mutate(across(starts_with("trust"), ~ 5 - .))
数值统计
count
用来基于数据计数。
比如,可以使用count来计算我们的数据中男性、女性各有多少人。1
wvs7 %>%
count(female)
# 如果想知道不同年龄段的男女数量怎么办呢?
wvs7 %>%
count(age, female)
这种列表在人口普查等统计数据中非常常见。↩︎
summarise
用来将个体数据转换成统计数据。
比如,我们想获得样本的年龄和教育水平平均数
wvs7 %>%
summarise(age = mean(age, na.rm = TRUE),
edu = mean(education, na.rm = TRUE))
我们前面提到的across
,
start_with
等同样可以在这里使用:
比如我们想获得所有关于机构信心变量的平均值:
wvs7 %>%
summarise(across(starts_with("confidence"), mean, na.rm = TRUE))
group_by
使分组操作成为可能:
wvs7 %>%
group_by(female) %>%
summarise(age = mean(age, na.rm = TRUE),
edu = mean(education, na.rm = TRUE))
group_by
实际是为现有数据建立群体索引,之后的所有操作都将在分组进行。
这一命令的逆操作是ungroup
。
Bonus
怎么样才能填补缺失的 x
, 然后把 y
和
z
合并成一个变量呢?
df_toy <- data.frame(x = sample(c(1:2, NA, NA, NA)),
y = c(1, 2, NA, NA, 5),
z = c(NA, NA, 3, 4, 5))
df_toy
df_toy %>%
mutate(x = coalesce(x, 0L),
yz = coalesce(y, z)) # Ta-da~~~
数据整理原则
我们上面的一系列操作都有一个共同的特点,你发现了吗?
head(wvs7)
- 不碰原始数据
- 对象覆盖需谨慎
wvs7 <- mutate(wvs7, female = as.numeric(female))
数据整合
直接合并
直接合并的前提基本和矩阵运算是基本一致的:只有前列数对得上后行才能进行。
- 行合并: 列数相等(并不是~)
- 列合并: 行数相等
分别举个例子:
wvs7_us <- filter(wvs7, country == "Unitied States")
wvs7_russia <- filter(wvs7, country == "Russia")
# 创建一个美俄数据
bind_rows(wvs7_us, wvs7_russia)
# 不等列行合并会发生什么?
# Try this
bind_rows(tibble(x = 1:3), tibble(y = 1:4))
wvs7_conf <- select(wvs7, starts_with("confidence"))
wvs7_trust <- select(wvs7, starts_with("trust"))
# 创建一个信心-信任数据
bind_cols(wvs7_conf, wvs7_trust)
索引合并
索引合并指的是基于共享的索引序列(可以是任何变量)合并数据。
让我们先创建两个演示数据:
- 个体层级平等认知数据;
- 国家层级人口变量数据。
如果wvs7_eq
是调查数据,wvs7_country
是人口统计数据,我们的研究需要将这两组数据合并分析个体层级和国家层级变量间的关系。
wvs7_eq <- select(wvs7, country, starts_with("equal")) %>%
filter(country %in% unique(country)[1:2])
wvs7_country <- group_by(wvs7, country) %>%
summarise(across(female:education, mean, na.rm = TRUE)) %>%
ungroup %>%
filter(country %in% unique(country)[2:3])
inner_join(wvs7_eq, wvs7_country)
left_join(wvs7_eq, wvs7_country)
right_join(wvs7_eq, wvs7_country)
full_join(wvs7_eq, wvs7_country)
总结
- 行动之前 想清楚;
- 巧妙且综合地使用
dplyr
函数;- 探索:
glimpse
,head
,tail
- 结构:
nrow
,ncol
,names
,str
- 特征:
table
,levels
- 属性:
length
,unique
,summary
,class
,typeof
- 结构:
- 梳理:
dplyr
命令集
- 探索:
- 数据整合原则:不碰原数据
- 数据合并
- 直接合并:
bind_*
- 索引合并:
*_join
- 直接合并: