第四關作業(翻譯)

數據分析的」分組-應用-結合」策略

很多數據分析都會用到」分組,應用,結合」的策略,這種策略是將一個大的問題拆分成可處理的更小部分,單獨處理每一個小部分,最後將這些小的內容合併起來。因此本文介紹一種新的R包,該方法能夠處理各種格式的數據。本文用兩個例子介紹這種方法,一個是基於過去擊球次數判斷棒球選手的能力,另外一個是利用空間溫度的3D模型估計臭氧層含量。本文所用的所有代碼都在網上的附加材料里。

1 引言

我們做數據分析做什麼?什麼是一般步驟,什麼是一般經常犯的錯誤?由於數據分析的重要性,因此有很多關於如何進行數據分析的研究。本文介紹一種非常簡單的數據分析方法「分組,應用,結合,」這是將大的問題拆分為小問題,然後獨立解決每一個小問題,最後再把小的數據塊結果組合在一起。下面列出分析的所有步驟:

1 數據準備,比如分組排序、標準化、或者進行新變數計算。

2 分析結果呈現,比如計算單側均值、計算分組總數。

3 模塊化,把單獨的模型應用於多個數據模塊。這些模型可以應用於原來的數據,也能用來組成更加複雜的遺傳模型。

當「分組,應用,結合」策略有用的時候就記錄下來,這能幫我們處理相似問題,而這些問題在之前卻被忽視。這樣就能把更多精力用到新問題上。這種策略已經有一些:APL』S 分組策略、Excel表、SQL分組運算、以及SAS程序。然而,利用軟體進行計算是更好的一種方式,將概念和計算結合在一起減少認知障礙。本文介紹一種應用這種策略的R包「plyr」

通常情況下,「plyr」包能夠提供處理一系列問題的簡便演算法,避免計算數據結構相關的細節問題。有些不必要的循環沒必要調用,因為這些循環很慢,但是他們沒有被清晰的定義,重要的和不重要的混在一起了。」plyr」包主要就是減少這些不必要的代碼,同時闡明計算的主要部分。

為了促進」plyr」的使用和發展,第2部分比較了plyr的代碼和基礎R代碼的差異。第3部分介紹plyr工具包家族,介紹三種輸入和四種輸出方式,輸入方式是分開的,輸出方式是重新結合的。第4部分「plyr」包也提供了幫助功能,包括錯誤矯正,拋雪球演算法、列處理、進度報告。第5部分討論這些功能的實現,包括探究棒球選手的表現,臭氧層時空變化規律等。第6部分介紹」plyr」包相似的R基礎功能以及相關的安裝包。第7部分介紹「plyr」包的未來計劃。

這篇文章介紹「plyr』包的0.1.8版本。需要R2.8.1以後的版本,並沒有實時執行依賴。「plyr」包的最新信息可以在plyr 上找到。在R中安裝」plyr」可以通過install.packages(「plyr」)實現。本文所用的代碼都已經上傳到附件。

注意: 數組包括一維的向量和二維的矩陣。數組能夠由很小的向量產生,包括邏輯型、字元型、整數型、數值型。一個列表數組就是一個非原子陣列(有範圍的列表),可能包括任何數據結構類型,比如線性模型或者2D kernel 密度估計。基本標籤設置,數組的dimnames(),數據框和矩陣的rownames()及colnames(),原子向量和列表的names()

2 動機

怎麼才能讓這種策略起作用?「plyr」包在循環和內置功能方面的優勢是什麼?因此比較plyr包和基礎R功能在例5.2中的實現差異,採集臭氧層24x24個網格的數據,每個月拍攝衛星照片,連續測量6年的數據從而去除季節的影響。一共41472個觀察數據,儲存在24x24x72的數組中,其中一個位置有72(6x12mon)個值。

通過線性模型的殘差估計,我們可以粗略的描述一個位置的信息。

One<-ozone[1,1,]Month<-ordered(rep(1:12,length=72))Model<-rlm(one~month-1)Deseas<-resid(model)Deseasf<-function(value)rlm(value~month-1)

一個限制因素就是把這個功能用到每一個位點,按照輸入方式重組輸出結果(一個三維數組)。把模型輸出為2維表也是很好的方式,因此我們可以參考模型信息(model[[1,1]])對臭氧層信息進行計算(ozone[1,1,])。保持數據結構的一致性能夠減少認知障礙。基礎R包中,我們可以用循環和應用函數處理這些問題。

循環:

Models<-as.list(rep(NA,24*24))Dim(models)<-c(24,24)Deseas<-array(NA,c(24,24,72))Dimnames(deseas)<-dimnames(ozone)For (I in seq_len(24)){ For (j in seq_len(24)){ Mod<-deseasf(ozone[I,j, ]) Models[[I,j]]<-mod Deseas[I,j]<-resid(mod) }}

應用函數:

Model<-apply(ozone,1:2,deseasf)Resides<-unlist(lapply(models,resid))Dim(resides)<-c(72,24,24)Deseas<-aperm(resids,c(2,3,1))Dimnames(deseas)<-dimnames(ozone)

For 循環最主要的劣勢是很多記賬式的代碼:數組的規模很難在多個位置編碼,同時在填充數據之前需要創建輸出結構。應該函數,apply()和lapply(), 能夠簡化任務流程,但是並沒有二維數組轉換為三維數組的直接方法。在plyr 包中,代碼非常短,因為以下細節需要注意:

Models<-aaply(ozone,1:2,deseasf)Deseas<-aaply(models,1:2,resid)

這些代碼都是什麼意思呢?所有的plyr功能有一個簡潔但是信息豐富的命名策略,第一個和第二個字元描述輸入和輸出數據類型,輸入決定怎麼拆分數據,輸出決定怎麼合併數據,這兩個函數用來輸入和輸出數組。其他數據類型是列表和數據框。因為「plyr「包能夠保證輸入和輸出以一致的方式進行,因此對於給定的問題使用這種數據結構就會很容易。

例如,不必用三維數組儲存臭氧層數據,而是用數據框儲存。如果數據是參差不齊的、非不規則的、或者不完整的,這種格式就會很合適,如果我們沒有在每一個時間點、每一個位置都測定的話就會有這種情況。想像一個名為ozonedf的數據框,列名為1at,long,time,month, value.。為了去除季節因素的干擾,我們首先需要調整方法把一個數據框作為輸入對象:

deseasf_df<-function(df){ rlm(value~month-1,data=df)}

因為數據是參差不齊的,因此很難使用for循環,我們使用split(),lapply()和mapply()函數解決這個問題。這裡」分組-應用-結合「策略在R基礎函數中已經存在:用split()函數拆分,用lapply()函數應用,最後使用rbind()函數結合為一個數據框。

Pieces<-split(ozonedf,list(ozonedf$lat,ozonedf$long))Models<-lapply(pieces,deseasf_df)Results<-mapply(function(model,df){ cbind(df[rep(1,72),c(「lat」,」long」)],resid(model))},models,pieces)Deseasdf<-do.call(「rbind」,results)

大部分的混雜是是標籤問題:我們使用mapply()函數把數據匹配到模型中,「plyr」包為我們省去了所有的複雜標籤,因此僅僅兩行就行。

Models<-dlply(ozonedf,.(lat,long), deseasf_df)Deseas<-ldply(models,resid)

Dlply包輸入一個數據框,返回一個列表,而ldply包正相反:它輸入一個列表輸出一個數據框。比較這個代碼和存儲數組時使用的代碼間的區別。

後面是「plyr」包的細節描述。如果你被這個例子吸引,你可以直接跳到後面學習這個例子,其中包括移除」季節作用「前後的一些細節。

3 使用方法

表1列出了」plyr」包的基本函數。每個函數都是以輸入和輸出內容的類型命名的:a=array,d=data frame, l=list, and_=nothing。輸入的類型決定了大的數據結構怎麼拆分成小的部分,在3.1中有說明;輸出類型決定小的數據塊怎麼重新組合起來,3.2有說明。

輸入和輸出類型的作用是相互作用的,因此不必單獨去學習這12個函數,學習3種類型的輸入函數和4種類型的輸出函數已經足夠了。因此,可以參考表1的行(輸入類型)和列(輸出類型)。我們使用d*ply表示行(輸入類型),*dply表示列(輸出類型)。

**ply函數根據輸入類型具有2~3個功能:

表1: plyr包的12個關鍵函數,數組(array)包含矩陣(matrices)和向量(vectors)

a*ply(.data, .margins, .fun, ……,.progress=」none」)

d*ply(.data, .variables, .fun, ……,.progress=」none」)

l*ply(.data, .fun, …,.progress=」none」)

第一個命令是.data ,它是被拆分、處理、重組的函數。第二個命令是.variables 或者.margins,描述如何拆分輸入數據。第三個命令,.fun,是處理函數,應用於每一個拆分出來的數據塊。另外其他的命令是用於處理函數。如果省略.fun,單個數據塊將不會被更改,但是整個數據結構將會被轉換為另外一個類型。處理函數控制進度條的顯示,在最後的第4部分展示。注意所有的命令都是以「.」開始,這可以避免和進程函數的名字衝突,有助於從控制單個進程的命令轉換到控制重複命令的視覺化呈現。

3.1 輸入

對於如何拆分輸入數據,不同的輸入格式有不同的規則,而這些規則在下面會詳細介紹。首先進行簡單的概述:

1、數組被拆分成「lower-d」大小的數據塊:a*ply()

2、數據框按照變數重組形成子集:d*ply()

3、列表中的每一個元素是一個數據塊:l*ply()

技術備忘表:輸入數據不是按照數據結構的類型進行拆分的,而是按照處理方法進行的。被a*ply()拆分的數據必須對dim()響應並且接受多維索引。被d*ply()拆分的數據,必須和split()共同起作用並被整合到列表中。被列表拆分的數據,必須和length()及[[.共同起作用。這意味著數據框可以用a*ply()操作,這時候數據框被認為是二維矩陣。如果數據框用l*ply()操作,這時候數據框被認為是向量組成的列表。

3.1.1 輸入:數組(a*ply)

Margins命令決定a*ply函數的拆分維度。如果對apply熟悉,a*ply也是以相同的方式運行。對於一個二維數組,有四種方式處理這種情形,圖1解釋了其中的三種情形:

1 .margins=1: 拆分成行

2 .margins=2: 拆分成列

3 .margins=c(1,2): 拆分成單獨的小塊

第四種方式不用拆分矩陣,相當於.margins=c(). 但是很少使用plyr包運行這種方法

圖1:拆分矩陣的3種方法,矩陣上邊的數字代表拆分的方式,原始矩陣為左上角的矩陣,並標出兩個維度。每個可能產生的結果用藍色方塊顯示。

三維數組有點複雜。可以產生3個二維數組,三個3個一維數組,1個零維數組,這些都在圖2中顯示。注意一維數組和二維數組是如何交叉相關的,margins命令同樣適用於更高維度的數組,但是也會讓拆分數組的方式變得非常多。

圖2:拆分3維數組的7種方式,圖上的數字代表拆分的方式,原始數組在左上方顯示,並且標出不同維度標籤。藍色模塊代表其中的一個輸出結果。

特殊情形:m*ply是一種操作數組的特殊方法和R中的基本功能mapply對應,plyr包對應的是maply, mdply, mlply和m_ply. m*ply() 可以對矩陣和數據框進行操作,按照行進行拆分,並將結果作為參數進行運算。圖3顯示如何利用這種方法從正態分布矩陣中提取正態分布的參數。

圖3:使用m*ply包的rnorm(), m*ply(data, rnorm)函數。以列中的數字為標準,函數按照每行的數字運行一次。如果有列名或者位置信息,函數就按照這種方式進行匹配。

3.1.2 輸入:數據框(d*ply)

當我們操作數據框時,我們通常希望按照組合變數的方式進行拆分。利用d*ply指定需要的變數。這些變數以一個特殊的方式標出,並在數據框中首先進行計算,然後進行全局運算。(在這種情況下,我們需要確保變數的長度和數據框的行數是一致的)

1 .(var1) 將會按照var1變數進行數據框的拆分,.(a,b,c)將變數進行重組,並且輸出標籤為a,b,c。

2 我們也可以使用變數功能:.(round(a))、 .a(a*b)這兩個函數。如果將結果輸出到一個數據框,那麼將會產生彆扭的變數名(由make.names()產生)。一種更改變數名的方式是:.(product=a*b)

3 plyr包設定的默認值是首先讀取數據框,然後從全局角度運行命令.(anothervar)。但是,還是建議大家將相關變數放進同一個數據框中,這樣在在運行的時候就會比較容易。

同時,還有兩種熟悉的方式定義拆分的數據塊:

①作為列名的字元變數:c(「var1」,」var2」)

②用一個公式(只有等式右邊):~var1+var2

圖4展示了拆分數據框的兩個例子。拆分數據框比拆分數組容易理解,也更容易繪圖顯示,因為僅有兩個維度。

3.1.3 輸入:列表(l*ply)

列表是最容易處理的輸入數據類型,因為它本身就是一個個的小組塊,也就是列表的一個個元素。由於這個原因,l*ply函數不需要那種如何拆分數據結構的命令。l*ply函數和a*ply函數在運行一維數組時功能一樣。l*ply 也可以被用來處理原子向量。

圖4:按照變數拆分數據框的兩個例子。如果同時按照性別和年齡拆分,就只有一個子集多於一行:13歲的男性。

表2:不同函數的應用範圍及無效的輸出數據類型。解釋的細節在輸出部分。

特殊情況:r*ply是操作列表的一種特殊情況,它相當於R的基礎函數replicate(),對於繪製隨機數字的分布圖很有用。這有點不同於其他的plyr方法。不像.data命令,r*ply具有.n的命令,它是重複運行的次數,而不僅僅是一個接收符號,能夠將每個重複設置出差異化。

3.2 輸出

輸出類型定義了數據塊如何重新組合,怎麼設置標籤。標籤特別重要,因為它保證輸入和輸出一致。

輸入和輸出的類型是相同的,除非有額外的輸出類型 ,-,定義輸出類型。這對於plot()函數和write.table()函數很有用,這種函數僅僅調用過程數據,而不是返回值。

輸出數據類型也有一些限制條件。一般來說,進程函數應該和最終輸出結果具有相同的數據類型,(例如:向量,矩陣,數組,對應*aply,數據框對應*dply)但是也有例外(表2已經列出)。這部分內容會在不同輸出數據類型的單獨介紹部分進行詳述。

3.2.1輸出:數組(*aply)

數組的輸出類型是由輸入的數據塊和相應的維度決定的。圖5和圖6從兩個維度解釋了這種模式。對於數組,數據塊按照預設方式進行組合;列表被認為是一維的數組;數據框根據拆分數據塊的變數增加維度。如果輸入的是數組,輸出數組的標籤將會和原來一致。如果輸入的是數據框,輸出數組的標籤將從數據框的子集中提取。

進程函數應該返回元數據數組(比如邏輯型,字元型,數值型,整數型)或者固定大小、固定類型的數據,或者返回列表。如果是元數據數組,其他維度將會加在現有維度的垂直方向。如果是列表,輸出結果將會是列表數組。如果沒有結果,*aply將會返回長度為0 的邏輯向量。

所有的*aply函數有一個drop.的命令。如果邏輯為TRUE,默認將長度為1維的數據刪除。這個很有用,因為在R中,一個長度為3的向量不是3x1的矩陣,也不是3x1x1的數組。

圖5: 單一變數在不同維度輸出結果的展示,左上角為單變數。右上方的兩個圖形代表輸入:左邊是長度為2的向量,右邊是3x2的矩陣。左下方的兩個圖形代表進程組塊:上邊是長度為3的向量。下邊是2x2的矩陣。其他維度以垂直方式加到現有維度上。右下方有一個4維數組,因此沒有在這裡顯示。

圖6:一維向量在不同維度的輸出結果展示,左上角為一維向量。右上角代表輸入:左邊為按行拆分的2x3矩陣,右邊是按照列拆分的3x2矩陣。左下方代表單一進程塊的形狀:最上面是單一值,中間是長度為3的向量,下邊是2x2的矩陣。

3.2.2輸出:數據框(*dply)

當輸出結果為數據框時,它將包含輸入結果和額外增加的列,這些列指出了每一行數據的來源。如果需要的話,這些列也能融合新的數據和原有數據。如果輸入的是數據框,將會有一個變數相關列拆分原始數據。如果輸入的是列表,將會有一個列名相關列拆分原始數據。如果輸入的是數組,將會有一個拆分維度後的列名相關列拆分原始數據。圖7解釋了這些輸入數據框的處理方法。

圖7:利用圖4nrow()相關的例子解釋用ddply()產生的輸出結果。上圖顯示了不同拆分方法產生的結果。注意列標籤是如何添加的,然後就能根據需要選擇相應的子集。

進程函數要麼返回數據框,要麼是固定長度的數據元,而這些數據元組成了輸出的列。如果沒有輸出結果,*dply將會返回空的數據框。.plyr包提供了一種as.data.frame方法處理相關函數。as.data.frame(mean) 將會創建一個新的函數,它能夠產生一個數據框。

3.2.3 輸出:列表(*lply)

這是最簡單的輸出格式,每一個處理的數據塊都匯總到一個列表中。列表同樣保留每個數據塊的標籤,因此當你使用ldply或者laply函數進一步處理列表時,標籤將會顯示出來,就像曾經使用的aaply,adply,daply或者ddply函數。llply 對於計算複雜對象很管用,比如模型,利用這種方法能夠提取出感興趣的數據塊並放進數組或者數據框。

對於進程函數的輸出結果,這裡沒有限制。如果沒有輸出結果,*lply將會返回長度為0的列表。

3.3輸出:空值(*_ply)

有時候操作列表可能會產生副作用,比如繪圖到屏幕或者保存結果到一個文件中,在這種情況下,*_ply是更好的選擇,比直接放棄*lply產生的結果要好,因為*lply函數不會儲存中間結果。*_ply函數有一個額外的命令,.print,它決定了是否列印每一個結果,並且它也能用於lattice包或者ggplot2包。

原文:pan.baidu.com/s/1dEXyHP

總結:這是數據分析作業的翻譯部分,但是我前前後後花了一個月才翻譯完成,部分原因是其他事情變多了,更多的原因是翻譯挺痛苦的,而且是自己根本不知道什麼內容的文章。最終也沒翻譯完成,第四部分之後的內容沒有翻譯。

最大的收穫是閱讀英文的水平又上升了一個台階,之前沒有這樣一個單詞一個單詞的讀並把它翻譯成中文,現在慢下來能注意到很多之前忽視的問題。但是也有缺點,翻譯完了也不知道這些知識怎麼用,還是得直接練習學的快,也理解的深入。

推薦閱讀:

@所有人 | 高薪翻譯崗位等你來!
《古文觀止-祭公諫征犬戎》的譯文和注釋是什麼?
人工智慧加持移動翻譯,傳統的翻譯員即將大量失業?
雙語精讀|美元匯率恐引發貿易戰

TAG:R | 數據分析 | 翻譯 |