![89e736c3ebe2155425359272f78d3a01.png](https://i-blog.csdnimg.cn/blog_migrate/b00a68da43bbc079bace48e595b322e8.jpeg)
数据处理主要内容包括:
- 1. 特殊值处理
- 1.1 缺失值
- 1.2 离群值
- 1.3 日期
- 2. 数据转换(base vs. dplyr)
- 2.1 筛选(subset vs. filter/select/rename)
- 2.2 排序(order vs. arrange)
- 2.3 转换(transform vs. mutate/transmute)
- 2.4 分组与概括(group_by/summarise)
- 3. 数据框重塑(base vs. dplyr)
- 3.1 数据框的合并(rbind/cbind vs. bind_rows/bind_cols)
- 3.2 数据框的关联(merge vs. *_ join)
- 3.3 数据框的长宽转换(reshape2 包)
本文我们学习数据转换的有关内容,笔记(四)相关链接:
Sub-woo:R语言笔记(四):数据处理(上)zhuanlan.zhihu.com![2bc9353efc83c5420cacbc55132dcd2d.png](https://i-blog.csdnimg.cn/blog_migrate/c4f2c809bd75e77acc6b90239175a843.jpeg)
![88004a27efd08bbf12145842769e89cc.png](https://i-blog.csdnimg.cn/blog_migrate/721358bd5bfd500e343b75a0c4dfb6ea.jpeg)
有出错或补充的地方请大神们不吝赐教,作者会持续更新!
2. 数据转换
在这一部分我们会分别介绍 R 语言在处理数据转换时会用到的 base 包与 dplyr 包中的函数。
2.1 筛选(subset/filter/select)
- R 语言基本包(base)中用于筛选数据子集的函数是 subset() 。
subset(x, subset, select, drop = FALSE, ...)
x:向量(vector),矩阵(matrix)或数据框(dataframe)
subset:目标行符合的条件
select:目标列的序数
举几个例子:
set.seed(100)
x <- sample(0:50, 10)
y <- matrix(sample(0:50, 12), nrow = 3, ncol = 4)
z <- data.frame(a = sample(0:50, 5), b = sample(0:50, 5))
x
# [1] 9 37 47 24 13 43 22 21 5 3
y
# [,1] [,2] [,3] [,4]
# [1,] 5 48 11 45
# [2,] 33 42 34 24
# [3,] 6 17 7 1
z
# a b
# 1 50 20
# 2 3 26
# 3 49 38
# 4 47 15
# 5 31 10
subset(x, x >= 25) # 返回 x 中大于 25 的元素
# [1] 37 47 43
subset(y, y[, 2] >= 25 & y[, 3] <= 25, select = c(1, 3))
# 筛选出 y 的第二列大于 25 且第三列小于 25 的行(即第一行),并返回目标行的第 1 和第 3 列数据
# [,1] [,2]
# [1,] 5 11
subset(z, a <= 25 | b <= 25, select = a)
# 筛选出 a 列小于 25 或 b 列小于 25 的行(第 1,2,4,5 行),并返回目标行的 a 列数据
# a
# 1 50
# 2 3
# 4 47
# 5 31
- dplyr 包中用于筛选数据子集的函数有 filter(), slice(), select() 。
filter(.data, ...)
slice(.data, ...)
select(.data, ...)
rename(.data, ...)
四种函数都只用于 dataframe 结构的筛选,其中 filter() 与 slice() 用于筛选行,其中 filter() 多根据条件进行筛选,slice() 多根据行序数进行筛选;select() 与 rename() 用于筛选列,我们来看看 R 给出的 example。
【注】filter() 函数用法与 subset() 用法基本相似,区别在于 subset() 可以处理向量和矩阵,并且能够通过 select 参数直接筛选列,因此我们接下来主要介绍其他三种函数。
首先是 slice() 函数,用法比较简单,主要根据行序数进行筛选。
library(dplyr)
slice(z, 1:3) # 返回 z 的第 1 到第 3 行数据
# a b
# 1 50 20
# 2 3 26
# 3 49 38
slice(z, n()) # 返回 z 的最后一行数据
# a b
# 1 31 10
slice(z, 3: n()) # 返回 z 的第 3 行到最后一行数据
# a b
# 1 49 38
# 2 47 15
# 3 31 10
select() 函数用法较多,但都十分简单,作者直接将 dplyr 包的 examples 复制过来了=。=
另附参考资料:【R语言】必学包之dplyr包
iris <- as_tibble(iris) # so it prints a little nicer
select(iris, starts_with("Petal"))
# 返回列名以 "Petal" 开头的列
select(iris, ends_with("Width"))
# 返回列名以 "Width" 结尾的列
select(iris, contains("etal"))
# 返回变量名包含 "etal" 的列
select(iris, -contains("etal"))
# 返回变量名不包含 "etal" 的列
select(iris, Species, everything())
# 将 Species 变量作为第一列,并返回所有列
select(iris, -Sepal.Length, Sepal.Length)
# 将 Sepal.Length 变量作为最后一列,并返回所有列
df <- as.data.frame(matrix(runif(100), nrow = 10))
df <- tbl_df(df[c(3, 4, 7, 1, 9, 8, 5, 2, 6, 10)])
# 将各个列重新排序为 V3, V4, V7, ...
select(df, V4: V6)
# 返回第 V4 到第 V6 列(分别为第 4,7,1,9,8,5,2,6 列)
select(iris, -starts_with("Petal"))
# 返回不含以 "Petal" 开头的列(删除以 "Petal" 开头的列)
starwars %>% group_by(gender) %>% select(group_cols())
select(mtcars, mtcars$cyl)
# 返回 mtcars 数据集中名为 cyl 的列
select(mtcars, mtcars$mpg : mtcars$disp)
# 返回名为 mpg 到名为 disp 的列
vars <- c("Sepal.Length", "Sepal.Width")
select(iris, one_of(vars))
# 对于筛选字符串中的列名对应的列,需要使用 one_of()
rename() 函数主要为变量重命名,select() 也可以实现,区别在于 rename() 会返回所有列。
select(iris, petal_length = Petal.Length)
# 返回 Petal.Length 变量并重命名为 petal_length
rename(iris, petal_length = Petal.Length)
# 返回所有列,并将 Petal.Length 重命名为 petal_length
select(iris, obs = starts_with("S"))
# 返回以 "S" 开头的列,并重命名为 obs
# 当列数大于 1 时,重命名自动调整为 obs1, obs2, ...
2.2 排序(order/arrange)
根据变量名对变量进行排序,可以通过:手动进行排序;使用基本包中的 order() 排序;使用 dplyr 包中的 arrange() 排序。
order(..., na.last = TRUE, decreasing = FALSE,
method = c("auto", "shell", "radix"))
# 只能对向量进行排序,返回的是排序的索引值
# na.last 为 TRUE,排序时将 NA 放在最末;为 FALSE,放在第一位;为 NA,则移除
# decreasing 为 TRUE,降序排序;否则升序排序
arrange(.data, 变量1, desc(变量2))
# 只能对数据框进行操作
# 变量1升序,变量2降序联合排序
以 iris 数据集为例:
dat <- iris
names(dat) # 获取原始数据的变量名排序
# [1] "Sepal.Length" "Sepal.Width" "Petal.Length" "Petal.Width" "Species"
dat_manual <- dat[, c(3, 4, 1, 2, 5)]
# 观察后进行手动调整
order(names(dat)) # 升序返回索引值
# [1] 3 4 1 2 5
dat_order <- dat[, order(names(dat))]
# 使用 order() 对变量名进行升序排列
dat_order <- dat[, order(names(dat), decreasing = T)]
# 使用 order() 对变量名进行降序排列
dat_order <- dat[order(dat$Petal.Width, dat$Petal.Length), ]
# 使用 order() 对 Petal.Width 和 Petal.Length 联合升序排序
library(dplyr)
dat_arrange <- arrange(dat, dat$Petal.Width, dat$Petal.Length)
# 使用 arrange() 对 Petal.Width 和 Petal.Length 联合升序排序
dat_arrange <- arrange(dat, dat$Petal.Width, desc(dat$Petal.Length))
# 使用 arrange() 对 Petal.Width 升序,对 Petal.Length 降序联合排序
2.3 转换(transform/mutate/transmute)
基本包中的 transform() 函数可以为数据框添加新的变量,也可以对已有的变量进行编辑/删除。dplyr 包提供了两个添加新变量的函数,mutate() 和 transmute() 。
transform(.data, new_variable = NULL, ...)
mutate(.data, new_variable = NULL, ...)
transmute(.data, new_variable = NULL, ...)
三者区别在于,mutate() 在 transform() 能添加新变量的基础上,可以同时使用刚添加的变量再创建其他变量;mutate() 返回添加新变量后的新数据框,而 transmute() 仅返回新创建的变量。接下来我们来看看它们是如何实现变量编辑的:
set.seed(100)
z <- data.frame(a = sample(0:50, 3), b = sample(0:50, 3))
z
# a b
# 1 9 50
# 2 37 24
# 3 47 13
z2 <- z
z2[, 3] <- z2[, 1] + z2[, 2]
# 手动创建新变量
z2[, 2] <- NULL
# 手动删除变量 b
transform(z, c = a + b) # 创建新变量 c
# a b c
# 1 9 50 59
# 2 37 24 61
# 3 47 13 60
transform(z, b = NULL) # 删除变量 b
# a
# 1 9
# 2 37
# 3 47
# transform(z, c = a + b, d = c + 1) 会报错因为对新变量的引用需要另外书写代码
mutate(z, c = a + b, d = c + 1) # 不会报错,mutate() 的优点
# a b c d
# 1 9 50 59 60
# 2 37 24 61 62
# 3 47 13 60 61
transmute(z, c = a + b, d = c + 1) # 只返回新变量
# c d
# 1 59 60
# 2 61 62
# 3 60 61
2.4 分组与概括(group_by/summarise)
group_by() 和 summarise() 都是 dplyr 包中的函数,处理对象都是数据框结构。
group_by(.data, add = FALSE, .drop = TRUE)
# 当 add = FALSE 时,再使用 group_by() 函数分组会覆盖原分组效果;add = TRUE,则会再原有分组基础上再分组
# 当 .drop = TRUE 时,分组后的空集会被移除;否则使用 group_by_drop_default(.tbl) 函数对空组填补缺失值
summarise(.data, ...)
# 使用指定的函数获取数据框的数值特征,返回一维向量
实际工作中,group_by() 常常配合其他函数使用,因此,接下来我们先来举例介绍 summarise() 用法和效果,再结合 group_by() 函数看看差异。
library(dplyr)
dat <- mtcars
summarise(dat, quantile(disp, 0.25)) # 返回四分之一分位数
# quantile(disp, 0.25) n()
# 1 120.825 32
summarise(dat, Q1 = quantile(disp, 0.25), ME = median(disp), Q3 = quantile(disp, 0.75))
# Q1 ME Q3
# 1 120.825 196.3 326
# 可以返回多个数值特征,并且自定义变量名
接下来结合 group_by() :
dat <- group_by(dat, cyl)
summarise(dat, Q1 = quantile(disp, 0.25), ME = median(disp), Q3 = quantile(disp, 0.75))
# cyl Q1 ME Q3
# <dbl> <dbl> <dbl> <dbl>
# 1 4 78.8 108 121.
# 2 6 160 168. 196.
# 3 8 302. 350. 390
cyl 变量表示的是气缸个数,取值为 4, 6 和 8,因此对该变量进行分类便将 dat 分为三个 group。再对其使用 summarise() 会对三个 group 分别计算其四分之一分位数、中位数、四分之三分位数。我们再试试对两个变量分组的效果:
dat <- group_by(dat, cyl, gear, add = TRUE)
summarise(dat, Q1 = quantile(disp, 0.25), ME = median(disp), Q3 = quantile(disp, 0.75))
# cyl gear Q1 ME Q3
# <dbl> <dbl> <dbl> <dbl> <dbl>
# 1 4 3 120. 120. 120.
# 2 4 4 78.0 93.5 126.
# 3 4 5 101. 108. 114
# 4 6 3 233. 242. 250.
# 5 6 4 160 164. 168.
# 6 6 5 145 145 145
# 7 8 3 297. 355 410
# 8 8 5 314. 326 338.
gear 表示的是 forward gears(前齿轮?)个数,取值为 3, 4 和 5;cyl 有三个取值,因此对两个变量进行分组,应该会有 3×3 = 9 个 group,但实际只有 8 个,是因为对八个气缸的车型没有 4 个 forward gears,该组为空集,不填补缺失值就会被 drop 掉。分组后再使用 summarise() 的结果十分清晰,cyl 作为第一分组依据,gear 作为第二分组依据,分别对各组计算四分之一数、中位数和四分之三分位数。