2012年12月23日日曜日

R: やっぱりapply系を使い慣れておかないと

Rはベクトル計算が強い。ていうかforループの多用は格好悪い。
いっぱい関数つくったりする前に、やっぱりapply系を使いこなしておきたい。


ということで、apply()の練習。

apply()は行列(matrix)の行(1)あるいは列(2)を対象として関数を適用する。



apply(X,MARGIN,FUN,OA)

  X: 対象とする行列
  MARGIN: 1 あるいは 2
  FUN: 関数
  OA: FUNに与える X 以外の引数(必要時のみ)



まず、適当な行列をつくる


set.seed(0)  # 乱数のseedを規定
numbers <- rnorm(12,0,1)
matrix1 <- matrix(numbers,nrow=4)

> matrix1
           [,1]       [,2]         [,3]
[1,]  1.2629543  0.4146414 -0.005767173
[2,] -0.3262334 -1.5399500  2.404653389
[3,]  1.3297993 -0.9285670  0.763593461
[4,]  1.2724293 -0.2947204 -0.799009249

行単位でmax()。

> apply(matrix1,1,max)

[1] 1.262954 2.404653 1.329799 1.272429



列単位でmax()。


> apply(matrix1,2,max)
[1] 1.3297993 0.4146414 2.4046534

自作関数をつくってみる。関数名はf1220.1()。
max()で求めたxの最大値にyを足す。


f1220.1 <- function(x,y){
z <- max(x) + y
return(z)
}

関数の動作確認。1, 2, 3の最大値に1を足すと4。

num123 <- c(1,2,3)

> f1220.1(num123,1)
[1] 4


apply()にはFUNのoptional argumentsを与えることができる。
行あるいは列単位でf1220.1()を実行。引数は1。


> apply(matrix1,1,f1220.1,1)
[1] 2.262954 3.404653 2.329799 2.272429


> apply(matrix1,2,f1220.1,1)
[1] 2.329799 1.414641 3.404653

引数は複数でもOK。


f1220.2 <- function(x,y,a,b){
z <- max(x) + y + a + b
return(z)
}

> apply(matrix1,1,f1220.2,1,1,1)
[1] 4.262954 5.404653 4.329799 4.272429

> apply(matrix1,2,f1220.2,1,1,1)
[1] 4.329799 3.414641 5.404653



apply()の対象となる行列に、行と列の名前がある場合。


colnames(matrix1) <- c("A","B","C")
rownames(matrix1) <- c("first.row","second.row","third.row","fourth.row")

> matrix1
                    A          B            C
first.row   1.2629543  0.4146414 -0.005767173
second.row -0.3262334 -1.5399500  2.404653389
third.row   1.3297993 -0.9285670  0.763593461
fourth.row  1.2724293 -0.2947204 -0.799009249

結果はこんな風になる。


> apply(matrix1,1,max)
 first.row second.row  third.row fourth.row 
  1.262954   2.404653   1.329799   1.272429 

> apply(matrix1,2,max)
        A         B         C 
1.3297993 0.4146414 2.4046534 






次に、lapplyとsapplyの練習。
まず、適当なリストをつくる。


set.seed(0)
a <- rnorm(10,0,1)
set.seed(1)
b <- rnorm(10,0,1)
list1 <- list(a,b)

> list1
[[1]]
 [1]  1.262954285 -0.326233361  1.329799263  1.272429321
 [5]  0.414641434 -1.539950042 -0.928567035 -0.294720447
 [9] -0.005767173  2.404653389

[[2]]
 [1] -0.6264538  0.1836433 -0.8356286  1.5952808  0.3295078
 [6] -0.8204684  0.4874291  0.7383247  0.5757814 -0.3053884

lapplyはリストを対象とする。リストの各要素に対して関数を適用する。


> lapply(list1,mean)
[[1]]
[1] 0.358924

[[2]]
[1] 0.1322028

sapplyはlapplyの結果をsimplifyして返す。


> sapply(list1,mean)
[1] 0.3589240 0.1322028

自作関数も動く。

f1220.3 <- function(x){
y <- x + 1
return(y)
}

> lapply(list1,f1220.3)
[[1]]
 [1]  2.26295428  0.67376664  2.32979926  2.27242932  1.41464143
 [6] -0.53995004  0.07143297  0.70527955  0.99423283  3.40465339

[[2]]
 [1] 0.3735462 1.1836433 0.1643714 2.5952808 1.3295078 0.1795316
 [7] 1.4874291 1.7383247 1.5757814 0.6946116

> sapply(list1,f1220.3)
             [,1]      [,2]
 [1,]  2.26295428 0.3735462
 [2,]  0.67376664 1.1836433
 [3,]  2.32979926 0.1643714
 [4,]  2.27242932 2.5952808
 [5,]  1.41464143 1.3295078
 [6,] -0.53995004 0.1795316
 [7,]  0.07143297 1.4874291
 [8,]  0.70527955 1.7383247
 [9,]  0.99423283 1.5757814
[10,]  3.40465339 0.6946116



引数を必要とする関数も動かせる。

f1220.4 <- function(x,b){
y <- x + b
return(y)
}

> lapply(list1,f1220.4,2)
[[1]]
 [1] 3.262954 1.673767 3.329799 3.272429 2.414641 0.460050 1.071433
 [8] 1.705280 1.994233 4.404653

[[2]]
 [1] 1.373546 2.183643 1.164371 3.595281 2.329508 1.179532 2.487429
 [8] 2.738325 2.575781 1.694612

> sapply(list1,f1220.4,2)
          [,1]     [,2]
 [1,] 3.262954 1.373546
 [2,] 1.673767 2.183643
 [3,] 3.329799 1.164371
 [4,] 3.272429 3.595281
 [5,] 2.414641 2.329508
 [6,] 0.460050 1.179532
 [7,] 1.071433 2.487429
 [8,] 1.705280 2.738325
 [9,] 1.994233 2.575781
[10,] 4.404653 1.694612



リストの中のリストも対象にできる。
まず、入れ子状のリストをつくる。

names <- c("a","b","c","d","e")
set.seed(0)
value.a <- rnorm(10,0,1)
set.seed(1)
value.b <- rnorm(10,0,1)
set.seed(2)
value.c <- rnorm(10,0,1)
set.seed(3)
value.d <- rnorm(10,0,1)
set.seed(4)
value.e <- rnorm(10,0,1)

list2 <- list()
list2$names <- names

values <- list(a=value.a, b=value.b, c=value.c, d=value.d, e=value.e)
list2$values <- values

> list2
$names
[1] "a" "b" "c" "d" "e"

$values
$values$a
 [1]  1.262954285 -0.326233361  1.329799263  1.272429321
 [5]  0.414641434 -1.539950042 -0.928567035 -0.294720447
 [9] -0.005767173  2.404653389

$values$b
 [1] -0.6264538  0.1836433 -0.8356286  1.5952808  0.3295078
 [6] -0.8204684  0.4874291  0.7383247  0.5757814 -0.3053884

$values$c
 [1] -0.89691455  0.18484918  1.58784533 -1.13037567 -0.08025176
 [6]  0.13242028  0.70795473 -0.23969802  1.98447394 -0.13878701

$values$d
 [1] -0.96193342 -0.29252572  0.25878822 -1.15213189  0.19578283
 [6]  0.03012394  0.08541773  1.11661021 -1.21885742  1.26736872

$values$e
 [1]  0.2167549 -0.5424926  0.8911446  0.5959806  1.6356180
 [6]  0.6892754 -1.2812466 -0.2131445  1.8965399  1.7768632


クラスを確認。
> class(list2)
[1] "list"

> class(list2$values)
[1] "list"


入れ子のリストにlapply()を適用。

> lapply(list2$values,mean)
$a
[1] 0.358924

$b
[1] 0.1322028

$c
[1] 0.2111516

$d
[1] -0.06713568

$e
[1] 0.5665293


sapply()も動く。





> sapply(list2$values,mean)
          a           b           c           d           e 
 0.35892396  0.13220278  0.21115165 -0.06713568  0.56652929 



リストの中の行列にはapply()が使える。
まず、行列を含むリストをつくる。


list3 <- list()
list3$names <- names
values <- cbind(a=value.a, b=value.b, c=value.c, d=value.d, e=value.e)
rownames(values) <- seq(1,10,1)
list3$values <- values

> list3
$names
[1] "a" "b" "c" "d" "e"

$values
              a          b           c           d          e
1   1.262954285 -0.6264538 -0.89691455 -0.96193342  0.2167549
2  -0.326233361  0.1836433  0.18484918 -0.29252572 -0.5424926
3   1.329799263 -0.8356286  1.58784533  0.25878822  0.8911446
4   1.272429321  1.5952808 -1.13037567 -1.15213189  0.5959806
5   0.414641434  0.3295078 -0.08025176  0.19578283  1.6356180
6  -1.539950042 -0.8204684  0.13242028  0.03012394  0.6892754
7  -0.928567035  0.4874291  0.70795473  0.08541773 -1.2812466
8  -0.294720447  0.7383247 -0.23969802  1.11661021 -0.2131445
9  -0.005767173  0.5757814  1.98447394 -1.21885742  1.8965399
10  2.404653389 -0.3053884 -0.13878701  1.26736872  1.7768632


クラスを確認。

> class(list3)
[1] "list"

> class(list3$values)
[1] "matrix"



apply()を動かす。


> apply(list3$values,1,max)
        1         2         3         4         5         6 
1.2629543 0.1848492 1.5878453 1.5952808 1.6356180 0.6892754 
        7         8         9        10 
0.7079547 1.1166102 1.9844739 2.4046534 

> apply(list3$values,2,max)
       a        b        c        d        e 
2.404653 1.595281 1.984474 1.267369 1.896540 




こういうのをちゃんと理解してから複雑な仕事をした方が良い。





0 件のコメント:

コメントを投稿