之前我们详细的学习了reshape2包,在数据处理阶段,它帮助我们很容易的实现长宽格式数据之间的转换。而今天所要学习的tidyr包可以看作是reshape2包的进化版本,该包的作者依旧是Rstudio的首席科学家,R语言界的大神Hadley Wickham。tidyr包往往与dplyr包结合使用,目前渐有取代reshape2包之势, 是值得关注的一个R包。
在tidyr包中,有四个常用的函数,分别是:
接下来我们主要对这四个函数进行详细学习,并在此基础上学习tidyr包其他的一些实用功能。
导入所用的包
> 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水平保持不变)
数据转换的示意图:
首先我们先查看原始数据:
> 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(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
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
在学习了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
附学习文档:
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!