原创: 拴小林 数据驱动实践 6月11日
原文:R语言数据管理与dplyr、tidyr | 第4讲
往期回顾
R语言 | 第一部分:数据预处理
R语言|第2讲:生成数据
R语言常用的数据输入与输出方法 | 第三讲
目录
0 二维数组行列引用
1 创建新变量
2 变量重新编码
3 变量重新命名
4 缺失值
5 dplyr包的下述五个函数用法
5.1 筛选: filter
5.2 排列: arrange
5.3 选择: select
5.4 变形: mutate
5.5 汇总: summarise
5.6 分组: group_by
6 tidyr包的下述四个函数用法
6.1 宽数据转为长数据:gather (excel透视表反向操作)
6.2 长数据转为宽数据:spread (excel透视表功能)
6.3 多列合并为一列:unit
6.4 将一列分离为多列:separat
正文
先前已经讲过R语言生成测试数据、数据预处理和外部数据输入等内容,但这仅仅是第一步,我们还需要对数据集进行筛选、缺失值处理等操作,以便获得可以应用于建模或者可视化的数据集(变量)。接下来就以鸢尾花测试数据集进行进一步的数据管理和筛选操作。
0 二维数组行列引用
> data(iris)
> head(iris,5) #显示前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
数据集管理中,首先必须懂“对指定维度数据的引用”。例如:引用第一行数据,引用第一列数据,引用第一行第一列的数据。
> data(iris) #鸢尾花数据集
> dim(iris) #读取iris数据集的维度数值,以“行数 列数 ”形式展示
[1] 150 5
#说明iris数据集是150 x 5的二维数组
通过行列值引用:数据集[行值,列值]
如行值或列值仅1个数字,表示仅引用该行或列的数据
> iris[1,] #引用第1行数据
Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1 5.1 3.5 1.4 0.2 setosa
> head(iris[,1],5) #引用第1列的数据,其中因数据过长,使用head()函数取前5个数字
[1] 5.1 4.9 4.7 4.6 5.0
如行值或列值为组合数据,则表示引用组合行列交叉位置的数据
> iris[1:5,1:3]
Sepal.Length Sepal.Width Petal.Length
1 5.1 3.5 1.4
2 4.9 3.0 1.4
3 4.7 3.2 1.3
4 4.6 3.1 1.5
5 5.0 3.6 1.4
通过变量名引用(多用于二维数组中):数据集$变量名
> head(iris$Petal.Length,5)
[1] 1.4 1.4 1.3 1.5 1.4
1 创建新变量
在R语言中,可以通过变量计算/分布函数等生成数据,并赋值给特定变量。
> x <- (iris$Sepal.Length+iris$Sepal.Width)/3
> x
[1] 2.866667 2.633333 2.633333 2.566667 2.866667 3.100000 2.666667 2.800000
[9] 2.433333 2.666667 3.033333 2.733333 2.600000 2.433333 3.266667 3.366667
[17] 3.100000 2.866667 3.166667 2.966667 2.933333 2.933333 2.733333 2.800000
[25] 2.733333 2.666667 2.800000 2.900000 2.866667 2.633333 2.633333 2.933333
[33] 3.100000 3.233333 2.666667 2.733333 3.000000 2.833333 2.466667 2.833333
……省略部分内容
算术运算符
+(加)
-(减)
*(乘)
/(除)
^或 ** (求幂)
x%%y (求余)
x%/%y (商,整数)
2 变量重新编码
可用于将连续数据编码为分组数据,或者替代异常值等。在R中重新编码数据常用逻辑运算符,通过TRUE/FALSE等返回值,确定编码的位置。
> df <- iris
#将Petal.Length列等于1.4的位置重新编码为“”
> df$Petal.Length[df$Petal.Length == 1.4] <- ""
> head(df,10)
Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1 5.1 3.5 0.2 setosa
2 4.9 3.0 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 0.2 setosa
6 5.4 3.9 1.7 0.4 setosa
7 4.6 3.4 0.3 setosa
8 5.0 3.4 1.5 0.2 setosa
9 4.4 2.9 0.2 setosa
10 4.9 3.1 1.5 0.1 setosa
同一变量分层编码(iris原始数据如下)
> df <- iris
> head(df,10) #编码前输出结果
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
7 4.6 3.4 1.4 0.3 setosa
8 5.0 3.4 1.5 0.2 setosa
9 4.4 2.9 1.4 0.2 setosa
10 4.9 3.1 1.5 0.1 setosa
> df <- within(df,{
+ Petal.Length[Petal.Length == 1.4] <- "一点四"
+ Petal.Length[Petal.Length == 1.3] <- "一点三"
+ Petal.Length[Petal.Length == 1.5] <- "一点五"})
> head(df,10) #重新编码后输出结果
Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1 5.1 3.5 一点四 0.2 setosa
2 4.9 3.0 一点四 0.2 setosa
3 4.7 3.2 一点三 0.2 setosa
4 4.6 3.1 一点五 0.2 setosa
5 5.0 3.6 一点四 0.2 setosa
6 5.4 3.9 1.7 0.4 setosa
7 4.6 3.4 一点四 0.3 setosa
8 5.0 3.4 一点五 0.2 setosa
9 4.4 2.9 一点四 0.2 setosa
10 4.9 3.1 一点五 0.1 setosa
3 变量重新命名
通过names()函数重命名变量
> df <- iris
> head(df,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
> names(df)[5] <- "testNAME"
> head(df,5)
Sepal.Length Sepal.Width Petal.Length Petal.Width testNAME
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
4 缺失值
针对数据集中的缺失值,可以通过重新编码处理,还可以直接删除缺失值/缺失值。删除缺失值行:na.omit()
> df <- matrix(c(1:5,NA,7:10),nrow=5)
> df
[,1] [,2]
[1,] 1 NA
[2,] 2 7
[3,] 3 8
[4,] 4 9
[5,] 5 10
> df <-na.omit(df)
> df
[,1] [,2]
[1,] 2 7
[2,] 3 8
[3,] 4 9
[4,] 5 10
attr(,"na.action")
[1] 1
attr(,"class")
[1] "omit"
5 dplyr包的下述五个函数用法【高级数据管理包】
install.packages("dplyr")
library(dplyr)
#使用datasets包中的mtcars数据集做演示,首先将过长的数据整理成友好的tbl_df数据:
> mtcars_df = tbl_df(mtcars)
> head(mtcars_df)
# A tibble: 6 x 11
mpg cyl disp hp drat wt qsec vs am gear carb
<dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 21 6 160 110 3.9 2.62 16.5 0 1 4 4
2 21 6 160 110 3.9 2.88 17.0 0 1 4 4
3 22.8 4 108 93 3.85 2.32 18.6 1 1 4 1
4 21.4 6 258 110 3.08 3.22 19.4 1 0 3 1
5 18.7 8 360 175 3.15 3.44 17.0 0 0 3 2
6 18.1 6 225 105 2.76 3.46 20.2 1 0 3 1
5.1 筛选: filter()
filter(mtcars_df,mpg==21,hp==110) #按给定的逻辑判断筛选出符合要求的子数据集
# A tibble: 2 x 11
mpg cyl disp hp drat wt qsec vs am gear carb
<dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 21 6 160 110 3.9 2.62 16.5 0 1 4 4
2 21 6 160 110 3.9 2.88 17.0 0 1 4 4
5.2 排列: arrange()
arrange(mtcars_df, disp) #可对列名加 desc(disp)进行降序
5.3 选择: select()
> select(mtcars_df, disp:wt) #用列名作参数来选择子数据集:
# A tibble: 32 x 4
disp hp drat wt
<dbl> <dbl> <dbl> <dbl>
1 160 110 3.9 2.62
2 160 110 3.9 2.88
3 108 93 3.85 2.32
4 258 110 3.08 3.22
# ... with 28 more rows
5.4 变形: mutate()
#取行
#取1:dim(mtcars_df)[1]行
mutate(mtcars_df, NO = 1:dim(mtcars_df)[1])
#数值重定义和赋值
#将Ozone列取负数赋值给new,然后Temp列重新计算为(Temp - 32) / 1.8
mutate(airquality, new = -Ozone, Temp = (Temp - 32) / 1.8)
5.5 汇总: summarise()
#对数据框调用其它函数进行汇总操作
summarise(mtcars_df,mdisp = mean(disp, na.rm = TRUE))
5.6 分组: group_by()
# %>% 是管道函数,将左侧数据结果传递到右侧,作为右侧处理的原始数据
#当对数据集通过group_by()添加了分组信息后,mutate(),arrange() 和 summarise() 函数会自动对这些 tbl 类数据执行分组操作。
cars <- group_by(mtcars_df, cyl)
countcars <- summarise(cars, count = n()) # count = n()用来计算次数
%>%管道函数,把相应的数据直接引用为右侧源数据集
countcars <- group_by(mtcars_df, cyl) %>% summarise(count = n())
6 tidyr包的下述四个函数用法
install.packages("tidyr") #安装tidyr包
library(tidyr)
6.1 宽数据转为长数据:gather()
类似excel透视表反向操作
#gather(data, key, value, …, na.rm = FALSE, convert = FALSE)
#data:需要被转换的宽形表
#key:将原数据框中的所有列赋给一个新变量key
#value:将原数据框中的所有值赋给一个新变量value
#…:可以指定哪些列聚到同一列中
#na.rm:是否删除缺失值
widedata <- data.frame(person=c('Alex','Bob','Cathy'),grade=c(2,3,4),score=c(78,89,88))
#widedata
# person grade score
#1 Alex 2 78
#2 Bob 3 89
#3 Cathy 4 88
longdata <- gather(widedata, variable, value,-grade)
#longdata
# person variable value
#1 Alex grade 2
#2 Bob grade 3
#3 Cathy grade 4
#4 Alex score 78
#5 Bob score 89
#6 Cathy score 88
6.2 长数据转为宽数据:spread()
类似excel透视表操作
#spread(data, key, value, fill = NA, convert = FALSE, drop = TRUE)
#data:为需要转换的长形表
#key:需要将变量值拓展为字段的变量
#value:需要分散的值
#fill:对于缺失值,可将fill的值赋值给被转型后的缺失值
stocks <- data.frame(
time = as.Date('2009-01-01') + 0:9,
X = rnorm(10, 0, 1),
Y = rnorm(10, 0, 2),
Z = rnorm(10, 0, 4)
)
stocksm <- stocks %>% gather(stock, price, -time)
#stocksm
# time stock price
#1 2009-01-01 X -1.6411394
#2 2009-01-02 X -0.2144050
#3 2009-01-03 X -1.0630161
stocksm %>% spread(stock, price)
# time X Y Z
#1 2009-01-01 -1.6411394 -5.2254532 7.5666852
#2 2009-01-02 -0.2144050 0.3570096 4.8142193
#3 2009-01-03 -1.0630161 -1.3085735 7.3624203
stocksm %>% spread(time, price)
6.3 多列合并为一列:unit()
#unite(data, col, …, sep = “_”, remove = TRUE)
#data:为数据框
#col:被组合的新列名称
#…:指定哪些列需要被组合
#sep:组合列之间的连接符,默认为下划线
#remove:是否删除被组合的列
wideunite<-unite(widedata, col = information, person, grade, score, sep= "-")
wideunite
# information
#1 Alex-2-78
#2 Bob-3-89
#3 Cathy-4-88
6.4 将一列分离为多列:separate()
#separate()函数可将一列拆分为多列,一般可用于日志数据或日期时间型数据的拆分,语法如下:
#separate(data, col, into, sep = “[^[:alnum:]]+”, remove = TRUE,
#convert = FALSE, extra = “warn”, fill = “warn”, …)
#data:为数据框
#col:需要被拆分的列
#into:新建的列名,为字符串向量
#sep:被拆分列的分隔符
#remove:是否删除被分割的列
widesep <- separate(wideunite, information,c("person","grade","score"), sep = "-")
widesep
# person grade score
#1 Alex 2 78
#2 Bob 3 89
#3 Cathy 4 88
dplyr和tidyr参考鸿燕藏锋博客