読者です 読者をやめる 読者になる 読者になる

apply familyの紹介

R Tsukuba.R 勉強会

apply familyの紹介

まとめ

  • Rらしいコードを書くならapply family
  • ベクトル、行列、データフレーム、リストに対して何か作用させるようなもの
  • applyとtapplyは覚えて帰って損ないよ!!

apply familyって?

  • lispのapplyのようなもの
  • Rを使いこなす上では割けては通れない関数群
    • Rはインタプリタ的なものなので、for文をそのまま回すと遅いことがある
    • ベクトルを中心に考えるRとしては、Rらしいコードが書ける

で、applyファミリーって何?

  • ベクトル、行列、データフレーム、リストに対して何か作用させるようなもの

種類

  • apply
  • tapply
  • sapply
  • lapply
  • rapply
  • mapply

例で説明

apply

  • 行や列に対していっぺんに何かを作用させる
    • 意味分かんない
> cars
> mean(cars$speed)
[1] 15.4
> mean(cars$dist)
[1] 42.98

一つ一つめんどくさい

  • この例ならsummary(cars)とかでできる
  • 自分で作った関数とかsummaryがやってくれないやつを一辺にやりたい
    • 例えば、自分で平均と標準偏差を返す関数を作ったとか
  • そういう時にapply関数

実例

  • 第一引数にデータフレーム
    • 行列でもいい
  • 第二引数は1か2
    • 1は行
    • 2は列
> apply(cars,2,mean)
speed  dist
15.40 42.98

mapply

  • (複数個の)ベクトルのそれぞれの要素をある関数に適用させることができる関数
  • RubyやPerlのmapと思ってもらえばいいです
> mapply(function(x,y){x+y},1:10,11:20)
 [1] 12 14 16 18 20 22 24 26 28 30
> mapply(function(x){paste("R:",x,sep="")},1:10)
 [1] "R:1"  "R:2"  "R:3"  "R:4"  "R:5"  "R:6"  "R:7"  "R:8"  "R:9"  "R:10"

mapplyを使わないでやることもできる

  • ベクトル中心の考え方
> paste("R:",1:10,sep="")
 [1] "R:1"  "R:2"  "R:3"  "R:4"  "R:5"  "R:6"  "R:7"  "R:8"  "R:9"  "R:10"

ちなみにMap関数というのもあるよ

> Map(function(x){paste("R:",x,sep="")},1:10)
[[1]]
[1] "R:1"

[[2]]
[1] "R:2"

[[3]]
[1] "R:3"

[[4]]
[1] "R:4"

[[5]]
[1] "R:5"

[[6]]
[1] "R:6"

[[7]]
[1] "R:7"

[[8]]
[1] "R:8"

[[9]]
[1] "R:9"

[[10]]
[1] "R:10"

lapplyとsapply

  • 本質的には同じような働きをする関数
  • 返す結果がリストか、ベクトル(行列)かという違いくらい

lapply

  • リストに対して、ある関数をそれぞれ適用させるための関数
  • データフレームっぽいのならapplyでいい
    • 長さが整っていないものならlapplyかsapplyを使いましょう
  • lapplyは返す結果がlist
> a <- 1:10
> b <- letters[1:26]
> x <- list(a,b)
> lapply(x,summary)
[[1]]
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max.
   1.00    3.25    5.50    5.50    7.75   10.00

[[2]]
   Length     Class      Mode
       26 character character

sapply

  • lapplyの返す結果がベクトルのやつ
  • 返ってきた結果を使いまわすんだったら、こっちのほうが使い易いかもしれない
> x <- list(a = 1:10, beta = exp(-3:3), logic = c(TRUE,FALSE,TRUE,FALSE))
> sapply(x, mean)
       a     beta    logic
5.500000 4.535125 0.500000

tapply

  • 因子とか層別で分析したいときに重宝する関数
    • こいつはapplyとtapplyくらいは覚えて帰って損しないと思うよ
> library(MASS)
> attach(quine)
> tapply(Days,Age,mean)
      F0       F1       F2       F3
14.85185 11.15217 21.05000 19.60606
> tapply(Days,list(Sex,Age),mean)
        F0       F1       F2       F3
F 18.70000 12.96875 18.42105 14.00000
M 12.58824  7.00000 23.42857 27.21429
> tapply(Days,list(Sex,Age),mean)
        F0       F1       F2       F3
F 18.70000 12.96875 18.42105 14.00000
M 12.58824  7.00000 23.42857 27.21429

rapply

  • listに対して再帰的に作用する関数
  • データ解析をする時はそんなに使わないかも…?
    • ネストしたリストに対して、それぞれの要素の絶対値を返す例
> list(-5:5,rep(0:1,3),list(10:-10))
[[1]]
 [1] -5 -4 -3 -2 -1  0  1  2  3  4  5

[[2]]
[1] 0 1 0 1 0 1

[[3]]
[[3]][[1]]
 [1]  10   9   8   7   6   5   4   3   2   1   0  -1  -2  -3  -4  -5  -6  -7  -8
[20]  -9 -10
> rapply(list(-5:5,rep(0:1,3),list(10:1)),abs,how="list")
[[1]]
 [1] 5 4 3 2 1 0 1 2 3 4 5

[[2]]
[1] 0 1 0 1 0 1

[[3]]
[[3]][[1]]
 [1] 10  9  8  7  6  5  4  3  2  1

functionのところは任意の関数が書けるよ

  • 2で割って余りが0じゃなかったら"fuga"に置換
> rapply(list(-5:5,rep(0:1,3),list(10:1)),function(x){ifelse(x%%2==0,x,"fuga")},how="list")
[[1]]
 [1] "fuga" "-4"   "fuga" "-2"   "fuga" "0"    "fuga" "2"    "fuga" "4"   
[11] "fuga"

[[2]]
[1] "0"    "fuga" "0"    "fuga" "0"    "fuga"

[[3]]
[[3]][[1]]
 [1] "10"   "fuga" "8"    "fuga" "6"    "fuga" "4"    "fuga" "2"    "fuga"

まとめ

  • Rらしいコードを書くならapply family
  • ベクトル、行列、データフレーム、リストに対して何か作用させるようなもの
  • applyとtapplyは覚えて帰って損ないよ!!