Rにおけるapply関数群の使い方と実践

Kaggleのtitanicを解いているときにRのapply関数群がわからず苦労したので、まとめておきます。

apply関数群について簡単に説明したのち、実際にtitanicではapply関数をどう使っていくのかについても見ていきます。

今回は[【Kaggle入門, R言語】Titanic号の乗客データを用いた生存者予測―ロジスティックモデルでスコア80%を超えることができるか挑戦してみた― ](http://zeema.hatenablog.com/entry/2017/09/04/003400) の記事を使ってkaggleに入門することを想定しているので、記事内でつかわれているapply,sapply,lapply,tapplyに絞って解説します。

また、titanicでのデータの読み込み方についてや解き方は上の記事をご覧ください。

###apply(x,i,f)

applyの第1引数にはデータを代入し、第2引数にはオプションとして1または2を代入します。

第2引数の1は各行に対して処理を行う場合、2は各列に対して処理を行う場合をそれぞれ表します。

第3引数には適用したい関数を指定します。

```R
# apply関数を適用するための行列を作成
> apptest<-matrix(c(23,2.3,3.3,5,19,24),nrow=2)
> apptest
     [,1] [,2] [,3]
[1,] 23.0  3.3   19
[2,]  2.3  5.0   24
#各行に対して平均値を求める
> apply(apptest,1,mean)
[1] 15.10000 10.43333
#各列に対して中央値を求める
> apply(apptest,2,median)
[1] 12.65  4.15 21.50
```

###lapply(x,f),sapply(x,f)
lapplyはリスト型に対して一括で処理を加えます。

引数は入力データと演算処理を行うための関数2つだけです。

```R
# apply関数を適用するためのリストを作成
> testlapp<-list(1:15,20:35,40:55,60:75)
> testlapp
[[1]]
 [1]  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15

[[2]]
 [1] 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35

[[3]]
 [1] 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55

[[4]]
 [1] 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75

# 戻り値はリスト型
> lapply(testlapp,median)
[[1]]
[1] 8

[[2]]
[1] 27.5

[[3]]
[1] 47.5

[[4]]
[1] 67.5

```

sapplyはlapplyと使い方は同じですが、戻り値が異なります。

lapplyの戻り値がリスト型であるのに対してsapplyの戻り値はベクトル型になります。

```R
> testsapp<-list(1:15,20:35,40:55,60:75)
# 戻り値はベクトル型
> sapply(testsapp,median)
[1]  8.0 27.5 47.5 67.5
```

###tapply(x,i,f)

tapplyはデータフレームのデータを相手に処理を行うので、データフレームをつくるところから始めます。

戻り値はベクトルまたはリストで返ってきます。

コードを見た方が直感的に理解しやすいかも知れません。



```R
# 受験者名と点数と教科が記入されたデータを用意
> testtapp <- data.frame(examinee=c("Jhon","Mike","Alice","Mike","Alice"),score=c(94,23,49,67,75),subject=c("math","ethics","english","chinese","physics"))
> testtapp
  examinee score subject
1     Jhon    94    math
2     Mike    23  ethics
3    Alice    49 english
4     Mike    67 chinese
5    Alice    75 physics

#受験者の平均得点を求める
> tapply(testtapp$score,list(testtapp$examinee),mean)
Alice  Jhon  Mike 
   62    94    45 
```
###Titanicではどのようにapply関数を使うか

データの欠損値の合計を一覧で表示するためにsapply関数を使っています。

ここではsapplyに第2引数で自分で定義した関数を渡しています。

alldataはcsvから読み込んできたデータです。

csvの読み込み方やコードは上記リンクをご覧ください。

```R
# 欠損値の合計を一覧で表示
> sapply(alldata,function(x) sum(is.na(x)))
PassengerId
0
Survived
418
Pclass
0
Name
0
Sex
0
Age
263
SibSp
0
Parch
0
Ticket
0
Fare
1
Cabin
1014
Embarked
2
Famsize
0
Dfamsize
0
```

乗客の年齢(Age)の欠損値を埋める際にapply,tapply関数を使います。


```R
# AgeのデータにいくつNAが含まれているか
> sum(is.na(alldata$Age)) #263 missing values for 'Age'
263

# Name変数の情報を利用して補完を行う
> alldata$Title <- gsub('(.*, )|(\\..*)', '', alldata$Name) #Name変数から呼称(Mr, Missなど)部分を抽出して新たな変数Titleとする．
# 使用している正規表現は次のとおり。
# (.*, )|(\\..*)のうち()はグループ化であり，.は任意の一文字。*は直前の一文字を0回以上続ける。
# \\.は単なる「.」文字のことであり\\..は「.の後に任意の一文字」を意味しており，さらに\\..*は「.●●」と.の後の任意の一文字を0回以上続ける，つまり，.の後の文字列を指定していることを意味する.
> table(alldata$Title)
 Capt          Col          Don         Dona           Dr     Jonkheer 
           1            4            1            1            8            1 
        Lady        Major       Master         Miss         Mlle          Mme 
           1            2           61          260            2            1 
          Mr          Mrs           Ms          Rev          Sir the Countess 
         757          197            2            8            1            1 
> officer <- c('Capt', 'Col', 'Don', 'Dr', 'Major', 'Rev')
> royalty <- c('Dona', 'Lady', 'the Countess','Sir', 'Jonkheer')

# Miss, Mrs, Royalty, Officerへ集約する
> alldata$Title[alldata$Title == 'Mlle']        <- 'Miss' 
> alldata$Title[alldata$Title == 'Ms']          <- 'Miss'
> alldata$Title[alldata$Title == 'Mme']         <- 'Mrs' 
> alldata$Title[alldata$Title %in% royalty]  <- 'Royalty'
> alldata$Title[alldata$Title %in% officer]  <- 'Officer'
> alldata$Title<-as.factor(alldata$Title)

# Titleごとの中央値でAgeの欠損値を補完する
> tapply(alldata$Age, alldata$Title,median, na.rm=TRUE)
> title.age <- aggregate(alldata$Age,by = list(alldata$Title), FUN = function(x) median(x, na.rm = T))
> title.age # Titleごとの年齢の中央値
Group.1	x
Master	4
Miss	22
Mr	29
Mrs	35
Officer	49
Royalty	39

> alldata[is.na(alldata$Age), "Age"] <- apply(alldata[is.na(alldata$Age), ] , 1, function(x) title.age[title.age[, 1]==x["Title"], 2])


```

###終わりに

kaggleでのデータ分析を始める際にはまずtitanicを入門として解くことになると思います。

その際に解き方を解説している記事が多数ありますが、コードを理解するためには多くのRの基礎を理解していかなければなりません。

そのRの基礎を補うお役に立てれば幸いです。

また同じ目的としてクロス集計表についても書いていますのでよかったらご一読ください。
Rでのクロス集計表の作成については[こちら](https://qiita.com/crash-boy/items/e7740162bb6f39636d01)

以上です。
ありがとうございました。

###参考

[【Kaggle入門, R言語】Titanic号の乗客データを用いた生存者予測―ロジスティックモデルでスコア80%を超えることができるか挑戦してみた― ](http://zeema.hatenablog.com/entry/2017/09/04/003400)
[apply()ファミリー](http://cse.naro.affrc.go.jp/takezawa/r-tips/r/24.html)
https://stats.biopapyrus.jp/r/basic/apply.html
[プログラマのためのR言語入門](https://qiita.com/stkdev/items/6aba2c1db2fa056170ae)