《R语言数据分析》——3.2 聚集
本節書摘來自華章出版社《R語言數據分析》一書中的第3章,第3.2節,作者蓋爾蓋伊·道羅齊(Gergely Daróczi),潘怡 譯,更多章節內容可以訪問云棲社區“華章計算機”公眾號查看。
3.2 聚集
最直接的數據匯總方法應該是調用stats包的aggregate函數,該函數能支持以下我們期望的功能:通過分組變量將數據劃分成不同的子集,并分別對這些子集進行統計匯總。調用aggregate函數的最基本方法之一是傳遞待聚集的數值向量,以及一個因子變量,該因子變量將定義參數FUN的值,以確定劃分函數。下面的樣例中,我們以每個工作日航班平均轉飛率作為劃分依據:
當然,我們需要一定時間來執行上述分析,不過別忘了我們剛剛處理的是將近25萬行數據,以分析2011年從休斯頓機場出發的航班日均轉非率。
換句話說,這個結果對那些沒有納入日均轉飛率統計的數據一樣有意義,例如,從結果可知,一周中周三、周四這兩天的航班轉飛率(0.3%左右)比周末的航班轉飛率(0.25%左右)更高一些,至少從休斯頓機場出發的航班是這種情況。
另外一種類似調用上述函數的方法是使用with函數,使用with函數的語法看起來更容易理解一些,因為在with函數里,我們不用重復地引用hflights數據庫:
執行結果因和上一種方法完全一致就不再重復顯示了。從aggregate函數的指南(參見?aggregate)可知其返回結果比較容易理解。不過,如果要從結果中查看返回數據列名并不容易?我們可以通過使用公式化的標記而不是像之前樣例那樣采用直接定義數值和因子變量的方法來解決這個問題:
使用公式化標記的好處是兩方面的:
輸入的字符相對較少
結果中顯示的行名稱是正確的
函數執行的結果相對之前的函數調用方法要更快一點,請參考3.3節相關內容。
使用公式化標記的唯一不利因素就是我們必須首先掌握這種方法,盡管該方法乍看起來稍顯笨拙,但由于很多R函數和包都可以運用這種標記方式,特別是在定義模型的時候,因此毫無疑問從長遠角度出發有必要了解好掌握該方法。
公式化標記是從S語言繼承下來的,常見語法形式為:response_variable~predictor_variable_1 + … + predictor_variable_n。該標記也包括一些其他記號,例如用“-”去掉變量,用“:”或“*”來包含變量間的相互作用。參見本書第5章建模(由Renata Nemeth和Gergely Tot授權閱讀),以及在R控制臺使用?formula命令獲得更多細節內容。
3.2.1 使用基礎的R命令實現快速聚集
還可以通過調用函數tapply或函數by來實現數據聚集,這些方法可以在一個不規則的矩陣上應用R函數。這也意味著我們能夠提供一個或多個INDEX變量,這些變量能被強制轉換為因子,然后,將相關R函數分別應用于每個數據子集的所有單元上。下面是一個簡單的樣例說明:
請注意函數tapply返回的是一個array對象,而不是常見的數據框對象。換句話說,也即該函數的執行速度比前面介紹過得的函數都要快。因此,首先使用tapply函數完成計算過程,再將結果增加合適的列名轉換為data.frame對象是可行的。
3.2.2 方便的輔助函數
上述轉換過程可以很容易地以一種用戶容易理解的方式完成,例如,plyr包(dplyr包更常見的一種形式)就是為數據框開發的特殊plyr版本(plyr specialized for data frames)。
plyr包提供了非常多的函數來處理data.frame、list或array類型的對象,返回結果也支持以上各種數據類型。這些函數的命名規則非常容易記憶:函數名的第一個字符代表輸入數據的類別,第二個字符代表輸出格式,所有的情況都以ply結尾。除了前面提到的三種R數據類型,還存在一些特殊的字符定義:
d代表data.frame
s代表array
l代表list
m為一種特殊的輸入類型,它意味著我們以表格方式為函數提供了多個參數
r代表函數希望輸入一個整數,以指明函數將要復制的次數
_是一種特殊的輸出類型,此時函數將不返回任何結果
以下最常見的組合分別代表著:
ddply以data.frame為輸入,返回也為data.frame
ldply以list為輸入,返回data.frame
l_ply不返回任何結果,但是在某些情況下非常有用。例如,基于一定元素遞歸而不使用for循環;作為.progress參數,可以獲得當前迭代狀態以及剩余時間。
可以在本書第4章找到更多關于plyr包的樣例以及用戶案例。本章,我們僅關注用該包完成數據統計。接下來,我們將在所有樣例中使用ddply(不要與dplyr包混淆)包:采用data.frame框架作為輸入參數,返回數據也是data.frame類型。
裝載包,并將mean函數作用于由DayofWeek劃分的數據子集的Diverted列:
plyr包的.函數為用戶提供了一種方便的引用變量(名稱)的方法。否則,ddply包將采用其他方式來解釋DayofWeek列的內容,導致錯誤。
這里要說明的重要一點是ddply比之前我們用過的aggregate函數速度更快。但從其他方面而言,我對這個結果還并不十分滿意,輸出結果使用了V1這樣的列名,讓我有些受不了。這里我們不再進行更新data.frame的名稱這樣的再加工,而是調用summarise輔助函數來替代上面用的匿名函數,然后再顯式指定相應的列名:
好了,看起來像樣多了,不過我們還能做得更好嗎?
3.2.3 高性能的輔助函數
Hadley Wickham是ggplot、reshape和其他一些R開發包的作者,自2008年起開發了plyr包的第二代也可以說是特定版本。最基本的起因在于plyr包經常被用于將一類data.frame數據轉換成另一類data.frame數據,因此對它的應用需要特別小心。dplyr包是專門針對數據框應用開發的plyr定制版,實現速度更快,開發語言為C++,dplyr包還支持遠程數據庫。
不過,函數執行效率還是根據具體情況不同而變化。例如,dplyr包的語法與plyr包相比,就有非常大的改變。盡管前面提到的summarise函數在dplyr包里也可以使用,但dplyr包中已經沒有單獨的ddplyr函數,在dplyr包中所有的函數都是以plyr::ddplyr的組件身份執行的。
無論如何,為了不讓理論知識太過復雜,如果希望對某個數據集的子集進行匯總,我們首先要在聚集操作之前定義好分組:
結果對象和data.frame非常類似,只有一點不同:元數據將根據屬性的平均值合并到對象中。為了讓輸出結果短一點,我們不會展示對象的整個數據結構(str),只顯示其屬性:
從輸出的元數據可知,屬性indicies很重要,它包含了每周中每天記錄的ID,這樣接下來的操作就能很容易地從整個數據集中選擇所需的子集。下面,讓我們看一下通過使用dplyr包的summairse函數而非plyr在提高操作性能后,轉飛航班的比率:
結果差不多,哪個更好呢?讀者們有沒有比較兩種方法執行時間的差別?鑒于這些細微的差別,我們知道dplyr包效率更好。
3.2.4 使用data.table完成聚集
讀者們還記得[.data.table的第二個參數嗎?我們稱之為j,該參數包含了一個SELECT或UPDATE功能的SQL語句,其最重要的特性就是支持R表達式。因此,我們可以不使用函數,而是借助by參數來實現分組。
如果不希望采用V1來為結果表格的第二列數據命名,可以將summary對象指定為一個命名list,例如,hf?lights_dt[, list('mean(Diverted)'= mean(Diverted)), by = DayOfWeek],我們可以使用符號“.”而非list,就像在plyr包中的方法一樣。
除了將結果按期望順序排序,在現有鍵值列上進行數據統計速度也相對較快,下面我們將用一些實際案例對此進行說明。
總結
以上是生活随笔為你收集整理的《R语言数据分析》——3.2 聚集的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 《黑客秘笈——渗透测试实用指南》—第2章
- 下一篇: 《Android游戏编程入门经典》——1