背景:
鳶尾花數(shù)據(jù)集最初由Edgar Anderson 測量得到南吮,而后在著名的統(tǒng)計學(xué)家和生物學(xué)家R.A Fisher于1936年發(fā)表的文章「The use of multiple measurements in taxonomic problems」中被使用魄懂,用其作為線性判別分析(Linear Discriminant Analysis)的一個例子充蓝,證明分類的統(tǒng)計方法载城,從此而被眾人所知夸赫,尤其是在機器學(xué)習(xí)這個領(lǐng)域弥咪。
數(shù)據(jù)中的兩類鳶尾花記錄結(jié)果是在加拿大加斯帕半島上,于同一天的同一個時間段纠吴,使用相同的測量儀器硬鞍,在相同的牧場上由同一個人測量出來的。這是一份有著70年歷史的數(shù)據(jù)戴已,雖然老固该,但是卻很經(jīng)典,詳細數(shù)據(jù)集可以在UCI數(shù)據(jù)庫中找到糖儡。
鳶尾花數(shù)據(jù)集共收集了三類鳶尾花伐坏,即Setosa鳶尾花、Versicolour鳶尾花和Virginica鳶尾花握联,每一類鳶尾花收集了50條樣本記錄桦沉,共計150條每瞒。
1. apply()系列函數(shù)
apply()的被分析對象必須且只能是矩陣或數(shù)組
apply()對層、行纯露、列剿骨、行和列應(yīng)用函數(shù),根據(jù)觀測埠褪、變量和數(shù)據(jù)集不同層次的特征決定浓利。語法格式為:
apply(dataset, MARGIN, FUN)
dataset是apply應(yīng)用的數(shù)據(jù)集,數(shù)據(jù)結(jié)構(gòu)是數(shù)組组橄、矩陣或數(shù)據(jù)框荞膘。參數(shù)MARGIN是apply()應(yīng)用的維度罚随,MARGIN=1表示矩陣和數(shù)組的行玉工,MARGIN=2表示矩陣和數(shù)組的列。參數(shù)FUN為應(yīng)用的計算函數(shù)f()淘菩,可帶有f()的參數(shù)遵班。FUN函數(shù)結(jié)果的長度確定apply()的返回值類型,通常為array類型潮改,若返回值的向量長度不等狭郑,則返回list對象。
> d<- matrix(1:9, ncol=3)
> d
[,1] [,2] [,3]
[1,] 1 4 7
[2,] 2 5 8
[3,] 3 6 9
> apply(d, 1, sum)
[1] 12 15 18
使用apply()函數(shù)對鳶尾花數(shù)據(jù)集第1-4列求和汇在,包含所有行翰萨。
> data(iris) #調(diào)用數(shù)據(jù)集
> head(iris)
Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1 5.1 3.5 1.4 0.2 setosa
2 4.9 3.0 1.4 0.2 setosa
3 4.7 3.2 1.3 0.2 setosa
4 4.6 3.1 1.5 0.2 setosa
5 5.0 3.6 1.4 0.2 setosa
6 5.4 3.9 1.7 0.4 setosa
> apply(iris[, 1:4],2, sum)
Sepal.Length Sepal.Width Petal.Length Petal.Width
876.5 458.6 563.7 179.9
2. lapply()函數(shù)
lapply()的被分析對象必須且只能是向量或列表
apply系列函數(shù)中,lapply()函數(shù)以列表形式返回應(yīng)用函數(shù)的結(jié)果糕殉,這是其最顯著特征亩鬼。使用lapply()函數(shù)處理數(shù)據(jù)框后得到列表,有時可能需要將得到的列表再次轉(zhuǎn)為數(shù)據(jù)框阿蝶。轉(zhuǎn)換需要經(jīng)過如下幾個階段:
1.使用unlist()函數(shù)雳锋,將列表轉(zhuǎn)換為數(shù)據(jù)框。
2.使用matrix()函數(shù)羡洁,將想來那個轉(zhuǎn)換為矩陣玷过。
3.使用as.data.frame()函數(shù),將矩陣轉(zhuǎn)換為數(shù)據(jù)框筑煮。
4.使用names()函數(shù)辛蚊,從列表獲取變量名,賦給數(shù)據(jù)框的各列真仲。
對于數(shù)據(jù)框的行名和列名袋马,可以分別使用rownames()、colnames()函數(shù)指定袒餐。
> lapply(iris[, 1:4], sum)
$`Sepal.Length`
[1] 876.5
$Sepal.Width
[1] 458.6
$Petal.Length
[1] 563.7
$Petal.Width
[1] 179.9
> lapply(iris[, 1:4], mean)
$`Sepal.Length`
[1] 5.843333
$Sepal.Width
[1] 3.057333
$Petal.Length
[1] 3.758
$Petal.Width
> lapply(split(iris$Sepal.Length,iris$Species), mean)
$`setosa`
[1] 5.006
$versicolor
[1] 5.936
$virginica
[1] 6.588
> unlist(lapply(split(iris$Sepal.Length,iris$Species), mean))
setosa versicolor virginica
5.006 5.936 6.588
3. sapply()函數(shù)
sapply()的被分析對象必須且只能是向量或列表
sapply()函數(shù)與lapply()函數(shù)類似飞蛹,但以矩陣谤狡、向量等數(shù)據(jù)類型返回結(jié)果。下列示例代碼中卧檐,使用lapply()函數(shù)將以列表形式返回各列平均值墓懂,而使用sapply()函數(shù)則以向量形式返回各列平均值。
sapply(list,g) g為操作函數(shù)霉囚,返還結(jié)果為向量捕仔,而lapply返還結(jié)果為list形式。常與split結(jié)合使用
> sapply(iris[, 1:4], sum)
Sepal.Length Sepal.Width Petal.Length Petal.Width
876.5 458.6 563.7 179.9
> sapply(iris[, 1:4], mean)
Sepal.Length Sepal.Width Petal.Length Petal.Width
5.843333 3.057333 3.758000 1.199333
使用as.data.frame()函數(shù)可以將sapply()函數(shù)返回的向量進一步轉(zhuǎn)換為數(shù)據(jù)框盈罐。此時榜跌,需要t(x)函數(shù)轉(zhuǎn)置向量的行與列,將無法得到想要的數(shù)據(jù)框盅粪。下列中钓葫,先使用sapply()函數(shù)對鳶尾花數(shù)據(jù)集的前四列分別求平均值,得到包含平均值的向量后票顾,再使用as.data.frame()函數(shù)將向量轉(zhuǎn)換為數(shù)據(jù)框础浮。
> x<-sapply(iris[, 1:4], mean)
> as.data.frame(x)
x
Sepal.Length 5.843333
Sepal.Width 3.057333
Petal.Length 3.758000
Petal.Width 1.199333
> as.data.frame(t(x))
Sepal.Length Sepal.Width Petal.Length Petal.Width
1 5.843333 3.057333 3.758 1.199333
> sapply(iris, class)
Sepal.Length Sepal.Width Petal.Length Petal.Width Species
"numeric" "numeric" "numeric" "numeric" "factor"
> y<-sapply(iris[, 1:4], function(x){x > 3})
> class(y)
[1] "matrix"
> head(y)
Sepal.Length Sepal.Width Petal.Length Petal.Width
[1,] TRUE TRUE FALSE FALSE
[2,] TRUE FALSE FALSE FALSE
[3,] TRUE TRUE FALSE FALSE
[4,] TRUE TRUE FALSE FALSE
[5,] TRUE TRUE FALSE FALSE
[6,] TRUE TRUE FALSE FALSE
4. tapply()函數(shù)
apply系列函數(shù)中,使用tapply()函數(shù)會先對數(shù)據(jù)進行分組奠骄,然后將函數(shù)應(yīng)用到各組豆同。
參考帖子:http://rsoftware.h.baike.com/article-2015511.html
tapply(x,f,g) x為向量,f為因子列含鳞,g為操作函數(shù)影锈,相對數(shù)據(jù)框進行類似操作可以用by函數(shù).
tapply()的被分析對象必須且只能是向量
tapply()根據(jù)一個因子向量對數(shù)據(jù)向量進行分類,得到的分組數(shù)據(jù)是不等長分組蝉绷,然后對每個分組應(yīng)用函數(shù)fun()鸭廷。
tapply()語法格式:
tapply(data, index, FUN = NULL, ..., simplify = TRUE)
data只能是向量,index為因子向量潜必,長度應(yīng)與data相同靴姿。返回值是向量,若simplify=FALSE輸出列表磁滚。index向量因子有兩個形式:1)數(shù)據(jù)框的變量2)指定的分類向量佛吓。可用c()生成不規(guī)則的因子垂攘,也可用gl()生成等長分類的向量维雇。
同類系列函數(shù)有split()和by()。split()函數(shù)僅對數(shù)據(jù)框或一個變量根據(jù)另一個變量分組晒他,輸出是列表吱型。by()能對數(shù)據(jù)框和矩陣根據(jù)因子分組,可應(yīng)用多變量函數(shù)fun()陨仅。
> daf1<-data.frame(gender=c("M","M","F","M","F","F","M"),
+ age=c(47,59,21,32,40,24,25),
+ salary=c(55000,88000,32450,76500,123000,45650,65000)
+ )
> daf1$over40=ifelse(daf1$age>40,1,0) #年齡大于40歲的員工
> daf1$over40
[1] 1 1 0 0 0 0 0
> tapply(daf1$salary,list(daf1$gender,daf1$over40),mean) #計算平均工資
0 1
F 67033.33 NA
M 70750.00 71500
> #用list()設(shè)置多個因子津滞,將工資salary分成四組铝侵,所以有4個答案。
> tapply(daf1$salary,c(daf1$gender,daf1$over40),mean)
Error in tapply(daf1$salary, c(daf1$gender, daf1$over40), mean) :
arguments must have same length
# 參數(shù)的長度必需相同, 參數(shù)長度不同触徐,是因為c()的連接作用咪鲜。
> df <- data.frame(year=kronecker(2001:2003, rep(1,4)),
+ loc=c('beijing','beijing','shanghai','shanghai'),
+ type=rep(c('A','B'),6),
+ sale=rep(1:12))
> df
year loc type sale
1 2001 beijing A 1
2 2001 beijing B 2
3 2001 shanghai A 3
4 2001 shanghai B 4
5 2002 beijing A 5
6 2002 beijing B 6
7 2002 shanghai A 7
8 2002 shanghai B 8
9 2003 beijing A 9
10 2003 beijing B 10
11 2003 shanghai A 11
12 2003 shanghai B 12
> tapply(df$sale, df[,c('year','loc')], sum)
loc
year beijing shanghai
2001 3 7
2002 11 15
2003 19 23
> tapply(df$sale, df[,c('year','type')], sum)
type
year A B
2001 4 6
2002 12 14
2003 20 22
5. mapply()函數(shù)
mapply()的被分析對象必須是函數(shù)
mapply()函數(shù)與 sapply()函數(shù)類似,但他可以將多個參數(shù)傳遞給指定函數(shù)撞鹉。 mapply()函數(shù)的第一個參數(shù)是待應(yīng)用的FUN函數(shù)疟丙,它接受多個參數(shù)。要傳遞給FUN()函數(shù)的參數(shù)作為數(shù)據(jù)保存時鸟雏,mapply()函數(shù)將保存在數(shù)據(jù)中的值轉(zhuǎn)換為參數(shù)享郊,傳遞給FUN函數(shù),并調(diào)用執(zhí)行FUN函數(shù)孝鹊。
函數(shù)mapply()用在函數(shù)的參數(shù)有多個不同值的時候炊琉,參數(shù)順序和sapply()不同。標(biāo)準(zhǔn)格式:
mapply(FUN, ..., MoreArgs = NULL, SIMPLIFY = TRUE, USE.NAMES = TRUE)
data數(shù)據(jù)類型為向量或列表惶室,函數(shù)FUN對元素應(yīng)用温自;若參數(shù)長度為1玄货,得到的結(jié)果和sapply相同皇钞;但如果參數(shù)長度不等于1,F(xiàn)UN函數(shù)將按向量順序和循環(huán)規(guī)則(短向量重復(fù))逐個取參數(shù)應(yīng)用到對應(yīng)數(shù)據(jù)元素松捉。
使用mapply()函數(shù)時夹界,如果給定多個數(shù)據(jù),則這些數(shù)據(jù)的第一個元素組成一組隘世,作為參數(shù)傳遞給FUN函數(shù)可柿;然后第二個元素組成一組,作為參數(shù)傳遞給FUN函數(shù)丙者,以此類推复斥。
> dv1=c(1:4)
> dafr2=mapply(dv1,FUN=rep,times=1:4)
> dafr2
[[1]]
[1] 1
[[2]]
[1] 2 2
[[3]]
[1] 3 3 3
[[4]]
[1] 4 4 4 4
下面使用mapply()函數(shù),計算鳶尾花數(shù)據(jù)集1-4列的平均值與總和械媒。
> data("iris")
> mapply(mean,iris[, 1:4])
Sepal.Length Sepal.Width Petal.Length Petal.Width
5.843333 3.057333 3.758000 1.199333
> mapply(sum,iris[, 1:4])
Sepal.Length Sepal.Width Petal.Length Petal.Width
876.5 458.6 563.7 179.9
圖片來源:https://blog.csdn.net/wzgl__wh/article/details/52207233
6. vapply()函數(shù)應(yīng)用
vapply按變量進行函數(shù)操作目锭,vapply類似于sapply函數(shù),但是它的返回值有預(yù)定義類型纷捞,所以它使用起來會更加安全痢虹,有的時候會更快。在vapply函數(shù)中總是會進行簡化主儡,vapply會檢測FUN的所有值是否與FUN.VALUE兼容奖唯,以使他們具有相同的長度和類型。類型順序:邏輯糜值、整型丰捷、實數(shù)坯墨、復(fù)數(shù)。
vapply(X, FUN, FUN.VALUE, ..., USE.NAMES = TRUE)
X表示一個向量或者表達式對象病往,其余對象將被通過as.list強制轉(zhuǎn)換為list
simplify 邏輯值或者字符串畅蹂,如果可以,結(jié)果應(yīng)該被簡化為向量荣恐、矩陣或者高維數(shù)組液斜。
必須是命名的,不能是簡寫叠穆。默認值是TRUE少漆,若合適將會返回一個向量或者矩陣。如果simplify=”array”硼被,結(jié)果將返回一個陣列示损。
USE.NAMES 邏輯值,如果為TRUE嚷硫,且x沒有被命名检访,則對x進行命名。
FUN.VALUE 一個通用型向量仔掸,F(xiàn)UN函數(shù)返回值得模板脆贵。
x<-data.frame(a=rnorm(4,4,4),
b=rnorm(4,5,3),
c=rnorm(4,5,3))
vapply(x,mean,c(c=0))
k<-function(x){
list(mean(x),sd(x))
}
vapply(x,k,c(list(c=0,b=0)))
a b c
c 3.495029 2.780169 5.41083
b 4.671292 4.283595 3.320549
7. eapply 函數(shù)table
eapply函數(shù)通過對environment中命名值進行FUN計算后返回一個列表值,用戶可以請求所有使用過的命名對象起暮。
eapply(env, FUN, ..., all.names = FALSE, USE.NAMES = TRUE)
env 將被使用的環(huán)境
all.names 邏輯值卖氨,指示是否對所有值使用該函數(shù)
USE.NAMES 邏輯值,指示返回的列表結(jié)果是否包含命名
> require(stats)
> env <- new.env(hash = FALSE) # so the order is fixed
> env$a <- 1:10
> env$beta <- exp(-3:3)
> utils::ls.str(env)
a : int [1:10] 1 2 3 4 5 6 7 8 9 10
beta : num [1:7] 0.0498 0.1353 0.3679 1 2.7183 ...
> eapply(env, mean)
$`beta`
[1] 4.535125
$a
[1] 5.5
> unlist(eapply(env, mean, USE.NAMES = FALSE))
[1] 4.535125 5.500000
> eapply(env, quantile, probs = 1:3/4)
$`beta`
25% 50% 75%
0.2516074 1.0000000 5.0536690
$a
25% 50% 75%
3.25 5.50 7.75
> eapply(env, quantile)
$`beta`
0% 25% 50% 75% 100%
0.04978707 0.25160736 1.00000000 5.05366896 20.08553692
$a
0% 25% 50% 75% 100%
1.00 3.25 5.50 7.75 10.00
8负懦、rapply 函數(shù)
rapply是lapply的遞歸版本, 它只處理list類型數(shù)據(jù)筒捺,對list的每個元素進行遞歸遍歷,如果list包括子元素則繼續(xù)遍歷纸厉。
rapply(object, f, classes = "ANY", deflt = NULL, how = c("unlist", "replace", "list"), ...)
參數(shù)列表:
object:list數(shù)據(jù)
f: 自定義的調(diào)用函數(shù)
classes : 匹配類型, ANY為所有類型
deflt: 非匹配類型的默認值
how: 3種操作方式系吭,當(dāng)為replace時,則用調(diào)用f后的結(jié)果替換原list中原來的元素颗品;當(dāng)為list時肯尺,新建一個list,類型匹配調(diào)用f函數(shù)抛猫,不匹配賦值為deflt蟆盹;當(dāng)為unlist時,會執(zhí)行一次unlist(recursive = TRUE)的操作
…: 更多參數(shù)闺金,可選
比如逾滥,對一個list的數(shù)據(jù)進行過濾,把所有數(shù)字型numeric的數(shù)據(jù)進行從小到大的排序。
> x=list(a=12,b=1:4,c=c('b','a'))
> y=pi
> z=data.frame(a=rnorm(10),b=1:10)
> a <- list(x=x,y=y,z=z)
> # 進行排序寨昙,并替換原list的值
> rapply(a,sort, classes='numeric',how='replace')
$`x`
$`x`$`a`
[1] 12
$`x`$b
[1] 1 2 3 4
$`x`$c
[1] "b" "a"
$y
[1] 3.141593
$z
a b
1 -1.8383682 1
2 -1.0000541 2
3 -0.9739195 3
4 -0.9118907 4
5 -0.8726053 5
6 -0.7946537 6
7 -0.6531306 7
8 -0.6397726 8
9 -0.3413240 9
10 1.0768179 10
> class(a$z$b)
[1] "integer"
從結(jié)果發(fā)現(xiàn)讥巡,只有$z$a
的數(shù)據(jù)進行了排序,檢查$z$b
的類型舔哪,發(fā)現(xiàn)是integer欢顷,是不等于numeric的,所以沒有進行排序捉蚤。
接下來抬驴,對字符串類型的數(shù)據(jù)進行操作,把所有的字符串型加一個字符串’++++’缆巧,非字符串類型數(shù)據(jù)設(shè)置為NA布持。
> rapply(a,function(x) paste(x,'++++'),classes="character",deflt=NA, how = "list")
$`x`
$`x`$`a`
[1] NA
$`x`$b
[1] NA
$`x`$c
[1] "b ++++" "a ++++"
$y
[1] NA
$z
$z$`a`
[1] NA
$z$b
[1] NA
只有$x$c
為字符串向量,都合并了一個新字符串陕悬。那么题暖,有了rapply就可以對list類型的數(shù)據(jù)進行方便的數(shù)據(jù)過濾了。
9. 函數(shù)table(求因子出現(xiàn)的頻數(shù))
使用格式為:
table(..., exclude = if (useNA == "no") c(NA, NaN), useNA = c("no", "ifany", "always"), dnn = list.names(...), deparse.level = 1)
其中參數(shù)exclude表示哪些因子不計算捉超。
示例代碼:
> d <- factor(rep(c("A","B","C"), 5), levels=c("A","B","C","D","E"))
> d
[1] A B C A B C A B C A B C A B C
Levels: A B C D E
> table(d)
d
A B C D E
5 5 5 0 0
> table(d, exclude="B")
d
A C D E
5 5 0 0
常用apply族函數(shù)對比
lapply()和sapply()只能應(yīng)用在二維數(shù)據(jù)結(jié)構(gòu)胧卤,例如列表的元素,數(shù)據(jù)框的變量拼岳,而且并不需要指定維度枝誊。lappy()是最基本的原型函數(shù),不妨知道它是R語言最簡單的泛函裂问,僅此而已侧啼。lapply(),sapply()和vapply()的兩個主要參數(shù)是data和f()堪簿。data的數(shù)據(jù)類型是列表或向量,函數(shù)對所有列表元素皮壁、數(shù)據(jù)框變量應(yīng)用f()函數(shù)椭更。 lapply()返回的結(jié)果是列表,長度與data相同蛾魄,sapply()返回的結(jié)果是向量虑瀑,矩陣或數(shù)組,結(jié)果需要做預(yù)測滴须。而vapply()函數(shù)將對返回結(jié)果的值進行類型檢查舌狗,參數(shù)FUN.VALUE設(shè)置返回值類型,因此vapply()是結(jié)果可預(yù)測的sapply()版扔水。所以不可在函數(shù)內(nèi)部用sapply()痛侍,而應(yīng)使用vapply()。lapply()和sapply()可實現(xiàn)數(shù)據(jù)結(jié)構(gòu)操作的大多數(shù)功能魔市,包括創(chuàng)建數(shù)據(jù)結(jié)構(gòu)主届、取子集等赵哲,然而這并不是它們的優(yōu)勢。訪問操作與"["相同君丁,"["可提取數(shù)據(jù)結(jié)構(gòu)的分量枫夺。
參考:
【1】R語言與數(shù)據(jù)分析實戰(zhàn) 徐珉久,武傳海著绘闷,人民郵電出版社
【2】第三章第一節(jié) apply族函數(shù) http://rsoftware.h.baike.com/article-2015511.html
【3】R語言中的lapply sapply apply tapply mapply http://iccm.cc/lapply-sapply-apply-tapply-mapply-in-r-language/
【4】R中的apply族函數(shù) https://zhuanlan.zhihu.com/p/26466130
【5】R語言︱數(shù)據(jù)分組統(tǒng)計函數(shù)族——apply族用法與心得: https://blog.csdn.net/sinat_26917383/article/details/51086663
【6】掌握R語言中的apply函數(shù)族 http://blog.fens.me/r-apply/
生信技能樹公益視頻合輯:學(xué)習(xí)順序是linux橡庞,r,軟件安裝印蔗,geo毙死,小技巧,ngs組學(xué)喻鳄!
B站鏈接:https://m.bilibili.com/space/338686099
YouTube鏈接:https://m.youtube.com/channel/UC67sImqK7V8tSWHMG8azIVA/playlists
生信工程師入門最佳指南:https://mp.weixin.qq.com/s/vaX4ttaLIa19MefD86WfUA
學(xué)徒培養(yǎng):https://mp.weixin.qq.com/s/3jw3_PgZXYd7FomxEMxFmw
生信技能樹 - 簡書 http://www.reibang.com/u/d645f768d2d5