2013年8月28日 星期三

[R] 效能(1) apply和他的快樂朋友們

在R的世界裡,for迴圈是幾乎所以R programmer都要盡量避免的,因為for迴圈真的很容易拖慢速度!

apply系列的函數可以把運算向量化(vectorization),讓程式簡潔快速喔!!!並且可以和還在用for迴圈的新手們炫耀自己的功力。

先來看看Demo的資料,都是R內建的
> library(datasets)
> head(cars)
  speed dist
1     4    2
2     4   10
3     7    4
4     7   22
5     8   16
6     9   10
> head(airquality)
  Ozone Solar.R Wind Temp Month Day
1    41     190  7.4   67     5   1
2    36     118  8.0   72     5   2
3    12     149 12.6   74     5   3
4    18     313 11.5   62     5   4
5    NA      NA 14.3   56     5   5
6    28      NA 14.9   66     5   6

1. apply(資料名稱,計算方向,套用函數)

apply算是基本款的,但是就已經蠻強大的了

其中計算方向比較需要注意:
1 表示逐列
2 表示逐行

EX: 用apply函數來計算demo資料cars中不同欄位的平均數或者檢查資料格式,通通一行搞定!
> apply(cars,2,mean)
speed  dist
15.40 42.98
> apply(cars,2,class)
    speed      dist 
"numeric" "numeric" 

2. tapply(資料$欄位,分層欄位,套用函數)

個人認為tapply還蠻好用的,尤其是要做分層的時候,功能就像是SQL語法的group by

EX: 我們可以用它來計算demo資料airquality中不同月份(Month)的最大風速(Wind)
> tapply(airquality$Wind, airquality$Month,max)
   5    6    7    8    9
20.1 20.7 14.9 15.5 16.6 

3. sapply(列表或向量,套用函數) 

是作用在列表(list)或是向量(vector)上面的

EX: 把向量a通通取絕對值!
> sapply(-4:4,abs)
[1] 4 3 2 1 0 1 2 3 4
> a<- -4:4
> a
[1] -4 -3 -2 -1  0  1  2  3  4

或者把a這個list裡面的東東通通取平均
> a=list(a=c(1,2,3),b=c(2,3,4),c=c(3,4,5))
> a
$a
[1] 1 2 3

$b
[1] 2 3 4

$c
[1] 3 4 5

> sapply(a,mean)
a b c 
2 3 4 

4. mapply(函數,函數引數)

mapply其實就是sapply的多重版,可以放數多個函數引述

EX: 由N(0,1)中做五次抽樣,第一次抽一個樣本,第二次抽兩個樣本,...第五次抽五個樣本

> mapply(rnorm, n=1:7, mean=0, sd=1)
[[1]]
[1] -2.112067
[[2]]
[1]  0.7254029 -1.2384776
[[3]]
[1]  0.8083143 -1.6875636  0.6863660
[[4]]
[1]  2.0391266  0.2182393 -0.6225456  0.4714035
[[5]]
[1] 1.0811637 0.1209754 1.1659376 0.5173664 0.1244459

5. lapply(列表或向量,套用函數)

傳回列表(list)的apply函數

EX: 向量a中每個元素都+1並存在列表(list)裡
> > a <-1:4> a
[1] 1 2 3 4
> lapply(a,function(x) x+1)
[[1]]
[1] 2

[[2]]
[1] 3

[[3]]
[1] 4

[[4]]
[1] 5

6. rapply(列表或向量,套用函數) 

針對嵌套列表(nested list就是,list中又有list的東東)的apply函數

how選項可以決定要不要針對各list裡的value

EX: 加總(how="unlist")
> a<- list(x1=1:5,x2=2:7)
> b<- list(x1=7:5,x2=0:7)
> rapply(list(a,b),sum,how="unlist")
x1 x2 x1 x2 
15 27 18 28 
EX: 加總(how="list")
> rapply(list(a,b),sum,how="list")
[[1]]
[[1]]$x1
[1] 15

[[1]]$x2
[1] 27


[[2]]
[[2]]$x1
[1] 18

[[2]]$x2
[1] 28

2 則留言:

  1. 作者已經移除這則留言。

    回覆刪除
  2. 超級有用,能在為for迴圈debug的時候認識apply和他的快樂朋友們真是太及時了!
    感謝魯千:)

    回覆刪除