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