R語言 tidyr包的三個重要函數:gather,spread,separate的用法和舉例

tidyr是Hadley(Tidy Data的作者Hadley Wickham)寫的非常有用、並且經常會使用到的包,常與dplyr包結合使用(這個包也是他寫的)

準備工作:

首先安裝tidyr包(一定要加引號,不然報錯)

install.packages("tidyr")

載入tidyr(可以不加引號)

library(tidyr)

gather()

gather函數類似於Excel(2016起)中的數據透視的功能,能把一個變量名含有變量的二維錶轉換成一個規範的二維表(類似數據庫中關係的那種表,具體看例子)

我們先  >?gather,看看官方文檔說明:

gather {tidyr}    R Documentation
Gather columns into key-value pairs.

Description

Gather takes multiple columns and collapses into key-value pairs, duplicating all other columns as needed. You use gather() when you notice that you have columns that are not variables.

Usage

gather(data, key = "key", value = "value", ..., na.rm = FALSE,
  convert = FALSE, factor_key = FALSE)
Arguments

data    
A data frame.
key, value    
Names of new key and value columns, as strings or symbols.
This argument is passed by expression and supports quasiquotation (you can unquote strings and symbols). The name is captured from the expression with rlang::ensym() (note that this kind of interface where symbols do not represent actual objects is now discouraged in the tidyverse; we support it here for backward compatibility).
...    (這是一個參數)
A selection of columns. If empty, all variables are selected. You can supply bare variable names, select all variables between x and z with x:z, exclude y with -y. For more options, see the dplyr::select() documentation. See also the section on selection rules below.
na.rm    
If TRUE, will remove rows from output where the value column in NA.
convert    
If TRUE will automatically run type.convert() on the key column. This is useful if the column types are actually numeric, integer, or logical.
factor_key    
If FALSE, the default, the key values will be stored as a character vector. If TRUE, will be stored as a factor, which preserves the original ordering of the columns.

說明:

第一個參數放的是原數據,數據類型要是一個數據框;

下面傳一個鍵值對,名字是自己起的,這兩個值是做新轉換成的二維表的表頭,即兩個變量名;

第四個是選中要轉置的列,這個參數不寫的話就默認全部轉置;

後面還可以加可選參數na.rm,如果na.rm = TRUE,那麼將會在新表中去除原表中的缺失值(NA)。

gather()舉例

先構造一個數據框stu:

stu<-data.frame(grade=c("A","B","C","D","E"), female=c(5, 4, 1, 2, 3), male=c(1, 2, 3, 4, 5))

這個數據框什麼意思就不說了,就是你想的那樣,成績-性別的人數分佈。

變量中的female和male就是上面所說的變量名中含有了變量,female和male應該是“性別”這個變量的的變量值,下面的人數的變量名(或者說屬性名)應該是“人數”,下面我們需要把原grade一列保留,去掉female和male兩列,增加sex和count兩列,值分別與原表對應起來,使用這個gather函數:

gather(stu, gender, count,-grade)

結果如下,行列就轉換過來了,第一個參數是原數據stu,二、三兩個參數是鍵值對(性別,人數),第四個表示減去(除去grade列,就只轉置剩下兩列)

在原表中單看這兩列是這樣對應的:

(female, 5), (female, 4), (female, 1), (female, 2), (female, 3)

(male, 1), (male, 2), (male, 3), (male, 4), (male, 5),

就是把原變量名(屬性名)做鍵(key),變量值做值(value)。

接下來就可以繼續正常的統計分析了。

separate()

separate負責分割數據,把一個變量中就包含兩個變量的數據分來(上例gather中是屬性名也是一個變量,一個屬性名一個變量),直接上例子:

separate()舉例

構造一個新數據框stu2:

stu2<-data.frame(grade=c("A","B","C","D","E"), 
                 female_1=c(5, 4, 1, 2, 3), male_1=c(1, 2, 3, 4, 5),
                 female_2=c(4, 5, 1, 2, 3), male_2=c(0, 2, 3, 4, 6))

跟上面stu很像,性別後面的1、2表示班級

我們先用剛纔的gather函數轉置一下:

stu2_new<-gather(stu2,gender_class,count,-grade)

不解釋了,跟上面一樣,結果如下:

但這個表仍然不是個規範二維表,我們發現有一列(gender_class)的值包含多個屬性(變量),使用separate()分開,separate用法如下:

separate(data, col, into, sep (= 正則表達式), remove =TRUE,convert = FALSE, extra = "warn", fill = "warn", ...)

第一個參數放要分離的數據框;

第二個參數放要分離的列;

第三個參數是分割成的變量的列(肯定是多個),用向量表示;

第四個參數是分隔符,用正則表達式表示,或者寫數字,表示從第幾位分開(文檔裏是這樣寫的:

If character, is interpreted as a regular expression. The default value is a regular expression that matches any sequence of non-alphanumeric values.
If numeric, interpreted as positions to split at. Positive values start at 1 at the far-left of the string; negative value start at -1 at the far-right of the string. The length of sep should be one less than into.)

後面參數就不一一說明了,可以自己看文檔

現在我們要做的就是把gender_class這一列分開:

separate(stu2_new,gender_class,c("gender","class"))

注意第三個參數是向量,用c()表示,第四個參數本來應該是"_",這裏省略不寫了(可能是下劃線是默認分隔符?)

結果如下:

spread()

spread用來擴展表,把某一列的值(鍵值對)分開拆成多列。

spread(data, key, value, fill = NA, convert = FALSE, drop =TRUE, sep = NULL)

key是原來要拆的那一列的名字(變量名),value是拆出來的那些列的值應該填什麼(填原表的哪一列)

下面直接上例子

spread()舉例

構造數據框stu3:

name<-rep(c("Sally","Jeff","Roger","Karen","Brain"),c(2,2,2,2,2))
test<-rep(c("midterm","final"),5)
class1<-c("A","C",NA,NA,NA,NA,NA,NA,"B","B")
class2<-c(NA,NA,"D","E","C","A",NA,NA,NA,NA)
class3<-c("B","C",NA,NA,NA,NA,"C","C",NA,NA)
class4<-c(NA,NA,"A","C",NA,NA,"A","A",NA,NA)
class5<-c(NA,NA,NA,NA,"B","A",NA,NA,"A","C")
stu3<-data.frame(name,test,class1,class2,class3,class4,class5)

總共5門課,每個學生選兩門,列出期中、期末成績。

顯然,原表是不整潔的數據,表頭中含有變量(class1-5),所以先用gather函數。注意,這裏面有很多缺失值,就可以用到上面所講的na.rm=TRUE參數,自動去除有缺失值的記錄(一條記錄就是一行):

如果不寫 na.rm=TRUE 的話,結果是這樣的:

(未截全)

分析學生沒選課的“NA”成績是沒有意義的,所以這個情況下應該捨棄有缺失值的記錄。

現在這個表看起來已經很整齊了,但是每個人都有四條記錄,其中每門課除了test和grade的值不一樣,姓名、課程是一樣的,並且很多時候,我們需要分別對期中、期末成績進行統計分析,那麼現在這個表就不利於做分類統計了。

用spread函數將test列分來成midterm和final兩列,這兩列的值是選的兩門課的成績。

再重複一遍,第二個參數是要拆分的那一列的列名,第三個參數是擴展出的列的值應該來自原表的哪一列的列名。

stu3_new<-gather(stu3, class, grade, class1:class5, na.rm = TRUE)
spread(stu3_new,test,grade)

結果如下:

現在得到非常整齊的僅有10條數據的表,處理起來會更加方便。

最後補充一條,現在class列顯得有些冗餘,直接用數字似乎更簡潔,使用readr包中的parse_number()提出數字(還用到了dplyr的mutate函數),下面放出代碼:

install.packages("dplyr")
install.packages("readr")
library(readr)
library(dplyr)
mutate(spread(stu3_new,test,grade),class=parse_number(class))

最終結果:

是不是整整齊齊很好看!!!(*╹▽╹*)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章