天天看點

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包

作者

:悅光陰

出處

:http://www.cnblogs.com/ljhdo/

本文版權歸作者和部落格園所有,歡迎轉載,但未經作者同意,必須保留此段聲明,且在文章頁面醒目位置顯示原文連接配接,否則保留追究法律責任的權利。