R語言中的迴圈函式(Grouping Function)

深藍發表於2015-03-21

R語言中有幾個常用的函式,可以按組對資料進行處理,apply, lapply, sapply, tapply, mapply,等。這幾個函式功能有些類似,下面介紹下這幾個函式的用法。

Apply

這是對一個Matrix或者Array進行某個維度的運算。其格式是:

Apply(資料,維度Index,運算函式,函式的引數)

對於Matrix來說,其維度值為2,第二個引數維度Index中,1表示按行運算,2表示按列運算。下面舉一個例子:

m<-matrix(1:6,2,3)

構建一個簡單的2行3列的矩陣,內容為:

     [,1] [,2] [,3]
[1,]    1    3    5
[2,]    2    4    6
如果我們要計算每一行的sum值,那麼我們可以寫為:
apply(m,1,sum)
[1]  9 12
如果要計算每一列的mean值,那麼改為:
apply(m,2,mean)
[1] 1.5 3.5 5.5
假如某個值為NA,那麼要忽略NA值,進行每一行的SUM怎麼辦呢?
m[2,2]<-NA
     [,1] [,2] [,3]
[1,]    1    3    5
[2,]    2   NA    6
apply(m,1,sum)
[1]  9 NA
本身sum函式有一個引數na.rm,我們可以將這個引數帶人到apply函式中,作為第4個引數:
apply(m,1,sum,na.rm=TRUE)
[1] 9 8
需要注意的是如果是Data Frame,那麼系統會將其轉為Matrix,如果所有Column不是數字型別或者型別不一致,導致轉換失敗,那麼apply是運算不出任何一列的結果的。

Lapply

前面說到apply是對於matrix和array的,針對list,我們可以使用lapply函式。該函式接收list,返回的結果也是一個list。其呼叫如下:
Apply(資料,運算函式,函式的引數)
對於Data Frame來說,如果不同的列有不同的資料型別,不能轉換成Matrix,但是卻可以轉換成List,然後使用lapply函式。
我們建立一個學生名字,年齡和成績的Data Frame,然後統計平均年齡和平均成績,由於name列不是數值型別,所以無法算平均值,所以我們可以對非數值的資料只取count數量。這裡就需要用到自定義函式。
函式可以是匿名函式,也可以是之前定義好的函式,由於這裡邏輯簡單,我們可以用匿名函式解決。

s<-data.frame(name=c("Devin","Edward","Lulu"),age=c(30,33,29),score=c(95,99,90))

    name age score
1  Devin  30    95
2 Edward  33    99
3   Lulu  29    90


lapply(s,function(x){if(is.numeric(x)){mean(x)}else{length(x)}})

$name
[1] 3

$age
[1] 30.66667

$score
[1] 94.66667
我們可以看到返回了一個List的結果,裡面包含3個項,每個項是函式執行的結果。lapply返回的結果和傳入的List的結構相同,傳入多少個Item,返回的也是多少個Item。

Sapply

Sapply函式和Lapply函式很類似,也是對List進行處理,只是在返回結果上,Sapply會根據結果的資料型別和結構,重新構建一個合理的資料型別返回。呼叫格式如下:
Apply(資料,運算函式,函式的引數,simplify = TRUE, USE.NAMES = TRUE)
對於其中的simplify引數,就是指明是否對返回的結果集重新組織,如果為FALSE,那麼就相當於lapply了。USE.NAMES是對字串資料處理時,是否使用字串作為命名的。
還是上面的例子,只是把lapply換成sapply:
sapply(s,function(x){if(is.numeric(x)){mean(x)}else{length(x)}})
    name      age    score 
 3.00000 30.66667 94.66667 
我們可以看到結果集變成了一個數字向量,而不是List了。

Mapply

這是對多個資料(multivariate)進行sapply處理,只是呼叫是引數位置有所變化,先把函式放前面:
mapply(運算函式,函式的引數,第一個傳入引數,第二個資料…,SIMPLIFY = TRUE,USE.NAMES = TRUE)
比如我們自定義一個函式m3,接受3個數值引數,然後將3個數字相乘返回結果:
m3<-function(a,b,c){a*b*c}
然後我們構建3個向量,他們具有相同的長度:

a<-1:5
b<-2:6
c<-5:1

現在我們要求a,b,c中的對應各位數進行m3函式的運算,也就是把a,b,c的第一個數做運算,然後把a,b,c的第二個數做運算,然後第三個數~~~這時候就用mapply很方便:

mapply(m3,a,b,c)
[1] 10 24 36 40 30

OK,就這麼簡單,實現了對應的各位元素的運算。

Tapply

前面介紹的幾個apply函式都是對整體資料進行處理,而tapply是對向量中的資料進行分組處理。先看看tapply函式的呼叫格式:
tapply(向量資料,分組標識,運算函式,函式的引數,simplify = TRUE)
我們以一個學生資料的Data Frame為例來講解tapply函式,先構建一個新的學生資料,包含name,age,score,class,gender:

s<-data.frame(name=c("Devin","Edward","Lulu","Jeneen"),age=c(30,33,29,32),score=c(95,99,90,88),class=c(1,2,1,2),gender=c("M","M","F","F"))

    name age score class gender
1  Devin  30    95     1      M
2 Edward  33    99     2      M
3   Lulu  29    90     1      F
4 Jeneen  32    88     2      F

如果我們要計算每個班的平均成績,那麼使用tapply的方法是:

tapply(s$score,s$class,mean)
   1    2 
92.5 93.5 
如果改為按gender算平均成績,那麼就是:
tapply(s$score,s$gender,mean)
 F  M 
89 97 
如果同時按class和gender來看呢?這裡就需要把兩個向量構建成list作為第二個引數傳入:
tapply(s$score,list(s$class,s$gender),mean)
   F  M
1 90 95
2 88 99
 

相關文章