R實戰 第七篇:plyr包


在數據分析中,整理數據的本質可以歸納為:對數據進行分割(Split),然后應用(Apply)某些處理函數,最后將結果重新組合(Combine)成所需的格式返回,簡單描述為:Split - Apply - Combine,各個步驟的作用是:

  • Split:把要處理的數據分割成小片斷,常用的函數是split(),subset();
  • Apply:對每個小片斷獨立進行操作,常用的是apply家族函數,plyr包核心函數;
  • Combine:把片斷重新組合,常用的函數是unlist()函數。

這個過程可以通過Base包的apply家族函數來實現,apply家族函數包括了apply、sapply、lapply、tapply、aggregate等,可以應用於數據分析的各個階段。 

plyr包是apply家族函數的升級版本,使用plyr包可以實現:在一個函數內同時完成“Split - Apply - Combine”,並且,plyr包實現R類型(vector, list, data.frame)之間的分組變換,基本上可以取代Base包中的apply家族函數。

plyr包對核心函數的命名采用統一的格式:**ply,所有的函數名都由5個字符組成,且最后三個字符是ply,函數名的第一個字符代表輸入數據的類型,第二個字符代表輸出數據的類型,R類型的簡寫是:

  • d:data.frame
  • l:list
  • a:array,vector,matrix
  • r:代表replicate,重復多次
  • m:多輸入
  • _:舍棄輸出結果

這種統一的命名格式,使得plyr包的函數更容易記憶和使用,但是,plyr包不是預裝於R語言中,使用之前,需要加載和引用plyr包:

install.packages("plyr")
library(plyr)

一,plyr包函數

plyr包用於在R中實現split-apply-combine的模式,這中模式在數據分析中是極其常見的,通過把數據分解為小的分片,然后在分片上做操作,最后把結果組合在一起,以解決復雜的分析問題。因此,當遇到復雜的數據分析問題時,一般都需要把復雜的問題分組,然后在每個分組上做操作,最終把每個分組上的結果組合到一起。plyr包的函數很多,除了**ply的核心函數之外,還有一些輔助函數,在處理數據時,都十分有用。

1,ddply

plyr包中最常用的函數是ddply()函數,該函數對數據框進行操作,對每一行調用一個函數,並返回數據框類型:

ddply(.data, .variables, .fun = NULL, ...)

參數注釋:

  • .data:函數處理的數據框;
  • .variables:要進行拆分的變量名稱,傳遞變量的格式是: .(col_name),就是把進行分組的變量名包含在.()中;
  • .fun:應用到每行的函數
  • ...:傳遞到fun的其他參數

對於參數fun,有兩種賦值方式:

第一種: 如果使用colwise()函數,那么這使ddply函數把參數fun應用於每一列,除了參數.variable指定的數據列之外,例如:

ddply(diamonds,.(color),colwise(mean))

第二種: 使用summarize函數對指定的列執行操作,更為靈活,例如:

> ddply(diamonds,.(color),summarize,avg_price=mean(price),avg_carat=mean(carat))
  color avg_price avg_carat
1     D  3169.954 0.6577948
2     E  3076.752 0.6578667
.....

2,each函數

plyr包的each()函數,能夠把多個函數整合到一個函數中,每一個函數必須只能返回一個數值:

each(...)

使用each()函數,可以使函數aggregate()同時調用多個函數:

> aggregate(cbind(price,carat)~cut+color,diamonds,each(mean,sum))
         cut color   price.mean    price.sum   carat.mean    carat.sum
1       Fair     D     4291.061   699443.000    0.9201227  149.9800000
2       Good     D     3405.382  2254363.000    0.7445166  492.8700000
......

3,rename函數

按照名字對變量重命名:

rename(x, replace, warn_missing = TRUE, warn_duplicated = TRUE)

參數注釋:

  • x: 重命名的對象
  • replace:命名的向量,格式是:c(new_name=old_name,...)

使用rename函數對數據框的變量進行重命名,例如:

rename(mtcars, c("disp" = "displacement"))

4,arrange函數

按照數據框的變量對數據框排序,注意,arrange()函數不會保留行名稱(row.names)

arrange(df, ...)

例如,按照變量cyl和disp,對數據框mtcars進行排序:

# sort mtcars data by cylinder and displacement
mtcars[with(mtcars, order(cyl, disp)), ]
# Same result using arrange: no need to use with(), as the context is implicit
arrange(mtcars, cyl, disp)

5,mutate函數

對數據框進行轉換,或增加新的變量,或替換已經存在的變量,該函數和transfrom函數十分相似,不過,mutate()函數是遞進式的,這使得后期的轉換可以使用早期創建的變量。

# Things transform can't do
mutate(airquality, Temp = (Temp - 32) / 1.8, OzT = Ozone / Temp)

6,name_rows函數

在設計時,沒有plyr函數會保留行名稱(row names)。如果想保留行名稱,可以使用name_rows()把行名稱轉換為顯式的列值,在執行為相應的plyr操作之后,再使用name_rows把列值轉換為行名稱。

name_rows(df)

參數df :數據框對象,擁有 rownames,或者顯式的列名 .rownames

二,拆分-應用-組合

在R語言中,分組聚合可以通過三步實現:拆分-應用-合並(Split-Apply-Combine)。例如,對玩家的游戲成績進行統計和分析,創建示例數據:

> players_scores <- data.frame(
     player=rep(c('Tom','Dick','Jim'),times=c(2,5,3)),
     score=round(runif(10,1,100),-1)
 )

1,分組數據

計算每個玩家的平均得分,首先對玩家分組,需要用到split()函數,按照特定的字段對數據進行分組:

split(x, f, drop = FALSE, ...)

參數注釋:

  • x:數據框或向量,是被分組的數據;
  • f:因子類型,按照f對x進行分組;

函數的返回值是一個列表對象,每一個列表項都是包含分組數據的向量。

例如,split(score,player)函數的作用是按照player字段把數據框中的score拆分成一組,也就是說,player 相同的score是同一個分組,填充到同一個列表項中:

> (scores_by_player <- with(players_scores,split(score,player)))
$Dick
[1] 70 20 30 70 70

$Jim
[1] 80 90 50

$Tom
[1] 80 90

2,應用函數

當數據分割之后,對每個分組計算平均分。使用lapply()函數,對於每個列表項,應用mean()函數,計算單個列表項的平均值,例如:

list_mean_by_player <- lapply(scores_by_player,mean)

3,組合數據

組合數據是為了顯示數據,在顯示最終的數據時,通常把列表轉換為向量。lapply()函數返回的結果是一個列表對象,每一個列表項都是一個向量,因此可以使用unlist()函數,把列表轉換為向量,例如:

> unlist(list_mean_by_player)
    Dick      Jim      Tom 
52.00000 73.33333 85.00000 

三,使用apply家族函數實現分組聚合

在apply家族函數中,每個函數都用於特定的數據類型:

  • apply函數只能用於矩陣,
  • lapply函數能夠用於向量和列表(list),其工作原理是把一個函數應用於一個列表中的每個元素上,並且把結果作為列表返回;
  • sapply處理列表,返回向量。
  • mapply函數,把調用的函數應用到多個列表的每一個元素中。
  • tapply函數用於分組聚合運算,在研究數據時,有時需要對數據按照特定的字段進行分組,然后統計各個分組的數據,這就是SQL語法中的分組聚合。

在數據分析中,使用Base包實現”拆分-應用-合並“ 顯得十分繁瑣,可以使用tapply()函數一次完成所有的三個步驟,一氣呵成:

with(players_scores,tapply(score,player,mean))

tapply()函數常用的參數共有三個,第一個參數是數據框對象或向量,第二個參數是因子列表,也就是分組字段,第三個參數是指對單個分組應用的函數:

tapply(X, INDEX, FUN = NULL, ...)

by()函數和aggregate()函數是tapply()函數的包裝函數,功能相同,接口稍微不同。

by(data, INDICES, FUN, ..., simplify = TRUE)
aggregate(x, by, FUN, ..., simplify = TRUE, drop = TRUE)

四,使用plyr包實現分組聚合

函數daply的作用是分割數據框,對每個分組應用聚合函數,最后把每個分組的聚合值組合起來,以數組的形式返回:

daply(.data, .variables, .fun = NULL, ...)

參數注釋:

  • .data:數據框,存儲用於分析的數據;
  • .variables:分組字段,指定分組字段的格式是  .(col_name);
  • .fun:應用於每個分組的函數,有兩種方式,上文有詳細介紹。

為了計算每個player的平均得分,可以使用daply()函數,例如,

unlist(daply(players_scores,.(player),summarize,varScore=mean(score)))

在示例中,daply()函數返回的類型是list,通過unlist()函數轉換為向量。至於為什么返回的是list,而不是數組,我也很疑惑。

 

參考文檔:

plyr reference manual

R語言-數據整形之plyr包 R語言中plyr包


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM