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