vlambda博客
学习文章列表

R语言数据转换(三)常用数据处理包的使用

几个常用的数据处理包


这里介绍了几个比较常用的处理数据的R语言包的一些核心函数,若有更多的阅读需求请参考官方文档详细了解。

文章摘要:

序号 内容
1 reshape2包
2 tidyr包
3 dplyr包

reshape2包

1 简介

reshape2是reshape的进阶版,提高了运行效率和速度。该包具有很多方便好用的函数能对数据进行处理特别是在数据融合与重组方面非常强大。

2 宽数据、长数据

  1. 宽数据:在同一行,标识变量(一列或多列)能够唯一标识两个或多个变量的值,这种数据显示叫做数据的宽格式,也叫做宽数据。我们常见的数据基本都是宽数据。(示例如下)
ID Time x1 x2 x3
A 1 3 5 4
A 2 4 7 5
B 1 0 6 3
B 2 5 3 2
  • 在该表中,ID和Time组合是唯一的,x1,x2,x3则是观测值。这样的数据则称之为宽数据。
  1. 长数据:长数据也叫融合数据。得每个观测变量独占一行,每行都有唯一确定每个观测变量所需要的标识变量。融合之后的数据,称作长格式,也叫作长数据。示例如下:
ID Time variable value
A 1 x1 3
A 1 x2 5
A 1 x3 4
A 2 x1 4
A 2 x2 7
A 2 x3 5
B 1 x1 0
B 1 x2 6
B 1 x3 3
B 2 x1 5
B 2 x2 3
B 2 x3 2
  1. 在R中使用较多的是长数据,比如在ggplot2中,绘制分组时就要采用长数据。因此需要掌握如何使用宽数据变长数据。

3 reshape2中常用的函数

  1. melt()、decast()函数:宽数据变长数据、数据塑形。
  • melt()参数注释:
  • data:融合的数据框
  • id.vars:由标识变量构成的向量,用于标识观测的变量
  • measure.vars :由观测变量构成的向量
  • variable.name:用于保存原始变量名的变量的名称
  • value.name:用于保存原始值的名称

  • decast参数注释:
  • data:已融合的数据框
  • formula:用于指定输出的结果集格式
  • fun.aggregate:用于指定聚合函数,对已聚合的数据执行聚合运算
  • margins:相当于透视表中的行总计和列总计
  • subset:选取满足一些特定值的数据,相当于Excel透视表的筛选。例如, subset =.(variable ==“length”)
  • fill:用于填充结构缺失的值,默认为将fun.aggregate应用于0长度向量的值
  • value:value列的名称
  • 示例:
library(reshape2)
head(airquality,3)
names(airquality) <- tolower(names(airquality))
head(airquality,3)

head(melt(airquality),10)

aq1 <- melt(airquality,id.vars = c("month","day"))
head(aq1)
aq2 <- dcast(aq1,month~variable,fun.aggregate = mean,na.rm = T)
aq2

head(airquality,10)
  • 结果:
> library(reshape2)
> head(airquality,3)
ozone solar.r wind temp month day
1 41 190 7.4 67 5 1
2 36 118 8.0 72 5 2
3 12 149 12.6 74 5 3
> names(airquality) <- tolower(names(airquality))
> head(airquality,3)
ozone solar.r wind temp month day
1 41 190 7.4 67 5 1
2 36 118 8.0 72 5 2
3 12 149 12.6 74 5 3
>
> head(melt(airquality),10)
No id variables; using all as measure variables
variable value
1 ozone 41
2 ozone 36
3 ozone 12
4 ozone 18
5 ozone NA
6 ozone 28
7 ozone 23
8 ozone 19
9 ozone 8
10 ozone NA
>
> aq1 <- melt(airquality,id.vars = c("month","day"))
> head(aq1)
month day variable value
1 5 1 ozone 41
2 5 2 ozone 36
3 5 3 ozone 12
4 5 4 ozone 18
5 5 5 ozone NA
6 5 6 ozone 28
> aq2 <- dcast(aq1,month~variable,fun.aggregate = mean,na.rm = T)
> aq2
month ozone solar.r wind temp
1 5 23.61538 181.2963 11.622581 65.54839
2 6 29.44444 190.1667 10.266667 79.10000
3 7 59.11538 216.4839 8.941935 83.90323
4 8 59.96154 171.8571 8.793548 83.96774
5 9 31.44828 167.4333 10.180000 76.90000
>
> head(airquality,10)
ozone solar.r wind temp month day
1 41 190 7.4 67 5 1
2 36 118 8.0 72 5 2
3 12 149 12.6 74 5 3
4 18 313 11.5 62 5 4
5 NA NA 14.3 56 5 5
6 28 NA 14.9 66 5 6
7 23 299 8.6 65 5 7
8 19 99 13.8 59 5 8
9 8 19 20.1 61 5 9
10 NA 194 8.6 69 5 10

这里使用了melt()先融合数据,然后用dcast()函数重组数据

  1. merge()函数,有rbind的功能,但比rbind更强大
  • 示例:
x <- data.frame(k1 = c(NA,NA,3,4,5),k2 = c(1,NA,NA,4,5),data = 1:5)
y <- data.frame(k1 = c(NA,2,NA,4,5),k2 = c(NA,NA,3,4,5),data = 1:5)
x
y

rbind(x,y)

merge(x,y,by = "k1")#指定以k1为准

merge(x,y,by = "k2")#指定以k2为准

merge(x,y,by = c("k1","k2"))#指定以k1和k2为准
  • 结果:
> x <- data.frame(k1 = c(NA,NA,3,4,5),k2 = c(1,NA,NA,4,5),data = 1:5)
> y <- data.frame(k1 = c(NA,2,NA,4,5),k2 = c(NA,NA,3,4,5),data = 1:5)
> x
k1 k2 data
1 NA 1 1
2 NA NA 2
3 3 NA 3
4 4 4 4
5 5 5 5
> y
k1 k2 data
1 NA NA 1
2 2 NA 2
3 NA 3 3
4 4 4 4
5 5 5 5
>
> rbind(x,y)
k1 k2 data
1 NA 1 1
2 NA NA 2
3 3 NA 3
4 4 4 4
5 5 5 5
6 NA NA 1
7 2 NA 2
8 NA 3 3
9 4 4 4
10 5 5 5
>
> merge(x,y,by = "k1")
k1 k2.x data.x k2.y data.y
1 4 4 4 4 4
2 5 5 5 5 5
3 NA 1 1 NA 1
4 NA 1 1 3 3
5 NA NA 2 NA 1
6 NA NA 2 3 3
>
> merge(x,y,by = "k2")
k2 k1.x data.x k1.y data.y
1 4 4 4 4 4
2 5 5 5 5 5
3 NA NA 2 NA 1
4 NA NA 2 2 2
5 NA 3 3 NA 1
6 NA 3 3 2 2
>
> merge(x,y,by = c("k1","k2"))
k1 k2 data.x data.y
1 4 4 4 4
2 5 5 5 5
3 NA NA 2 1

tidyr包

1 用于处理tidy数据,即整洁干净的数据

什么是整洁数据

  • 每一行代表一个变量
  • 每一列代表一个观测
  • 没有重复的列名和行名

参考网址

Tidy Messy Data • tidyr (tidyverse.org)

2 tidyr包的几个核心函数

  • 获得示例数据
head(mtcars)
x <- mtcars[1:10,1:4]
head(x)
x <- data.frame(names = rownames(x),x)
head(x)

  1. gather()函数,对数据进行整合
  • 形式:gather(data, key, value, …, na.rm= FALSE, convert =FALSE)
  • 参数解释:
  • data:需要被转换的宽形表
  • key:将原数据框中的所有列赋给一个新变量key
  • value:将原数据框中的所有值赋给一个新变量value
  • …:可以指定哪些列聚到同一列中
  • na.rm:是否删除缺失值
  • 示例:
x1 <- gather(x,key = "key","value",cyl,disp,mpg)
x1
  • 结果:
> x1 <- gather(x,key = "key","value",cyl,disp,mpg)
> x1
names hp key value
1 Mazda RX4 110 cyl 6.0
2 Mazda RX4 Wag 110 cyl 6.0
3 Datsun 710 93 cyl 4.0
4 Hornet 4 Drive 110 cyl 6.0
5 Hornet Sportabout 175 cyl 8.0
6 Valiant 105 cyl 6.0
7 Duster 360 245 cyl 8.0
8 Merc 240D 62 cyl 4.0
9 Merc 230 95 cyl 4.0
10 Merc 280 123 cyl 6.0
11 Mazda RX4 110 disp 160.0
12 Mazda RX4 Wag 110 disp 160.0
13 Datsun 710 93 disp 108.0
14 Hornet 4 Drive 110 disp 258.0
15 Hornet Sportabout 175 disp 360.0
16 Valiant 105 disp 225.0
17 Duster 360 245 disp 360.0
18 Merc 240D 62 disp 146.7
19 Merc 230 95 disp 140.8
20 Merc 280 123 disp 167.6
21 Mazda RX4 110 mpg 21.0
22 Mazda RX4 Wag 110 mpg 21.0
23 Datsun 710 93 mpg 22.8
24 Hornet 4 Drive 110 mpg 21.4
25 Hornet Sportabout 175 mpg 18.7
26 Valiant 105 mpg 18.1
27 Duster 360 245 mpg 14.3
28 Merc 240D 62 mpg 24.4
29 Merc 230 95 mpg 22.8
30 Merc 280 123 mpg 19.2
  1. sperad()函数对数据进行打散
  • 形式:spread(data, key, value, fill = NA, convert = FALSE, drop = TRUE)
  • 参数解释:
  • data:需要转换的长形表
  • key:需要将变量值拓展为字段的变量
  • value:需要分散的值
  • fill:对于缺失值,可将fill的值赋值给被转型后的缺失值
  • 示例:
x2 <- spread(x1,key = "key",value = "value")
x2
  • 结果:
> x2 <- spread(x1,key = "key",value = "value")
> x2
names hp cyl disp mpg
1 Datsun 710 93 4 108.0 22.8
2 Duster 360 245 8 360.0 14.3
3 Hornet 4 Drive 110 6 258.0 21.4
4 Hornet Sportabout 175 8 360.0 18.7
5 Mazda RX4 110 6 160.0 21.0
6 Mazda RX4 Wag 110 6 160.0 21.0
7 Merc 230 95 4 140.8 22.8
8 Merc 240D 62 4 146.7 24.4
9 Merc 280 123 6 167.6 19.2
10 Valiant 105 6 225.0 18.1
  1. separate()函数按照列进行分割,unite()进行合并
  • 形式:separate(data, col, into, sep = “[^[:alnum:]]+”, remove = TRUE,
  • 参数解释:
  • convert = FALSE, extra = “warn”, fill = “warn”, …)
  • data:为数据框
  • col:需要被拆分的列
  • into:新建的列名,为字符串向量
  • sep:被拆分列的分隔符
  • remove:是否删除被分割的列
  • 形式:unite(data, col, …, sep = , remove = TRUE)
  • 参数解释:
  • data:为数据框
  • col:被组合的新列名称
  • …:指定哪些列需要被组合
  • sep:组合列之间的连接符,默认为下划线
  • remove:是否删除被组合的列
  • 示例:
y <- data.frame(x = c("1.2","2.3","3.4"))
y

separate(y,col = x,into = c("A","B"))#默认为分隔符为"."。

y <- data.frame(x = c("1-2","2-3","3-4"))
y1 <- separate(y,col = x,into = c("A","B"),sep = "-")#设定分隔符
y1

unite(y1,col = "AB",A,B,sep = "-")#进行合并操作
  • 结果:
> y <- data.frame(x = c("1.2","2.3","3.4"))
> y
x
1 1.2
2 2.3
3 3.4
>
> separate(y,col = x,into = c("A","B"))#默认为分隔符为"."。
A B
1 1 2
2 2 3
3 3 4
>
> y <- data.frame(x = c("1-2","2-3","3-4"))
> y1 <- separate(y,col = x,into = c("A","B"),sep = "-")#设定分隔符
> y1
A B
1 1 2
2 2 3
3 3 4
>
> unite(y1,col = "AB",A,B,sep = "-")#进行合并操作
AB
1 1-2
2 2-3
3 3-4

dplyr包

1. dplyr简介

dplyr是R语言的数据分析包,类似于python中的pandas,能对dataframe类型的数据做很方便的数据处理和分析操作。

dplyr如同R的大多数包,都是函数式编程,这点跟Python面向对象编程区别很大。优点是初学者比较容易接受这种函数式思维,有点类似于流水线,每个函数就是一个车间,多个车间共同完成一个生产(数据分析)任务。

而在dplyr中,就有一个管道符 %>% ,符号左侧表示数据的输入,右侧表示下游数据处理环节,能够大大提高数据处理效率。

2. 参考资料

  • A Grammar of Data Manipulation • dplyr (tidyverse.org)

3. dplyr包的常用函数

  • 数据处理
  • 下面只展示代码结果,不再分开展示代码和结果:
  1. fliter()对数据进行过滤
> library(dplyr)
> head(iris)
Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1 5.1 3.5 1.4 0.2 setosa
2 4.9 3.0 1.4 0.2 setosa
3 4.7 3.2 1.3 0.2 setosa
4 4.6 3.1 1.5 0.2 setosa
5 5.0 3.6 1.4 0.2 setosa
6 5.4 3.9 1.7 0.4 setosa
#按照条件进行过滤
> dplyr::filter(iris,Sepal.Length>=7.7)
Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1 7.7 3.8 6.7 2.2 virginica
2 7.7 2.6 6.9 2.3 virginica
3 7.7 2.8 6.7 2.0 virginica
4 7.9 3.8 6.4 2.0 virginica
5 7.7 3.0 6.1 2.3 virginica
  1. 去除重复行
> dplyr::distinct(rbind(iris[1:3,],iris[1:5,]))
Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1 5.1 3.5 1.4 0.2 setosa
2 4.9 3.0 1.4 0.2 setosa
3 4.7 3.2 1.3 0.2 setosa
4 4.6 3.1 1.5 0.2 setosa
5 5.0 3.6 1.4 0.2 setosa
  1. 数据提取,切片
> dplyr::slice(iris,10:12)
Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1 4.9 3.1 1.5 0.1 setosa
2 5.4 3.7 1.5 0.2 setosa
3 4.8 3.4 1.6 0.2 setosa
  1. 随机取样
> dplyr::sample_n(iris,3)#按个数随机选取
Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1 5.1 2.5 3.0 1.1 versicolor
2 6.8 3.2 5.9 2.3 virginica
3 6.0 3.0 4.8 1.8 virginica
> dplyr::sample_frac(iris,0.05)#按比例随机选取
Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1 5.1 3.8 1.6 0.2 setosa
2 6.3 3.4 5.6 2.4 virginica
3 5.0 3.4 1.5 0.2 setosa
4 4.8 3.0 1.4 0.3 setosa
5 4.6 3.6 1.0 0.2 setosa
6 4.3 3.0 1.1 0.1 setosa
7 5.3 3.7 1.5 0.2 setosa
8 5.8 2.7 3.9 1.2 versicolor
  1. 排序
 dplyr::arrange(iris,iris$Sepal.Length)
Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1 4.3 3.0 1.1 0.1 setosa
2 4.4 2.9 1.4 0.2 setosa
3 4.4 3.0 1.3 0.2 setosa
4 4.4 3.2 1.3 0.2 setosa
#…………
> dplyr::arrange(iris,desc(iris$Sepal.Length))#反向排序
Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1 7.9 3.8 6.4 2.0 virginica
2 7.7 3.8 6.7 2.2 virginica
3 7.7 2.6 6.9 2.3 virginica
4 7.7 2.8 6.7 2.0 virginica
#…………
  1. 提取子集slect()
  • 示例:
> x <- dplyr::select(iris,Sepal.Length)
> head(x)
Sepal.Length
1 5.1
2 4.9
3 4.7
4 4.6
5 5.0
6 5.4
  • 统计函数summrise()函数
> summarise(iris,avg= mean(Sepal.Length))
avg
1 5.843333
  • 链式操作符%>%两个百分号中间夹着一个大于号,称为链式操作符,它功能是用于实现将一个函数的输出传递给下一个函数,作为下一个函数的输入。在Rstudio中可以使用ctrl+shift+M快捷键输出出来。
> head(iris,20) %>% tail(5)
Sepal.Length Sepal.Width Petal.Length Petal.Width Species
16 5.7 4.4 1.5 0.4 setosa
17 5.4 3.9 1.3 0.4 setosa
18 5.1 3.5 1.4 0.3 setosa
19 5.7 3.8 1.7 0.3 setosa
20 5.1 3.8 1.5 0.3 setosa
  • 分组,管道操作符等函数符合使用
> dplyr::group_by(iris,iris$Species)
# A tibble: 150 x 6
# Groups: iris$Species [3]
Sepal.Length Sepal.Width Petal.Length Petal.Width Species `iris$Species`
<dbl> <dbl> <dbl> <dbl> <fct> <fct>
1 5.1 3.5 1.4 0.2 setosa setosa
2 4.9 3 1.4 0.2 setosa setosa
3 4.7 3.2 1.3 0.2 setosa setosa
4 4.6 3.1 1.5 0.2 setosa setosa
5 5 3.6 1.4 0.2 setosa setosa
6 5.4 3.9 1.7 0.4 setosa setosa
7 4.6 3.4 1.4 0.3 setosa setosa
8 5 3.4 1.5 0.2 setosa setosa
9 4.4 2.9 1.4 0.2 setosa setosa
10 4.9 3.1 1.5 0.1 setosa setosa
# ... with 140 more rows

> iris %>% group_by(iris$Species)
# A tibble: 150 x 6
# Groups: iris$Species [3]
Sepal.Length Sepal.Width Petal.Length Petal.Width Species `iris$Species`
<dbl> <dbl> <dbl> <dbl> <fct> <fct>
1 5.1 3.5 1.4 0.2 setosa setosa
2 4.9 3 1.4 0.2 setosa setosa
3 4.7 3.2 1.3 0.2 setosa setosa
4 4.6 3.1 1.5 0.2 setosa setosa
5 5 3.6 1.4 0.2 setosa setosa
6 5.4 3.9 1.7 0.4 setosa setosa
7 4.6 3.4 1.4 0.3 setosa setosa
8 5 3.4 1.5 0.2 setosa setosa
9 4.4 2.9 1.4 0.2 setosa setosa
10 4.9 3.1 1.5 0.1 setosa setosa
# ... with 140 more rows

> iris %>% group_by(Species) %>% summarise(avg = mean(Sepal.Length))
# A tibble: 3 x 2
Species avg
<fct> <dbl>
1 setosa 5.01
2 versicolor 5.94
3 virginica 6.59

> iris %>% group_by(Species) %>% summarise(avg = mean(Sepal.Length)) %>% arrange(avg)
# A tibble: 3 x 2
Species avg
<fct> <dbl>
1 setosa 5.01
2 versicolor 5.94
3 virginica 6.59
  • 增加列
> x <- dplyr::mutate(iris,sum = iris$Sepal.Length+iris$Sepal.Width)
> head(x)
Sepal.Length Sepal.Width Petal.Length Petal.Width Species sum
1 5.1 3.5 1.4 0.2 setosa 8.6
2 4.9 3.0 1.4 0.2 setosa 7.9
3 4.7 3.2 1.3 0.2 setosa 7.9
4 4.6 3.1 1.5 0.2 setosa 7.7
5 5.0 3.6 1.4 0.2 setosa 8.6
6 5.4 3.9 1.7 0.4 setosa 9.3

4.dplyr包对于双表格的操作

> a <- data.frame(x1=c("A","B","C"),x2=c(1:3))
> b <- data.frame(x1=c("A","B","D"),x3=c(T,F,T))
> a
x1 x2
1 A 1
2 B 2
3 C 3
> b
x1 x3
1 A TRUE
2 B FALSE
3 D TRUE
> dplyr::left_join(a,b,by = "x1")#左连接
x1 x2 x3
1 A 1 TRUE
2 B 2 FALSE
3 C 3 NA
> dplyr::right_join(a,b,by = "x1")#右链接
x1 x2 x3
1 A 1 TRUE
2 B 2 FALSE
3 D NA TRUE
> dplyr::full_join(a,b,by = "x1")#取并集
x1 x2 x3
1 A 1 TRUE
2 B 2 FALSE
3 C 3 NA
4 D NA TRUE
> dplyr::semi_join(a,b,by = "x1")#取交集
x1 x2
1 A 1
2 B 2
> dplyr::anti_join(a,b,by = "x1")#取补集
x1 x2
1 C 3

5 几个数据集运算

> frist <- mtcars[1:4,]
> second <- mtcars[2:6,]
> intersect(frist,second)#取交集
mpg cyl disp hp drat wt qsec vs am gear carb
Mazda RX4 Wag 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4
Datsun 710 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1
Hornet 4 Drive 21.4 6 258 110 3.08 3.215 19.44 1 0 3 1
> dplyr::union(frist,second)#取并集
mpg cyl disp hp drat wt qsec vs am gear carb
Mazda RX4 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4
Mazda RX4 Wag 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4
Datsun 710 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1
Hornet 4 Drive 21.4 6 258 110 3.08 3.215 19.44 1 0 3 1
Hornet Sportabout 18.7 8 360 175 3.15 3.440 17.02 0 0 3 2
Valiant 18.1 6 225 105 2.76 3.460 20.22 1 0 3 1
> setdiff(frist,second)#取补集
mpg cyl disp hp drat wt qsec vs am gear carb
Mazda RX4 21 6 160 110 3.9 2.62 16.46 0 1 4 4
> setdiff(second,frist)#取补集
mpg cyl disp hp drat wt qsec vs am gear carb
Hornet Sportabout 18.7 8 360 175 3.15 3.44 17.02 0 0 3 2
Valiant 18.1 6 225 105 2.76 3.46 20.22 1 0 3 1