R語(yǔ)言最優(yōu)秀的是它的向量化編程跟狱,這其中apply族函數(shù)扮演了非常重要的角色寺晌。apply族函數(shù)是由apply世吨、sapply、lapply呻征、mapply耘婚、tapply等函數(shù)組成的。熟練使用apply族函數(shù)陆赋,能夠簡(jiǎn)化程序沐祷,提高代碼的運(yùn)算速度。
apply
apply是最基本的函數(shù)攒岛。為了方便演示戈轿,選取了R自帶的數(shù)據(jù)框mtcars的前4行和前5列,并賦值給data阵子。a1返回的結(jié)果是data數(shù)據(jù)每一行的和,由于每行都有一個(gè)和胜蛉,所以a1是4個(gè)元素組成的數(shù)值向量挠进。a2返回的結(jié)果是data數(shù)據(jù)每一列的均值,同樣誊册,a2是5個(gè)元素組成的數(shù)值向量领突。
# 獲取內(nèi)置數(shù)據(jù)
data <- mtcars[1:4,1:5]
print(data)
## mpg cyl disp hp drat
## Mazda RX4 21.0 6 160 110 3.90
## Mazda RX4 Wag 21.0 6 160 110 3.90
## Datsun 710 22.8 4 108 93 3.85
## Hornet 4 Drive 21.4 6 258 110 3.08
# 對(duì)數(shù)據(jù)框每行求和
a1 <- apply(data,1,sum)
print(a1)
## Mazda RX4 Mazda RX4 Wag Datsun 710 Hornet 4 Drive
## 300.90 300.90 231.65 398.48
# 對(duì)數(shù)據(jù)框每列求均值
a2 <- apply(data,2,mean)
print(a2)
## mpg cyl disp hp drat
## 21.5500 5.5000 171.5000 105.7500 3.6825
apply函數(shù)的第一個(gè)參數(shù)表示數(shù)據(jù),第二個(gè)參數(shù)表示維度(1表示行案怯,2表示列)君旦,第三個(gè)參數(shù)表示在維度上操作的函數(shù)。需要注意的是第三個(gè)參數(shù)嘲碱,用作演示的函數(shù)是R自帶的函數(shù)(sum金砍、mean),當(dāng)然麦锯,這里也可以是自己定義的函數(shù)恕稠。
# 自定義函數(shù)(求極差)
func <- function(x){
result <- diff(range(x))
return(result)
}
# 對(duì)數(shù)據(jù)框每列求極差
a3 <- apply(data,2,func)
print(a3)
## mpg cyl disp hp drat
## 1.80 2.00 150.00 17.00 0.82
sapply
sapply的用法比apply要更靈活一些,同樣扶欣,用data做演示鹅巍。計(jì)算數(shù)據(jù)框data每列的數(shù)據(jù)范圍千扶,用sapply進(jìn)行計(jì)算,返回的結(jié)果存儲(chǔ)在s1里骆捧,sapply第一個(gè)參數(shù)是需要計(jì)算的數(shù)據(jù)框澎羞,第二個(gè)參數(shù)是函數(shù),第三個(gè)參數(shù)simplify=T(默認(rèn))代表返回的結(jié)果簡(jiǎn)化表示敛苇,s1的數(shù)據(jù)格式為矩陣妆绞。
s1 <- sapply(data,range,simplify = T)
class(s1)
## [1] "matrix"
如果不想讓計(jì)算的結(jié)果自動(dòng)合并成矩陣,可以設(shè)置simplify=F接谨,將返回一個(gè)列表摆碉,列表的每個(gè)組件包含了data數(shù)據(jù)框每列的range函數(shù)計(jì)算結(jié)果。
s2 <- sapply(data,range,simplify = F)
class(s2)
## [1] "list"
sapply一個(gè)更常見的用法是針對(duì)列表的組件進(jìn)行操作脓豪。例如有n個(gè)數(shù)據(jù)框巷帝,對(duì)每個(gè)數(shù)據(jù)框都要進(jìn)行相同的操作,常規(guī)方法用循環(huán)遍歷扫夜,但操作體驗(yàn)差楞泼,速度慢,更優(yōu)的解決方案是:先對(duì)單個(gè)數(shù)據(jù)框定義處理函數(shù)笤闯,然后用sapply對(duì)所有數(shù)據(jù)框采取相同操作堕阔。
# 定義一個(gè)數(shù)據(jù)框組成的list
df_list <- list(a=mtcars[1:3,1:4],
b=airquality[1:3,1:4],
c=iris[1:3,1:4])
# 自定義函數(shù)(求數(shù)據(jù)框歐氏距離的最大值)
max_func <- function(x){
d <- dist(x,p=2)
return(max(d))
}
# sapply對(duì)每個(gè)數(shù)據(jù)框計(jì)算
s3 <- sapply(df_list,max_func)
print(s3)
## a b c
## 54.7744466 72.3488770 0.5385165
lapply
lapply的用法與sapply基本相同,只不過返回的結(jié)果是以list儲(chǔ)存的颗味。
# 求每一列的均值
l1 <- lapply(data,mean)
print(l1)
## $mpg
## [1] 21.55
##
## $cyl
## [1] 5.5
##
## $disp
## [1] 171.5
##
## $hp
## [1] 105.75
##
## $drat
## [1] 3.6825
class(l1)
## [1] "list"
mapply
mapply在sapply和lapply的基礎(chǔ)上進(jìn)行了拓展超陆,可以應(yīng)用在多個(gè)變量上。a浦马、b时呀、c三個(gè)數(shù)值向量,第一次需要計(jì)算1*2*3
晶默,第二次需要計(jì)算2*3*4
谨娜,...,以此類推磺陡。當(dāng)需要每次變化的變量有多個(gè)時(shí)趴梢,用mapply計(jì)算更方便快捷。
a <- 1:5
b <- 2:6
c <- 3:7
m1 <- mapply(prod,a,b,c)
print(m1)
## [1] 6 24 60 120 210
tapply
tapply主要用在分組計(jì)算上币他。分組計(jì)算是常見的數(shù)據(jù)處理操作坞靶,能夠處理分組計(jì)算的函數(shù)也不少,tapply的優(yōu)勢(shì)是簡(jiǎn)單便捷圆丹。
# 數(shù)據(jù)框
group_df <- data.frame(value=1:6,label=rep(c("a","b"),3,each=1))
print(group_df)
## value label
## 1 1 a
## 2 2 b
## 3 3 a
## 4 4 b
## 5 5 a
## 6 6 b
# 按照l(shuí)abel分組計(jì)算value和
t1 <- tapply(X =group_df$value,INDEX = group_df$label,sum)
print(t1)
## a b
## 9 12