1. 程式人生 > >R學習筆記 第六篇:資料變換和清理

R學習筆記 第六篇:資料變換和清理

用R的分組操作之前,首先要了解R語言包,包實質上是實現特定功能的,預先寫好的程式碼庫(library),R擁有大量的軟體包,許多包都是由某一領域的專家編寫的,但並不是所有的包都有很高的質量的,在使用包之前,最好導社群中瞭解其他網友的反饋。

安裝包,引用包和解除安裝包的命令分別是:

install.packages("package-name")
library(package-name)
remove.packages("package-name")

資料分析的工作,80%的時間耗費在處理資料上,而資料處理的過程可以分為:分離-操作-結合(Split-Apply-Combine),也就是說,先將資料根據特定的欄位分組,每個分組都是獨立的;然後,對每個分組執行轉換,最後把轉換後的結果組合在一起,在資料處理中,經常需要迴圈訪問資料,R語言是向量化的,天生具有處理迴圈操作的優勢。

一,分組聚合

在apply函式家族中,apply函式只能用於矩陣,lapply函式能夠用於向量和列表(list),其工作原理是把一個函式應用於一個列表中的每個元素上,並且把結果作為列表返回;sapply處理列表,返回向量。mapply函式,把呼叫的函式應用到多個列表的每一個元素中。

tapply函式用於分組聚合運算,在研究資料時,有時需要對資料按照特定的欄位進行分組,然後統計各個分組的資料,這就是SQL語法中的分組聚合。在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)
+ )

計算每個玩家的平均得分,首先對玩家分組,split函式的作用是按照特定的欄位對資料框進行分組,第一個引數是資料框物件,第二個引數是分組欄位,split函式返回的結果是列表物件。

例如,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
複製程式碼

第二步是對每個分組計算平均分,利用lapply函式,把函式引用於列表的每個列表項中:

list_mean_by_player=lapply(scores_by_player,mean)

第三步是把結果合併到單個向量中,也就是把列表轉換成向量,

> unlist(list_mean_by_player)
    Dick      Jim      Tom 
52.00000 73.33333 85.00000 

在資料分析中,”拆分-應用-合併“ 顯示十分繁瑣,tapply函式一次完成所有的三個步驟,一氣呵成:

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

tapply函式常用的引數共有三個,第一個引數是:資料框物件或向量,第二個引數是因子列表,也就是分組欄位,第三個引數是指對單個分組應用的函式變數:

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

by函式和aggregate函式是tapply函式的包裝函式,功能相同,介面稍微不同。

二,aggregate函式

aggregate函式把資料分離為單獨的子集,為每一個子集計算聚合值,然後把聚合值結合(combine)在一起返回。aggregate函式第一個引數是:price~cut,這是formula物件,包括符號“ ~”,以及在符號“~”兩側的變數,左側代表要計算聚合值的變數(聚合變數),右側代表分組的變數,函式依據分組變數,把資料分離為多個單獨的子集。第二個引數是操作的資料框,第三個引數是應用在符號“~”左側的函式,例如:

> library(ggplot2)
> data("diamonds")

data函式的作用是載入指定的資料集,本例將載入ggplot2包中的diamonds資料集,這個資料集在下文直接引用。

使用aggregate函式操作diamonds資料集,按照cut欄位分組,函式mean的作用是為每個分組計算prince的平均值:

> aggregate(price~cut,diamonds,mean)

aggregate函式能夠新增多餘一個的分組變數,只需要在formula右側新增變數,並用加號“+”隔離:

複製程式碼
> aggregate(price~cut+color,diamonds,mean)
         cut color    price
1       Fair     D 4291.061
2       Good     D 3405.382
3  Very Good     D 3470.467
....
複製程式碼

aggregate函式能夠新增多個聚合變數,只需要在formula左側,使用函式cbind把兩個變數組合起來:

複製程式碼
> aggregate(cbind(price,carat)~cut,diamonds,mean)
        cut    price     carat
1      Fair 4358.758 1.0461366
2      Good 3928.864 0.8491847
3 Very Good 3981.760 0.8063814
4   Premium 4584.258 0.8919549
5     Ideal 3457.542 0.7028370
複製程式碼

還可以在aggregate函式formular物件的兩側分別新增多個變數執行操作

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

三,plyr包

plyr包基本上可以取代apply函式家族,plyr包核心函式的特點是:**ply,所有的函式名都由5個字元組成,且最後三個字元是ply,函式名的第一個字元代表輸入值的型別,第二個字元代表輸出值的型別。型別簡寫是:

  • d:data.frame
  • l:list
  • a:array,vector,matrix
  • r:代表replicate
  • _:捨棄輸出結果

plyr包的核心函式,使用起來十分方便,使用之前,需要載入和引用plyr包:

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

1,ddply函式

plyr包中最常用的函式是ddply函式,函式的第一個引數是要操作的資料框,第二個引數是:要進行拆分的列的名稱,第三個引數是要應用到每個元素上的函式。傳遞列時,無需引號,但是需要包含在.(col_name)的呼叫之後。

使用colwise函式,使ddply函式把第三個引數引用於每一列,除了第二個引數指定的資料列之外,或者使用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函式

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
......

三,dplyr包

dplyr包只能用於tibble型別的物件,用於對資料進行資料清理和轉換,使用以下命令載入和引用dplyr包:
install.packages("dplyr")
library(dplyr)

tibble 型別是dplyr包特有的物件型別(data frame tbl / tbl_df)。在利用dplyr包處理資料之前,首先需要把資料框裝載成tibble型別,可以呼叫 tbl_df函式把資料框型別的資料裝載成 tibble 型別的資料物件:

> df=tbl_df(diamonds)

1,投影函式(select)

從tibble變數中,選擇特定的資料列顯示,select函式的第一個引數是tibble變數:

> select(df,carat,cut,color)

2,篩選函式(filter)

從tibble變數中,按照特定的條件過濾資料:

> filter(df,color=='E')

3,轉換函式(mutate)

根據tibble變數中的資料,應用指定的公式,派生新的資料列,或重寫已經存在的資料列:

> mutate(df,avg_ct=price/carat)

4,彙總函式(summarize)

對tibble變數執行聚合運算,如果tibble已經被分組,那麼單獨對每個分組進行聚合運算:

> summarize(df,avg_prince=mean(price),avg_ct=mean(carat))

5,分組函式(group_by)和移除分組(ungroup)

被分組之後,tibble變數處於分組狀態,可以使用ungroup函式,移除tibble變數的分組狀態。

group_by(df,color)

6,管道操作符(%>%)

管道操作符(%>%)用於把前一步操作的結果集(變數型別是tibble)傳遞到下一個函式中,賦值給函式的第一個引數中:

複製程式碼
> group_by(df,color) %>% summarize(mean(price))
# A tibble: 7 x 2
  color `mean(price)`
  <ord>         <dbl>
1     D      3169.954
2     E      3076.752
3     F      3724.886
4     G      3999.136
5     H      4486.669
6     I      5091.875
7     J      5323.818
複製程式碼

7,排序函式(arrange)

arrange對tibble變數進行排序,預設是按照欄位的升序值排序,使用desc(field),可以按照欄位的降序值排序:

> group_by(df,color) %>% summarize(avg_price=mean(price)) %>% arrange(desc(avg_price))