R苦手の会#5(Skype読書会)

id:wakuteka主催の読書会も5回目です.今回もid:syou6162が参加してたくさんの脱線興味深いお話を聞かせてくれました.

のーと

範囲:http://www1.doshisha.ac.jp/~mjin/R/04.html
本だと最初の方にfunctionあったり先日の基本統計量のところにapplyあったり断片的に散らばってるぽい.

準備

7つのグループに4つの選択肢のアンケートをした結果.

> ## 7つのグループ,4つの選択肢
> life1<-matrix(0,7,4)
> life1[,1]<-c(101,153,89,26,36,167,125)
> life1[,2]<-c(120,162,135,49,70,216,143)
> life1[,3]<-c(70,88,78,42,30,144,89)
> life1[,4]<-c(35,46,24,17,16,71,65)
> 
> colnames(life1) <- c("A1", "A2", "A3", "A4")
> rownames(life1) <- LETTERS[1:7]
> life1
   A1  A2  A3 A4
A 101 120  70 35
B 153 162  88 46
C  89 135  78 24
D  26  49  42 17
E  36  70  30 16
F 167 216 144 71
G 125 143  89 65
applyを使ってみよう!

applyを使うと行や列ごとに関数を使える.

> ## Applyでグループごとの和を求める
> apply(life1, 1, sum)                    # 行に
  A   B   C   D   E   F   G 
326 449 326 134 152 598 422 
> apply(life1, 2, sum)                    # 列に
 A1  A2  A3  A4 
697 895 541 274 
> apply(life1, 1:2, log)                  # 各項目
        A1       A2       A3       A4
A 4.615121 4.787492 4.248495 3.555348
B 5.030438 5.087596 4.477337 3.828641
C 4.488636 4.905275 4.356709 3.178054
D 3.258097 3.891820 3.737670 2.833213
E 3.583519 4.248495 3.401197 2.772589
F 5.117994 5.375278 4.969813 4.262680
G 4.828314 4.962845 4.488636 4.174387

第一引数はデータフレームや行列を与える.
第二引数が1なら行に,2なら列に関数を使う.
第三引数に使う関数を指定.
これをforで書き直すと

> ## for
> ans <- numeric(0)
> for(i in 1:7){
+   ans[i] <- sum(life1[i,])
+ }
> ans
[1] 326 449 326 134 152 598 422

というような感じなので,第二引数は行列に与える添え字の位置と対応させて数字にしてるのかななどと思った.中身みたら長かったので読んでないけど…
あわせてよみたい:apply familyの紹介 - yasuhisa's blog
単語とその登場回数だけが記録されたデータフレームから元のベクトルを復元とかそういう使い方もするらしい.

> ## 単語,登場回数の一覧から元のベクトルを復元
> word <- c("a", "b", "c")
> count <- c(3, 4, 1)
> d <- data.frame(word, count)
> 
> ## 各行で複数の要素が帰ってくる場合リストになる
> ## そのためunlistでベクトルに戻している
> unlist(apply(d, 1, function(x){rep(x[1],x[2])}),
+        use.names=FALSE)
[1] "a" "a" "a" "b" "b" "b" "b" "c"

ここでは無名関数を使っている.こんな感じでその場でちょいちょいと関数を定義して代入せずに使える.

roundさんはroundされましたけど

後のためにデータだけ作成.まあroundくらい分かりますよね*1

> ## グループごとの和で割って割合を出す
> (life2 <- round((life1/apply(life1, 1, sum))*100, 2))
     A1    A2    A3    A4
A 30.98 36.81 21.47 10.74
B 34.08 36.08 19.60 10.24
C 27.30 41.41 23.93  7.36
D 19.40 36.57 31.34 12.69
E 23.68 46.05 19.74 10.53
F 27.93 36.12 24.08 11.87
G 29.62 33.89 21.09 15.40
関数はfunction関数を使用して(ry

グループごとの平均値と各データの差を計算して表示する関数を作成.

> ## さあ関数を作るぞ!!
> hensa <-  function(x){
+   round(t(t(x) - apply(x, 2, mean)), 2)
+ }
> hensa(life2)
--
> ## apply使おうぜ!! by 6162
> hensa2 <- function(x){
+   apply(x, 2, function(y){round(scale(y,scale=F),2)})
+ }
> hensa2(life2)
--
> ## 引数には省略時の規定値を設定できる
> hensa3 <-  function(x=life2){
+   hensa(x)
+ }
> hensa3()
--

ちなみに引数と省略時規定値のリストはhelp以外にformals()関数で取得できる.

if for
> ## if
> if(life2[1, 1] > mean(life2[ ,1])){
+   print("TRUE")
+ }else{
+   print("FALSE")
+ }
[1] "TRUE"
> 
> ## for
> for (i in 1:7){
+   if(life2[i,1]>mean(life2[,1])){
+     print("TRUE")
+   }else{
+     print("FALSE")
+   }
+ }
--
> for(j in 1:4){
+   for (i in 1:7){
+     if(life2[i,j]>mean(life2[,j])){
+       print("TRUE")
+     }else{
+       print("FALSE")
+     }
+   }
+ }
--

おまけ

平均より大きいのに○,小さいのに×つけてみ by 6162
apply(life2,2,
function(x){symnum(x,
cutpoints=c(0,mean(x),100),
symbols=c("×","○")
)})

ふふん*2

*1:あとExcelだと四捨五入だけどroundはちゃんとJIS丸めしてるとかそんなのも知ってますよねもちろん.

*2:最初applyの第二引数間違えてた.そのときの名残で転置しててやぐさんから素早い突っ込みを食らった.