数据清洗与管理之dplyr、tidyr

2019-06-20 11:58:32 浏览数 (1)

本期回顾

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 二维数组行列引用

代码语言:javascript复制
> 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

数据集管理中,首先必须懂“对指定维度数据的引用”

例如:引用第一行数据,引用第一列数据,引用第一行第一列的数据。

代码语言:javascript复制
> data(iris) #鸢尾花数据集
> dim(iris) #读取iris数据集的维度数值,以“行数 列数 ”形式展示
[1] 150   5   
#说明iris数据集是150 x 5的二维数组

通过行列值引用:数据集[行值,列值]

如行值或列值仅1个数字,表示仅引用该行或列的数据

代码语言:javascript复制
> 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

如行值或列值为组合数据,则表示引用组合行列交叉位置的数据

代码语言:javascript复制
> 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

通过变量名引用(多用于二维数组中):数据集$变量名

代码语言:javascript复制
> head(iris$Petal.Length,5)
[1] 1.4 1.4 1.3 1.5 1.4

1 创建新变量

在R语言中,可以通过变量计算/分布函数等生成数据,并赋值给特定变量。

代码语言:javascript复制
> 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
 [41] 2.833333 2.266667 2.533333 2.833333 2.966667 2.600000 2.966667 2.600000
 [49] 3.000000 2.766667 3.400000 3.200000 3.333333 2.600000 3.100000 2.833333
 [57] 3.200000 2.433333 3.166667 2.633333 2.333333 2.966667 2.733333 3.000000
 [65] 2.833333 3.266667 2.866667 2.833333 2.800000 2.700000 3.033333 2.966667
 [73] 2.933333 2.966667 3.100000 3.200000 3.200000 3.233333 2.966667 2.766667
 [81] 2.633333 2.633333 2.833333 2.900000 2.800000 3.133333 3.266667 2.866667
 [89] 2.866667 2.666667 2.700000 3.033333 2.800000 2.433333 2.766667 2.900000
 [97] 2.866667 3.033333 2.533333 2.833333 3.200000 2.833333 3.366667 3.066667
[105] 3.166667 3.533333 2.466667 3.400000 3.066667 3.600000 3.233333 3.033333
[113] 3.266667 2.733333 2.866667 3.200000 3.166667 3.833333 3.433333 2.733333
[121] 3.366667 2.800000 3.500000 3.000000 3.333333 3.466667 3.000000 3.033333
[129] 3.066667 3.400000 3.400000 3.900000 3.066667 3.033333 2.900000 3.566667
[137] 3.233333 3.166667 3.000000 3.333333 3.266667 3.333333 2.833333 3.333333
[145] 3.333333 3.233333 2.933333 3.166667 3.200000 2.966667

算术运算符

  • (加)
  • -(减)
  • *(乘)
  • /(除)
  • ^或 ** (求幂)
  • x%%y (求余)
  • x%/%y (商,整数)

2 变量重新编码

可用于将连续数据编码为分组数据,或者替代异常值等

在R中重新编码数据常用逻辑运算符,通过TRUE/FALSE等返回值,确定编码的位置。

代码语言:javascript复制
> 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

同一变量分层编码

代码语言:javascript复制
> 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()函数重命名变量

代码语言:javascript复制
> 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()

代码语言:javascript复制
> 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包的下述五个函数用法【高级数据管理包】

代码语言:javascript复制
# 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()

代码语言:javascript复制
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()

代码语言:javascript复制
arrange(mtcars_df, disp) #可对列名加 desc(disp)进行降序

5.3 选择: select()

代码语言:javascript复制
> 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
 5  360    175  3.15  3.44
 6  225    105  2.76  3.46
 7  360    245  3.21  3.57
 8  147.    62  3.69  3.19
 9  141.    95  3.92  3.15
10  168.   123  3.92  3.44
# ... with 22 more rows

5.4 变形: mutate()

代码语言:javascript复制
#取行
#取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()

代码语言:javascript复制
#对数据框调用其它函数进行汇总操作
summarise(mtcars_df,mdisp = mean(disp, na.rm = TRUE))

5.6 分组: group_by()

%>% 是管道函数,将左侧数据结果传递到右侧,作为右侧处理的原始数据

代码语言:javascript复制
#当对数据集通过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包的下述四个函数用法

代码语言:javascript复制
#install.packages("tidyr") #安装tidyr包
library(tidyr)

6.1 宽数据转为长数据:gather()

类似excel透视表反向操作

代码语言:javascript复制
#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透视表操作

代码语言:javascript复制
#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()

代码语言:javascript复制
#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()

代码语言:javascript复制
#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参考鸿燕藏锋博客

0 人点赞