R語(yǔ)言基礎(chǔ)6--apply函數(shù)家族及其應(yīng)用


R語(yǔ)言基礎(chǔ)系列:


apply函數(shù)家族是R語(yǔ)言中數(shù)據(jù)處理的一組核心函數(shù),通過使用apply函數(shù),我們可以實(shí)現(xiàn)對(duì)數(shù)據(jù)的循環(huán)、分組、過濾、類型控制等操作。
apply函數(shù)本身是用來(lái)解決數(shù)據(jù)循環(huán)處理的問題,為了面向不同的數(shù)據(jù)類型,不同的返回值,apply函數(shù)組成了一個(gè)函數(shù)加族,包括了8個(gè)功能類似的函數(shù)。

下面將分別介紹這幾個(gè)函數(shù)的定義和使用方法。

1. apply函數(shù)

apply函數(shù)是最常用的代替for循環(huán)的函數(shù)。apply函數(shù)可以對(duì)矩陣數(shù)據(jù)框、數(shù)組(二維、多維),\color{#ea4335}{按行或列進(jìn)行循環(huán)計(jì)算},對(duì)子元素進(jìn)行迭代,并把子元素以參數(shù)傳遞的形式給自定義的FUN函數(shù)中,并以返回計(jì)算結(jié)果。

1.1 函數(shù)定義:
apply(X, MARGIN, FUN, ...)
1.2 參數(shù)列表:

X:數(shù)組、矩陣、數(shù)據(jù)框
MARGIN:按行計(jì)算或按按列計(jì)算,1表示按行,2表示按列
FUN:自定義的調(diào)用函數(shù)
…:更多參數(shù),可選

1.3 應(yīng)用:
# 對(duì)一個(gè)矩陣的每一列求和
# 生成data.frame
> x <- cbind(x1 = 3, x2 = c(4:1, 2:5)); x
     x1 x2
[1,]  3  4
[2,]  3  3
[3,]  3  2
[4,]  3  1
[5,]  3  2
[6,]  3  3
[7,]  3  4
[8,]  3  5
 
apply(x,2,sum)
# x1 x2 
# 24 24 
apply(x,1,mean)
# [1] 3.5 3.0 2.5 2.0 2.5 3.0 3.5 4.0

2. lapply函數(shù)

lapply函數(shù)是一個(gè)最基礎(chǔ)循環(huán)操作函數(shù)之一,用來(lái)對(duì)list、data.frame數(shù)據(jù)集進(jìn)行循環(huán),并\color{#ea4335}{返}\color{#ea4335}{回}\color{#ea4335}{和}\color{#ea4335}{X}\color{#ea4335}{長(zhǎng)}\color{#ea4335}{度}\color{#ea4335}{相}\color{#ea4335}{同}\color{#ea4335}{的}\color{#ea4335}{list}\color{#ea4335}{結(jié)}\color{#ea4335}{構(gòu)}作為結(jié)果集,通過lapply的開頭的第一個(gè)字母’l’就可以判斷返回結(jié)果集的類型。

2.1 函數(shù)定義
lapply(X, FUN, ...)
2.2 參數(shù)列表

X:list、data.frame數(shù)據(jù)
FUN:自定義的調(diào)用函數(shù)
…:更多參數(shù),可選

2.3 應(yīng)用

輸入list,返回對(duì)每個(gè)list進(jìn)行操作后的list。

# 構(gòu)建一個(gè)list數(shù)據(jù)集x,分別包括a,b,c 三個(gè)KEY值。
x <- list(a = 1:10, b = rnorm(6,10,5), c = c(TRUE,FALSE,FALSE,TRUE));x
# $a
#  [1]  1  2  3  4  5  6  7  8  9 10

# $b
# [1]  9.186837  7.372569  9.942975 16.946282  2.550059
# [6]  6.991188

# $c
# [1]  TRUE FALSE FALSE  TRUE

# 分別計(jì)算每個(gè)KEY對(duì)應(yīng)該的數(shù)據(jù)的分位數(shù)。
lapply(x,fivenum)
# $a
# [1]  1.0  3.0  5.5  8.0 10.0

# $b
# [1]  2.550059  6.991188  8.279703  9.942975 16.946282

# $c
# [1] 0.0 0.0 0.5 1.0 1.0

如果輸入的是數(shù)據(jù)框,lapply會(huì)自動(dòng)把數(shù)據(jù)框按列進(jìn)行分組,再進(jìn)行計(jì)算。

lapply(data.frame(x), sum)
$x1
[1] 12

$x2
[1] 12

lapply可以很方便地對(duì)list數(shù)據(jù)集中個(gè)每個(gè)list進(jìn)行循環(huán)操作,還可以用data.frame數(shù)據(jù)集按列進(jìn)行循環(huán),但如果傳入的數(shù)據(jù)集是一個(gè)向量或矩陣對(duì)象,那么直接使用lapply就不能達(dá)到想要的效果了。lapply會(huì)分別循環(huán)矩陣中的每個(gè)值,而不是按行或按列進(jìn)行分組計(jì)算。

x <- cbind(x1=3, x2=c(2:1,4:5))
x; class(x)
#      x1 x2
# [1,]  3  2
# [2,]  3  1
# [3,]  3  4
# [4,]  3  5
# [1] "matrix" "array" 

lapply(x, sum)
# [[1]]
# [1] 3

# [[2]]
# [1] 3

# [[3]]
# [1] 3

# [[4]]
# [1] 3

# [[5]]
# [1] 2

# [[6]]
# [1] 1

# [[7]]
# [1] 4

# [[8]]
# [1] 5

3. sapply函數(shù)

sapply函數(shù)是一個(gè)簡(jiǎn)化版的lapply,sapply增加了2個(gè)參數(shù)simplify和USE.NAMES,主要就是讓輸出看起來(lái)更友好,與lapply不同的是,\color{#ea4335}{sapply返回值}\color{#ea4335}{為向量、}\color{#ea4335}{矩陣或數(shù)據(jù)框},而不是list對(duì)象。

3.1 函數(shù)定義
sapply(X, FUN, ..., simplify=TRUE, USE.NAMES = TRUE)
3.2 參數(shù)列表

X:數(shù)組、矩陣、數(shù)據(jù)框
FUN:自定義的調(diào)用函數(shù)
…:更多參數(shù),可選
simplify:是否數(shù)組化,當(dāng)設(shè)置simplify='array'時(shí),輸出結(jié)果按數(shù)組進(jìn)行分組
USE.NAMES:如果X為字符串,TRUE設(shè)置字符串為數(shù)據(jù)名,F(xiàn)ALSE不設(shè)置

3.3 應(yīng)用
x <- cbind(x1=3, x2=c(2:1,4:5))
# 對(duì)矩陣計(jì)算,計(jì)算過程同lapply函數(shù)
sapply(x, sum)
# [1] 3 3 3 3 2 1 4 5

# 對(duì)數(shù)據(jù)框計(jì)算
sapply(data.frame(x), sum)
# x1 x2 
# 12 12 

# 檢查結(jié)果類型,sapply返回類型為向量,而lapply的返回類型為list
class(lapply(x, sum))
# [1] "list"
class(sapply(x, sum))
# [1] "numeric"

如果simplify=FALSE和USE.NAMES=FALSE,那么完全sapply函數(shù)就等于lapply函數(shù)了。

sapply(data.frame(x), sum, simplify=FALSE, USE.NAMES=FALSE)
# $x1
# [1] 12
 
# $x2
# [1] 12

對(duì)于simplify為array時(shí),我們可以參考下面的例子,構(gòu)建一個(gè)三維數(shù)組,其中二個(gè)維度為方陣。

a<-1:2
 
# 按數(shù)組分組
sapply(a,function(x) matrix(x,2,2), simplify='array')
# , , 1
 
#      [,1] [,2]
# [1,]    1    1
# [2,]    1    1
 
# , , 2
 
#      [,1] [,2]
# [1,]    2    2
# [2,]    2    2
 
# 默認(rèn)情況,則自動(dòng)合并分組
sapply(a,function(x) matrix(x,2,2))
#      [,1] [,2]
# [1,]    1    2
# [2,]    1    2
# [3,]    1    2
# [4,]    1    2

對(duì)于字符串的向量,還可以自動(dòng)生成數(shù)據(jù)名。

val<-head(letters)
 
# 默認(rèn)設(shè)置數(shù)據(jù)名
sapply(val,paste,USE.NAMES=TRUE)
#   a   b   c   d   e   f 
# "a" "b" "c" "d" "e" "f" 
 
# USE.NAMES=FALSE,則不設(shè)置數(shù)據(jù)名
sapply(val,paste,USE.NAMES=FALSE)
# [1] "a" "b" "c" "d" "e" "f"

4. tapply函數(shù)

tapply用于分組的循環(huán)計(jì)算,通過INDEX參數(shù)(分類變量)對(duì)數(shù)據(jù)集X進(jìn)行分組并計(jì)算分組計(jì)算,相當(dāng)于group by的操作。

4.1 函數(shù)定義
tapply(X, INDEX, FUN = NULL, ..., simplify = TRUE)
4.2 參數(shù)列表

X:向量
INDEX:用于分組的索引
FUN:自定義的調(diào)用函數(shù)
…:接收多個(gè)數(shù)據(jù)
simplify:是否數(shù)組化,當(dāng)值array時(shí),輸出結(jié)果按數(shù)組進(jìn)行分組

4.3 應(yīng)用
#計(jì)算不同品種(Species)的鳶尾花(iris)的花瓣長(zhǎng)度(Petal.Length)的均值。
tapply(X = iris$Petal.Length,INDEX = iris$Species,FUN = mean)
#    setosa versicolor  virginica 
#     1.462      4.260      5.552 

5. mapply函數(shù)

mapply也是sapply的變形函數(shù),類似多變量的sapply,但是參數(shù)定義有些變化。第一參數(shù)為自定義的FUN函數(shù),第二個(gè)參數(shù)’…’可以接收多個(gè)數(shù)據(jù),作為FUN函數(shù)的參數(shù)調(diào)用。

5.1 函數(shù)定義
mapply(FUN, ..., MoreArgs = NULL, SIMPLIFY = TRUE,USE.NAMES = TRUE)
5.2 參數(shù)列表

FUN:自定義的調(diào)用函數(shù)
…:接收多個(gè)數(shù)據(jù)
MoreArgs:參數(shù)列表
SIMPLIFY:是否數(shù)組化,當(dāng)值array時(shí),輸出結(jié)果按數(shù)組進(jìn)行分組
USE.NAMES:如果X為字符串,TRUE設(shè)置字符串為數(shù)據(jù)名,F(xiàn)ALSE不設(shè)置

5.3 應(yīng)用

比如,比較3個(gè)向量大小,按索引順序取較大的值。

set.seed(1)
 
# 定義3個(gè)向量
x<-1:10
y<-5:-4
z<-round(runif(10,-5,5))
 
# 按索引順序取較大的值。
mapply(max,x,y,z)
# [1]  5  4  3  4  5  6  7  8  9 10

再看一個(gè)例子,生成4個(gè)符合正態(tài)分布的數(shù)據(jù)集,分別對(duì)應(yīng)的均值和方差為c(1,10,100,1000)。

set.seed(1)
 
# 長(zhǎng)度為4
n<-rep(4,4)
 
# m為均值,v為方差
m<-v<-c(1,10,100,1000)
 
# 生成4組數(shù)據(jù),按列分組
mapply(rnorm,n,m,v)
#           [,1]      [,2]      [,3]       [,4]
# [1,] 0.3735462 13.295078 157.57814   378.7594
# [2,] 1.1836433  1.795316  69.46116 -1214.6999
# [3,] 0.1643714 14.874291 251.17812  2124.9309
# [4,] 2.5952808 17.383247 138.98432   955.0664

由于mapply是可以接收多個(gè)參數(shù)的,所以我們?cè)谧鰯?shù)據(jù)操作的時(shí)候,就不需要把數(shù)據(jù)先合并為data.frame了,直接一次操作就能計(jì)算出結(jié)果了。

參考:https://blog.csdn.net/u012108367/article/details/80774977

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
禁止轉(zhuǎn)載,如需轉(zhuǎn)載請(qǐng)通過簡(jiǎn)信或評(píng)論聯(lián)系作者。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容