在資料分析中,整理資料的本質可以歸納為:對資料進行分割(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/
本文版權歸作者和部落格園所有,歡迎轉載,但未經作者同意,必須保留此段聲明,且在文章頁面醒目位置顯示原文連接配接,否則保留追究法律責任的權利。