R语言宽型与长型数据转换tidyr包

R语言长型数据转换tidyr包

前言

之前我们详细的学习了reshape2包,在数据处理阶段,它帮助我们很容易的实现长宽格式数据之间的转换。而今天所要学习的tidyr包可以看作是reshape2包的进化版本,该包的作者依旧是Rstudio的首席科学家,R语言界的大神Hadley Wickham。tidyr包往往与dplyr包结合使用,目前渐有取代reshape2包之势, 是值得关注的一个R包。

在tidyr包中,有四个常用的函数,分别是:

  • gather():宽数据转换为长数据,将行聚集成列
  • spread():长数据转换为宽数据,将列展开为行
  • unite():多列合并为一列
  • separate():将一列分离为多列.

接下来我们主要对这四个函数进行详细学习,并在此基础上学习tidyr包其他的一些实用功能。



一、gather()函数

导入所用的包

> library(dplyr)
> library(tidyr)

如前面所说,gather()函数是将宽数据转换为长数据,调用公式如下:

> gather(data=,key=,value=,...,na.rm=,convert=,factor_key=)
# key:创建一个新的列名,原数据的旧列名成为新列名的观测值
# value:再创建一个新的列名,原数据的所有旧列名的观测值成为新列名的观测值
# ...:按照实际需要自行指定需要转换的列
# na.rm:逻辑值,是否删除缺失值
# convert:逻辑值,在key列是否进行数据类型转换
# factor_key:逻辑值,若是F,则key自动转换为字符串,反之则是因子(原始lever水平保持不变)

数据转换的示意图:


attachments-2021-05-OcGdSnan60a66e9c4ff3c.png


首先我们先查看原始数据:

> head(iris,3)
  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

使用gather()函数进行数据重塑(代码中'%>%'为管道函数,这也是我们为什么要载入dplyr包的原因,关于管道函数,详见R Language Learning:dplyr包(十一)

> iris %>%
+ gather(key=var1,value = var2,...=1:4,na.rm = F) %>%
+ arrange(desc(var2)) %>%
+ head(3)
       Species         var1 var2
1    virginica Sepal.Length  7.9
2    virginica Sepal.Length  7.7
3    virginica Sepal.Length  7.7


二、spread()函数

spread()函数将长数据转为宽数据,即将列展开为行,调用公式如下:

> spread(data = ,key = ,value = ,fill = ,convert = ,drop = )
# key:指定转换的某列,其观测值作为转换后的列名
# value:其他列的观测值分散到相对应的各个单元
# fill:设定某个值,替换缺失值

我们使用R中的economics数据集来使用学习这一函数。

# 提取原数据集前三列
> data <- economics[1:3]
> head(data,3)
# A tibble: 3 × 3
        date   pce    pop
      <date> <dbl>  <int>
1 1967-07-01 507.4 198712
2 1967-08-01 510.5 198911
3 1967-09-01 516.3 199113
# 由于手边没有合适的长数据,所以我们先使用gather函数生成一份新的长数据,并假定我们要对这一份长数据进行列转行
> data %>%
+ gather(key=var1,value = var2,-date) %>%
+ head(3)
# A tibble: 3 × 3
         date  var1  var2
       <date> <chr> <dbl>
1  1967-07-01   pce 507.4
2  1967-08-01   pce 510.5
3  1967-09-01   pce 516.3
# -date:默认数据集中的date不做变化
# 使用spread()函数进行了长数据向宽数据的转换
# 原有的var1变量作为转换后的列名,var2变量值作为相应的观测值分散到各列
> data %>%
+ gather(key = var1,value = var2,-date) %>%
+ spread(key = var1,value = var2) %>%
+ head(3)
# A tibble: 3 × 3
         date   pce    pop
       <date> <dbl>  <dbl>
1  1967-07-01 507.4 198712
2  1967-08-01 510.5 198911
3  1967-09-01 516.3 199113


三、unit()函数

unite()函数是将数据框中多列合并为一列,调用公式如下:

> unite(data = ,col = ,... = ,sep = ,remove = )
# col:指定组合为新列的名字
# ...:指定数据中哪些列组合在一起
# sep:组合后新列中数据之间的分隔符
# remove:逻辑值,是否保留参与组合的列
# 数据准备
> date <- as.Date('2016-11-01') + 0:29
> hour <- sample(1:24,replace = TRUE,30)
> min <- sample(1:60,replace = TRUE,30)
> second <- sample(1:60,replace = TRUE,30)
> event <- sample(letters,30,replace = TRUE)
> data <- data.frame(date,hour,min,second,event)
> head(data,3)
        date hour min second event
1 2016-11-01   23  59     11     y
2 2016-11-02   21  12      4     u
3 2016-11-03    2  55     42     i

在这里,我们使用unite()函数将日期和时间数值合并到一列上。

# date和hour用空格连接
# datehour与时间数值用':'连接
> data %>%
+ unite(datehour,date,hour,sep=' ') %>%
+ unite(datetime,datehour,min,second,sep=':') %>%
+ head(3)
              datetime event
1  2016-11-01 23:59:1      y
2  2016-11-02 21:12:4      u
3  2016-11-03 2:55:42      i


四、separate()函数

在学习了unite()函数后,separate()函数就很好理解了,它的作用正好和unite相反,即将数据框中的某列按照分隔符拆分为多列,一般用于时间序列的拆分,调用公式如下:

> separate(data = ,col = ,into = ,sep = ,remove = ,
+ convert = ,extra = ,fill = ,...)
# col:待拆分的某列
# into:定义拆分后新的列名
# sep:分隔符
# remove:逻辑值,是否删除拆分后的列

我们使用上一节得到的时间数据集,定义为data_unite,并对它进行拆分

# 先拆分日期和时间,在对时间进行细拆分
> data_unite %>%
+ separate(datetime,c('date','time'),sep=' ') %>%
+ separate(time,c('hour','min','second'),sep=':') %>%
+ head(3)
         date hour min second event
1  2016-11-01   23  59      1     y
2  2016-11-02   21  12      4     u
3  2016-11-03    2  55     42     i


五、缺失值的简单补齐

> library(readxl)
> data <- read_excel('data.xlsx')
> data
# A tibble: 8 × 2
   type   num
  <chr> <dbl>
1     a    75
2     b    72
3  <NA>    66
4     a    NA
5     c    69
6     b    65
7     a    72
8     c    NA

从上面的数据中,我们可以看到类型与数值都存在缺失值。对于类型的缺失值,我们选择众数替换,对于数值型的缺失值,我们选择均值替换(也可选择中位数等,视具体情况而定)

> num_mean <- mean(data$num, na.rm = TRUE)
> type_mode <- as.character(data$type[which.max(table(data$type))])
> data <- replace_na(data = data, replace = list(num = num_mean, 
+ type = type_mode))
> data
# A tibble: 8 × 2
   type      num
  <chr>    <dbl>
1     a 75.00000
2     b 72.00000
3     a 66.00000
4     a 69.83333
5     c 69.00000
6     b 65.00000
7     a 72.00000
8     c 69.83333


附学习文档:

  1. Introducing tidyr
  2. tidyr包--数据处理包
  3. Data manipulation with tidyr
  4. Data Processing with dplyr & tidyr
  5. Easily tidy data with spread and gather functions
  • 发表于 2021-05-20 22:15
  • 阅读 ( 4552 )
  • 分类:R

0 条评论

请先 登录 后评论
omicsgene
omicsgene

生物信息

654 篇文章

作家榜 »

  1. omicsgene 654 文章
  2. 安生水 325 文章
  3. Daitoue 167 文章
  4. 生物女学霸 120 文章
  5. 红橙子 78 文章
  6. CORNERSTONE 72 文章
  7. rzx 67 文章
  8. xun 66 文章