Loop functions
R內建的語法糖,讓使用者能夠用一行就執行某些迴圈才能完成的工作,畢竟如果在終端機上下指令,要打一堆括號不太方便麻...
lapply(X, FUN, ...)與sapply(X, FUN, ...)
這兩個快樂夥伴基本上差不多,對一個list內所有的元素套用函式FUN做處理,再把結果回傳,差別在於lapply總是回傳list,而sapply會嘗試以元素的長度判斷要回傳的資料是vector(元素長度都是1)或matrix(元素長度都相等),如果無法判斷(元素長度不等)才會回傳list,參數說明如下:
X
要被處裡的listFUN
要用來處理X內元素的函式,可以是函數名稱,也可以直接在這個位置匿名函式(通常不建議)。...
會以as.list()處理後,以list的形式傳入FUN滿足FUN的參數列。
l in lapply for loop? s in sapply for simplify
> x <- list(a=rnorm(10), b=rnorm(100))
#把lapply回傳的list賦值給result
> result <- lapply(x, summary)
> result
$a
Min. 1st Qu. Median Mean 3rd Qu. Max.
-1.5840 -0.6913 -0.1396 0.1010 1.0960 1.9760
#中央極限定理,N愈大mean愈接近0
$b
Min. 1st Qu. Median Mean 3rd Qu. Max.
-3.44800 -0.69560 0.07730 0.02856 0.80970 2.62400
#result是一個list of list
> class(result)
[1] "list"
> class(result[1])
[1] "list"
#如果是以sapply的方式做處理就不同了
> result <- sapply(x, summary)
> result
a b
Min. -1.5840 -3.44800
1st Qu. -0.6913 -0.69560
Median -0.1396 0.07730
Mean 0.1010 0.02856
3rd Qu. 1.0960 0.80970
Max. 1.9760 2.62400
#這時sapply回傳的資料因為每個元素都等長,所以判定為matrix
> class(result)
[1] "matrix"
split()
用法:split(x, f, drop = FALSE, ...)
說明:把vector內的元素分類到factor對應位置上定義的group上,各參數的定義:
x
資料清單f
是factor,定義哪個位置的元素要被分到什麼群組(level)。drop
定義是否要把沒有分到元素的level去掉。
應用的地方:把值分到各group內,再用其他的looping function 去分析各group所具有的值特性如何,這是R語言分群分析常見的作法,非常重要。
#這個範例需要兩個額外的package,沒有的要先裝
#需要先熟悉dplyr章節或一邊查。
> library(nycflights13)
> library(dplyr)
#nycflights13裡面有資料表flights,先看看有哪些column。
> names(flights)
[1] "year" "month" "day" "dep_time" "sched_dep_time" "dep_delay"
[7] "arr_time" "sched_arr_time" "arr_delay" "carrier" "flight" "tailnum"
[13] "origin" "dest" "air_time" "distance" "hour" "minute"
[19] "time_hour"
#取出month欄位為9~12月的資料
> x <- filter(flights, month >= 9)
#如果目的是觀察不同month的飛行時間有什麼差別~~
#作法是以month分群,再比較各組之間的飛行時間
#假設要比較的是飛行時間的mean,作法如下:
#以x$air_time作資料,x$month作factor
> x <- split(x$air_time, x$month)
#把NA去掉,看各組平均有什麼不一樣
#btw,可觀察到標示level的維度用``標示起來,需要用x$`9`取值
> lapply(x, mean, na.rm = TRUE)
$`9`
[1] 143.4712
$`10`
[1] 148.8861
$`11`
[1] 155.4686
$`12`
[1] 162.591
#或可用sapply來做
#可看到9-12月飛行時間平均值逐月變高
> sapply(x, mean, na.rm = TRUE)
9 10 11 12
143.4712 148.8861 155.4686 162.5914
#當然也能把data.frame照factor分割成幾個子data.frame存入list...
tapply
tapply(X, INDEX, FUN = NULL, ..., simplify = TRUE)
可視為lapply或sapply加上split。
X
等著被分類的vectorINDEX
FactorFUN
要套用的function...
給FUN的參數simplify
TRUE/FALSE相當於sapply/lapply+split的差別
applyfunction (X, MARGIN, FUN, ...)
,對陣列(Array)中的某個維度套用函式,速度上並不會比寫loop快,但是方便在console中下指令,常用來快速計算Col/Row的總和或平均:
X
要處理的陣列(高維度 只能是Array,matrix在高維度無法計算,因為...我試過)。MARGIN
指定某維度處理,就二維陣列來說1代表row;2代表column,三維以上的n維資料需要用大小維n-1的vector指定函式要套用的維度,以一個大小c(5,6,7)的三維陣列來說,MAGRIN帶入c(3,2)代表把第3、2維度的資料平均,每一筆資料的大小是5,所得到的矩陣的大小是c(原陣列第三維大小,原陣列第一維大小),這裡不是很好懂喔,務必每個字用力看完連結起來才能理解。FUN
、...
要套用的function與他的快樂參數。
#以2維陣列為例
> x <- matrix(rnorm(15), 3, 5)
> x
[,1] [,2] [,3] [,4] [,5]
[1,] -0.02375525 1.646059 -0.9159770 1.4699183 0.4711965
[2,] -0.53446637 -1.584217 -0.7435603 0.8063436 -0.3150133
[3,] -0.13293834 1.975515 -0.1463013 1.2771603 -0.3068395
> apply(x, 1, mean)
[1] 0.5294884 -0.4741826 0.5333193
> apply(x, 2, mean)
[1] -0.23038665 0.67911926 -0.60194619 1.18447410 -0.05021877
#以3為陣列為例
> y <- array(rnorm(105), c(3, 5, 7))
> apply(y, c(2,3), mean)
[,1] [,2] [,3] [,4] [,5] [,6] [,7]
[1,] -1.10116049 -0.5275947 0.0304933 -0.6356397 -0.4271730 -0.28947457 0.9132292
[2,] -0.23953555 0.1877777 -0.1805146 -0.1254264 0.7093323 -0.00134389 -0.4557870
[3,] -0.07977013 -0.2130288 0.2032276 1.0838883 0.1289156 0.07675923 0.8414088
[4,] -0.29096530 -0.2734326 0.3380786 0.3248017 0.2510622 -0.08762972 0.7863718
[5,] 0.12816472 -0.3932561 -0.3754301 0.5006035 0.5095342 -1.27897267 -0.0174905
如果只是要求row/column的sum/mean,有更特化的函式可以直接使用:
colSums (x, na.rm = FALSE, dims = 1) rowSums (x, na.rm = FALSE, dims = 1) colMeans(x, na.rm = FALSE, dims = 1) rowMeans(x, na.rm = FALSE, dims = 1)
> m <- matrix(rnorm(35), 7, 5)
> colSums(m)
[1] -2.0219545 0.3988152 -0.9707659 1.0355328 -2.2227004
> rowSums(m)
[1] -3.1116904 2.5644270 -3.1475705 -0.9775098 -1.3515193 2.3498650 -0.1070747
> colMeans(m)
[1] -0.28885064 0.05697361 -0.13868084 0.14793326 -0.31752862
> rowMeans(m)
[1] -0.62233807 0.51288540 -0.62951411 -0.19550195 -0.27030386 0.46997299 -0.02141494
--
mapply
function (FUN, ..., MoreArgs = NULL, SIMPLIFY = TRUE, USE.NAMES = TRUE)
,解釋起來有點複雜,直接看程式碼:
> str(rnorm)
function (n, mean = 0, sd = 1)
#下面相當於做三次rnorm
#參數n依序填入1~3,mean依序填入3~5,sd依序填入1~3
> mapply(rnorm, 1:3, 3:5, 1:3)
[[1]]
[1] 1.212527
[[2]]
[1] 1.442751 4.947334
[[3]]
[1] 3.121546 8.634739 3.581960
#跟下面效果一樣
> list(rnorm(1,3,1),rnorm(2,4,2),rnorm(3,5,3))
[[1]]
[1] 3.186405
[[2]]
[1] 3.379362 3.193535
[[3]]
[1] 3.885325 3.246838 4.477587
Vectorize
Vectorizing a Function,依序把清單上的參數執行一次,而不是直接把清單作參數,但目標參數一定要有名稱而不可是...
> mySum <-
+ function(arg1, arg2){
+ sum(arg1,arg2)
+ }
#下面這一段:
> x <- 1:10
> y <- 11:20
> v <- vector()
> for(i in 1:length(x)){
+ v[i] <- mySum(x[i],y[i])
+ }
> v
[1] 12 14 16 18 20 22 24 26 28 30
#可以用Vectorize取代為這樣:
> vMySum <- Vectorize(mySum, c("arg1","arg2"))
> vMySum(1:10,11:20)
[1] 12 14 16 18 20 22 24 26 28 30
#方便吧...但解釋起來一點也不簡單,直接看比較快。