LoginSignup
5
3

More than 5 years have passed since last update.

kaggleでデータ分析の基礎 #1【titanic, tidyr, dplyr,ggplot】

Last updated at Posted at 2019-05-07

kaggleでデータ分析の基礎的な部分を勉強する

データ分析の手法は知ってて知りすぎることは無いと思います。
推定やモデリングはデータセットによって適したやり方がありますが、
手法を知らないと何が適しているかもわからない。
kaggleで他人の手法を見ながら知識を増やしていきたいと思います。

今回はもっと基礎的な「データを見ること」に注力しているkarnelで、視覚化や相関関係など、モデリングの発想を生む基礎的な部分について書いてあります。
ついでにtidyrやggplotも学べたらいいなと思い取り上げました。

Tidy TitaRnic

https://www.kaggle.com/headsortails/tidy-titarnic

この人のカーネルで勉強していきます。
翻訳していますが、間違いがあった場合は指摘していただけると幸いです。

1.概要

Rを使っていきます。
tidyverseパッケージを使ったモデリングをしていくものです。

まず最初に視覚化やデータの相互関係について確認します。
その後、分類器を使っていきます。
主にdplyrをデータの操作に使い、視覚化はggplot2を使います。
(カーネルの筆者も勉強中のパッケージらしいです)
pythonに興味がある人はpythanicという筆者のカーネルも見てみてください。

1.1 ライブラリやデータの読み込み

#視覚化
library('ggplot2') 
library('ggthemes')
library('ggridges')
library('ggforce')
library('ggExtra')
library('GGally')
library('scales')
library('grid')
library('gridExtra')
library('corrplot')
#欠損値
library('VIM')
#データ操作
library('dplyr') 
library('tidyr') 
library('readr')
library('stringr') 
library('forcats') 
library('modelr')
#モデル化
library('randomForest')
library('xgboost')
library('ROCR')

データの読み込み

train <- read_csv('../input/train.csv')
test  <- read_csv('../input/test.csv')

dplyrのread_csvを使っています。
baseで入っているのはread.csvです。
freadほど早く読み込んではくれないけれども、baseよりも多少処理が早くなります。

train <- train %>% mutate(
  Survived = factor(Survived),
  Pclass = factor(Pclass),
  Embarked = factor(Embarked),
  Sex = factor(Sex)
)

trainは891×12のデータ。
この操作でまず列をファクターに変換する。
生存(Survived)、客室クラス(Pclass)、乗船した港(Embarked)、性別(Sex)をファクターにした。

test <- test %>% mutate(
  Pclass = factor(Pclass),
  Embarked = factor(Embarked),
  Sex = factor(Sex)
)

testは418×11のデータ。
生存についての列が欠けている。

combine  <- bind_rows(train, test) # bind training & test data

rbindみたいな操作。1309行のcombineを作成する。
まずデータ全体について知りたいので結合させました。
(個別にみるのではなく、予想したいデータも結合させて一つで見るという考えは無かったので新鮮)

皮肉にもdplyrはデータをファクターに変換して読み込まず、文字列として格納してくれるので、便利だったりする。

ここまでに出てきたmutateや%>%は後で説明する。

1.2 データを俯瞰する

summary(combine)
##   PassengerId   Survived   Pclass      Name               Sex     
##  Min.   :   1   0   :549   1:323   Length:1309        female:466  
##  1st Qu.: 328   1   :342   2:277   Class :character   male  :843  
##  Median : 655   NA's:418   3:709   Mode  :character               
##  Mean   : 655                                                     
##  3rd Qu.: 982                                                     
##  Max.   :1309                                                     
##                                                                   
##       Age            SibSp            Parch          Ticket         
##  Min.   : 0.17   Min.   :0.0000   Min.   :0.000   Length:1309       
##  1st Qu.:21.00   1st Qu.:0.0000   1st Qu.:0.000   Class :character  
##  Median :28.00   Median :0.0000   Median :0.000   Mode  :character  
##  Mean   :29.88   Mean   :0.4989   Mean   :0.385                     
##  3rd Qu.:39.00   3rd Qu.:1.0000   3rd Qu.:0.000                     
##  Max.   :80.00   Max.   :8.0000   Max.   :9.000                     
##  NA's   :263                                                        
##       Fare            Cabin           Embarked  
##  Min.   :  0.000   Length:1309        C   :270  
##  1st Qu.:  7.896   Class :character   Q   :123  
##  Median : 14.454   Mode  :character   S   :914  
##  Mean   : 33.295                      NA's:  2  
##  3rd Qu.: 31.275                                
##  Max.   :512.329                                
##  NA's   :1

summary関数は列の特徴や属性、分布を知るための基本的な情報が得られます。
年齢(Age)、運賃(Fare)、乗船した港(Embarked)は欠損値があり、運賃は大きく欠損している。
当然ながら生存(Survived)列はtestで欠けているのでNAになっている。
ただし、文字列で入っているとNAがわからないのでticketやcabinはNAがあるか不明。

glimpse(combine)
## Observations: 1,309
## Variables: 12
## $ PassengerId <dbl> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,...
## $ Survived    <fct> 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0,...
## $ Pclass      <fct> 3, 1, 3, 1, 3, 3, 1, 3, 3, 2, 3, 1, 3, 3, 3, 2, 3,...
## $ Name        <chr> "Braund, Mr. Owen Harris", "Cumings, Mrs. John Bra...
## $ Sex         <fct> male, female, female, female, male, male, male, ma...
## $ Age         <dbl> 22, 38, 26, 35, 35, NA, 54, 2, 27, 14, 4, 58, 20, ...
## $ SibSp       <dbl> 1, 1, 0, 1, 0, 0, 0, 3, 0, 1, 1, 0, 0, 1, 0, 0, 4,...
## $ Parch       <dbl> 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 1, 0, 0, 5, 0, 0, 1,...
## $ Ticket      <chr> "A/5 21171", "PC 17599", "STON/O2. 3101282", "1138...
## $ Fare        <dbl> 7.2500, 71.2833, 7.9250, 53.1000, 8.0500, 8.4583, ...
## $ Cabin       <chr> NA, "C85", NA, "C123", NA, NA, "E46", NA, NA, NA, ...
## $ Embarked    <fct> S, C, S, S, S, Q, S, S, S, C, S, S, S, S, S, S, Q,...

dplyrのglimpseは分析で扱うときに素早く理解しやすいような説明を表示してくれる。(見やすい)

summaryとglimpseは最初にデータを調査するのに効果的です。

乗客ID(PassengerId)は人物の情報をつなぐインデックスになっている。

客室(Pclass)はチケットの階級であり、一等客室から三等客室まである。これをファクターに変換した。

名前(Name)は乗客の苗字であり、いくつか同じものがある。家族関係である。
いくつかの敬称は年齢層を示しているのだろう。
masterは少年
Mrは男性
種類や長さに違いはあるが、敬称-苗字という似た形をとっている。

性別(Sex)は男女を表す。
年齢(Age)は年齢である。NaNが含まれる。

SibSpは整数値であり、兄弟や配偶者の数を説明している。
Parchは親子関係を説明している。
Ticketは文字列で、さまざまな長さのチケット番号が入っている。
運賃(Fare)は小数点を含む値である。乗客がこの思い出に残る旅に支払った金額である....

客室番号(Cabin)は部屋番号である。
乗船した港(Embarked)は乗船場所を表す。

summaryでは浮動小数が一つ(fare), 整数値が一つ(age), 二つの順番になっている整数(SibSp, Parch), 三つのカテゴリカルデータ"質的変数??"(Sex, Pclass, Embarked), 三つのテキストデータ(Ticet, Chabin, Name)が確認できる。

ファクターに変更したことで、
・testに418個の生存列欠損があること。
・女性の二倍男性が乗っていること。
・40%が生存したこと。
がわかる。

より細かく確認するときは下記を使う。

train %>%
  count(Survived)
## # A tibble: 2 x 2
##   Survived     n
##   <fct>    <int>
## 1 0          549
## 2 1          342

%>%を"pipe"として使っている。
ある操作のoutputを次の操作のinputにすることがこのツール(dplyrのこと?)の活用法である。

これはpandasの"."やUNIXの"|"に似たものである。

pipeを使用すると、他のアプリで使うときに使いやすい。
(unixで実装したりすることを想定しているのかも)

メモ
pipeの役割がピンとこないが、
df$colの"$"に相当したり、

model <- lm(data~.)
model["residuals"]
みたいに特定のデータを抽出するときに使うものに相当するのでは?
この辺りなら私も使うので理解しやすい。
ここまでメモ

次のコードは単純に生存したかしていないかを週出する。

surv <- train %>% count(Survived) %>% filter(Survived == 1) %>% .$n
nosurv <- train %>% count(Survived) %>% filter(Survived == 0) %>% .$n
surv/(surv+nosurv)*100

を実行すると、38.4%の乗客が生き残ったことがわかる。

1.3 欠損値について

欠損値を知ることは重要である。
ほんの少しのデータだけで推論を作ることは賢いこととは言えない。
加えて、欠損値を削除したり補間する方法を間違えるとモデリング作業が破綻する。

次のプロットは"well-organised"さんのカーネルを参考にした。
欠損値と個々の値の組み合わせについてである。
cabinには529のNAがあり、そのうち158個がAgeとともにNAになっている。
あと運賃でもNAが一つ。

aggr(combine, prop = FALSE, combined = TRUE, numbers = TRUE, sortVars = TRUE, sortCombs = TRUE)
##  Variables sorted by number of missings: 
##     Variable Count
##        Cabin  1014
##     Survived   418
##          Age   263
##     Embarked     2
##         Fare     1
##  PassengerId     0
##       Pclass     0
##         Name     0
##          Sex     0
##        SibSp     0
##        Parch     0
##       Ticket     0

01.png

cabinとticketのようなchrで入っているものは、ブーリアンベクトル(理論型 TやFのこと)で確認する。

sum(is.na(combine$Ticket))
## [1] 0
sum(is.na(combine$Cabin))
## [1] 1014

is.naはTFでNAの列を出力してくれる。
sumを使うと、Tは1、Fは0として合計してくれる。
チケットの欠損値は無いようだ。
cabinは大部分が欠損している。

2 探索と可視化

データを調べましょう。
出来る限りたくさんの、異なる方法で。
繋がりや特徴が明らかになるでしょう。

2.1 特徴について

ggplot2は"Hadley Wickham"さんがつくった"glammar"なplot関数である。
ggplotは以下のような構文でできている。
・データインプット部分+
・asthetics(表現の割り当て)+
 ・geoms(何でplotするか)

どんな種類のplotでも同じ構文で書ける。

基本原理を理解したら、可視化の方法を別の方法に変更することは簡単である。(histでもpointでもbarplotでも構文は変えなくていい)

geomは追加して書き足すことができる。
複雑なplotも簡単な要素の組み合わせで書けてしまう。

このカーネルではたくさんのplot手法を試して遊んでみます。
まず、複雑なplotで全体を見てみましょう。

multiplotを使って確認していきます。
library(multiplot)はver3.5までしか動かないようです。
multiでなく個別plotにしています。

p_age = ggplot(train) +
  geom_freqpoly(mapping = aes(x = Age, color = Survived), binwidth = 1) +
  guides(fill=FALSE) +
  theme(legend.position = "none")
p_age

02.png

生存した人を水色、生存できなかった人をオレンジ色で表示している。
生存と年齢の分布が確認できる。
これを見るとまず20~30代の人が多くのっていた。
18~30歳までの若い大人の生存率は少なく、10代の子供の生存率は高い。
問題になるような外れ値はなさそう。
最高年齢は分布と一致している。
10代はすくない。
2.1章よりも後で後で運賃と年齢の密度plotを行って細かくみる。

中央値はこのようにして確認する。

train %>%
  group_by(Survived) %>%
  summarise(median_age = median(Age, na.rm=TRUE))
## # A tibble: 2 x 2
##   Survived median_age
##   <fct>         <dbl>
## 1 0              28.0
## 2 1              28.0
p_sex = ggplot(train, mapping = aes(x = Sex, fill = Survived)) +
  geom_bar(stat='count', position='fill') +
  labs(x = 'Sex') +
  scale_fill_discrete(name="Surv") +
  theme_few()
p_sex

03.png
性別と生存の関係。
この図だけで単純に考えると女性であれば生存する確率が高そう。

p_class = ggplot(train, mapping = aes(x = Pclass, fill = Survived, colour = Survived)) +
  geom_bar(stat='count', position='fill') +
  labs(x = 'Pclass') +
  theme(legend.position = "none")
p_class

04.png

客室での生存率を見ると一等客室は生き残れる確率が高い。
命は平等ではない....

p_emb = ggplot(train, aes(Embarked, fill = Survived)) +
  geom_bar(stat='count', position='fill') +
  labs(x = 'Embarked') +
  theme(legend.position = "none")
p_emb

05.png

乗船位置による生存率の違い。
CはSよりも高い生存率になった。
他の変数との相関など調べてみたいと思う。

p_sib = ggplot(train, aes(SibSp, fill = Survived)) +
  geom_bar(stat='count', position='fill') +
  labs(x = 'SibSp') +
  theme(legend.position = "none")
p_sib

06.png

兄弟や配偶者の数と生存確率について

p_par = ggplot(train, aes(Parch, fill = Survived)) +
  geom_bar(stat='count', position='fill') +
  labs(x = 'Parch') +
  theme(legend.position = "none")
p_par

07.png

親子関係について

p_fare = ggplot(train) +
  geom_freqpoly(mapping = aes(Fare, color = Survived), binwidth = 0.05) +
  scale_x_log10() +
  theme(legend.position = "none")
p_fare

08.png

運賃と生存について。
極端に多い値があり、スケールが役に立ちません。
こんなときは対数軸を使います。
安い客室の場合、生存率が低くなっていますが、これは安い客室が救命艇から離れていたからでしょう。

tidyverseはあのチャンピオン、wickhamさんが作ったものです。
パッケージの集合体であり、データの表示や変更を行う共通言語になっています。
データの特徴についての観察がしやすい。
このデータはかなり整頓されているが、すべてのデータセットがこうとは限らない。
整頓されていない面倒なデータセットの例はtidyrのパッケージを確認してみてください。

pipe %>%を使うと、操作を連結させて行うことができます。
上の年齢の中央値の計算例では一つの特徴に対してgroup_byでtrainを操作し、年齢の平均値を計算しました。

summariseだけでなくcountすることもできます。

train %>%
  group_by(Survived, Sex) %>%
  count(Sex)
## # A tibble: 4 x 3
## # Groups:   Survived, Sex [4]
##   Survived Sex        n
##   <fct>    <fct>  <int>
## 1 0        female    81
## 2 0        male     468
## 3 1        female   233
## 4 1        male     109

男女の生存についてのカウント
(クロス集計表みたいなもの)

diplyrのmutateを使うと次のような操作でdataframeに新しい列を作り、列名を命名することができます(nやfreqなどの列)。

train %>% mutate(single = SibSp==0) %>% count(single) %>% group_by(single) %>% mutate(freq = n/nrow(train))
## # A tibble: 2 x 3
## # Groups:   single [2]
##   single     n  freq
##   <lgl>  <int> <dbl>
## 1 F        283 0.318
## 2 T        608 0.682

train %>% mutate(single = Parch==0) %>% count(single) %>% group_by(single) %>% mutate(freq = n/nrow(train))
## # A tibble: 2 x 3
## # Groups:   single [2]
##   single     n  freq
##   <lgl>  <int> <dbl>
## 1 F        213 0.239
## 2 T        678 0.761

これは乗船者の32%が兄弟と船にのっていたこと、
24%が親子で乗っていたことがわかる。

長くなるのでいったん切る
つづき↓
kaggleでデータ分析の基礎 #2【titanic, tidyr, dplyr,ggplot】

5
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
3