初心者がデータ分析コンペにチャレンジしてみた!【SIGNATE】【ワインの品種予測】

コンペ

こんにちは、しゃおろんです。

SIGNATEというサイトで開催されているデータ分析コンペに参加しましたので、そのレポートをしたいと思います。

順位は18/71位(2019/03/24 時点)で、自分の中ではかなりいい結果は出せたかなと思います。(1位~19位までが同率なので、混戦でした。)

 

こんな人におすすめ

  • データ分析コンペに参加してみたいけど、何から始めたらよいか分からない
  • データ分析の流れを知りたい
  • 外れ値除去について知りたい
  • 交差検証について知りたい
  • 勾配ブースティング木を使ってみたい

ご注意

  • 機密情報保持の観点から、提供された生データは記載していません(グラフ等で実際の数値は分からない形にしています)
  •  主は勉強を始めたばかりの初心者です。考え方など間違っている部分があると思います。もし気づいた方はコメントにて指摘いただけると助かります
  • コードは全て記載しているわけではありません

 

テーマの確認

今回参加したのはコンペのテーマは、「ワインの品種予測」です。

【練習問題】ワインの品種の予測

ワインの化学成分から、使用されているぶどうの品種を予測するという問題です。

練習問題と書いてある通り、賞金が出るような問題ではなくデータ分析を体感してみたいという人向けに作られた問題となっています。

 

データは「学習用データ」「評価用データ」「応募用サンプルファイル」の3つが用意されています。

  • 学習用データ:モデルを学習させるために使用するデータ(説明変数と目的変数)
  • 評価用データ:実際に予測をするために使用するデータ(説明変数のみ)
  • 応募用ファイル:予測した値を記載するためのファイル

分析に使う環境とモデル

今回の分析で使用する環境及びモデルは以下です。

  • プログラミング言語:Python
  • 実行環境(分析する環境):JupyterNotebook
  • モデル(分析手法):勾配ブースティング木

 

JupyterNotebookが分からない方は、以下のUdemy講座で環境構築から解説されているので参考にされるとよいと思います。(普段は高額なので、セール時に購入することをおすすめします。)

【ゼロから始めるデータ分析】 ビジネスケースで学ぶPythonデータサイエンス入門

【キカガク流】人工知能・機械学習 脱ブラックボックス講座 – 初級編 –

 

モデルについては、今回は勾配ブースティング木というものを使っていきます。決定木モデルにブースティングという手法を組み合わせた分析です。

しゃおろん
しゃおろん

最近覚えたばかりの手法です。試しに使ってみました。

 

ブースティングについて知りたい方は、以下のサイトがイメージを掴みやすいと思います。弱学習器(精度の低い分析モデル)を組み合わせて高い精度のモデルを作るアンサンブル学習の一種です。

機械学習⑤ アダブースト (AdaBoost) まとめ

 

決定木分析について知りたい方は、下記のサイトがおすすめです。

[入門]初心者の初心者による初心者のための決定木分析

 

データの確認

実際に分析を行っていく前に、諸々準備を行います。

ライブラリのインストール

まず最初に必要なライブラリをインストールします。

 

データの読み込み

ライブラリがインストールできたら、サイトからダウンロードしたデータを読み込みます。(あらかじめ、JupyterNotebookを実行しているフォルダにダウンロードしたデータを入れておく必要があります。)

ファイルがTSV形式なので、pandas(インストールしたライブラリ)のread_table関数を使っていきます。(csvならread_csv)

 

データの確認

きちんと読み込めているかどうかは、head関数で確認します。

 

生データは見せられないのですが、項目は以下の通りです。

説明変数(予測に使うデータ)は、全部で13種類です。

アルコールやリンゴ酸は分かりますが、「フェノール」や「フラバノイド」は全く聞いたことないですね。ぱっと見ただけでは、どれが分析に使えそうか想像もつかないです。

目的変数となるワインの品種は全部で3種類となっています。

 

基本統計量の確認

describe関数を使えば、基本統計量(データの平均値や標準偏差など)を簡単に調べることができます。

この基本統計量の使い方は色々あると思いますが、私は「平均値」「最大値」「最小値」などをざっと見るために使っています。

 

データ型の確認

info関数を使えば、データの型を調べることができます。

float64というのは、簡単に言うと数値形式(小数点含む)のデータという意味です。intは整数形式のデータです。

全てnon-null(欠けているデータがない)となっているので、欠損値の処理は必要なさそうです。

サンプルは89個で、結構少ない印象を受けます。

 

基礎分析

次に、基礎分析として目的変数と各説明変数の関連性を調べていきます。

  • どの説明変数が使えそうか
  • 外れ値はあるのか

などを調べていきます。

 

今回の目的変数は、ワインの品種なのでカテゴリ型の変数です。散布図を使って相関関係を調べるのは適切ではないと考え、箱ひげ図を使って可視化していきます。

しゃおろん
しゃおろん

箱ひげ図はカテゴリごとのデータ分布を可視化するのに便利です。

 

全変数について述べると冗長になってしまうので、2つほどピックアップしますね。

 

「マグネシウム」と「ワインの品種」

箱ひげ図を使って、マグネシウムとワインの品種の関係を調べます。つまり、ワインの品種ごとにマグネシウムの値がどのように分布をしているか見ます。

箱ひげ図の作成には、seabornというライブラリのboxplot関数を使います。

 

品種ごとに分布は違いますが、あまり明確な違いはなさそうです。分類には少し使いづらい印象を受けます。例えばマグネシウムの値が100だった時、品種1~3どれもあり得そうですよね。

 

その他気になる点としては、外れ値があることです。オレンジの上にある点4つが外れ値を表します。このように外れた値があるまま分析をしてしまうと、モデルを作る際に外れ値を考慮してしまって予測精度が落ちる危険性があります。後ほど処理していきましょう。

しゃおろん
しゃおろん

例えばマグネシウムの値が120だった時、品種1or3と分類してほしいのですが、外れ値を考慮して学習してしまうと品種2と分類してしまう危険性が出てきます。

 

「色調」と「ワインの品種」

同じように、ワインの品種と色調について箱ひげ図を作っていきます。

 

こちらは、先ほどよりも明確に差が出ていますね。品種3(緑)が他よりもかなり違う分布をしているので、緑とその他を分類するのにはかなり有効な変数となりそうです。(Hueが0.8以下であれば、品種3である可能性がかなり高いです。)

 

考察

上記の2例のように、他の説明変数についても目的変数(ワインの品種)との関係を見ていきました。

結論としては、どの説明変数も目的変数に多少は関係がありそうだったため、全ての説明変数を使って分析することにしました。

 

データの前処理

どんな処理を行うか

基礎分析でデータの傾向を把握したので、実際にモデルを構築する前にデータの前処理を行っていきます。

前処理と一言で言っても、

  • 欠損値の処理
  • 外れ値の処理
  • 特徴量(説明変数)の追加
  • 特徴量(説明変数)の削除
  • スケーリング(各変数の大きさを揃える)

など色々ありますが、今回行う前処理は「外れ値の除去」のみです。

 

理由は以下の通りです。

  • 欠損値はinfo関数で調べて見つからなかったため
  • 外れ値は箱ひげ図で調べるとそれなりの数あったため
  • 特徴量の追加・削除はモデルの精度が出なかった場合に考えようと思ったため
  • スケーリングは決定木モデルの場合必要でないため

 

外れ値の除去

外れ値の除去には、3σ法を使います。(σはシグマと読みます)

σは標準偏差のことで、「平均値±3σ離れたデータは外れ値とみなす」というのが3σ法です。

イメージが湧かない方は、以下を参考にされるとよいと思います。

1σ、2σ、3σの意味と正規分布の場合の確率

 

では実際に外れ値の除去をしていきましょう。

まずは3σ法に必要な「平均値」と「標準偏差」を調べます。それぞれmean関数とstd関数を使います。

 

次にfor文を使って各列を見ていき、外れ値を除去します。流れは以下です。

  1. 3σ法における境界値(平均値±3σ)を求める
  2. 求めた境界値を、それぞれlowとhighという変数に格納する
  3. lowとhighを使ってデータを絞り込む(3σ内のデータのみを取り出す)
  4. 1~3を各列について繰り返す

 

実際にどれくらい外れ値が除去されたかは、len関数を使って調べることができます。

結果は「84」となりました。冒頭でデータ数が「89」であることを確認していたので、5つのデータが外れ値として削除されたことになります。

 

また、もう一度箱ひげ図を作成してみるとどのデータが削除されたかも分かります。

先ほど使った「マグネシウム」と「ワインの品種」の箱ひげ図について、外れ値の除去前と後を比べてみましょう。

形が変わっていることが分かりますね。上の図ではマグネシウムの値が150のデータが存在しますが、下の除去後の図では存在しません。うまく外れ値を除去できているようですね。

しゃおろん
しゃおろん

「下の図にもまだ外れ値がある」と考える方もいるかもしれませんが、今回の3σ法は「マグネシウム」という変数に対して実施しただけであって「品種2のマグネシウム」についての外れ値を除去したわけではないので、問題ないと考えます。

 

モデルの構築

前処理も終わったので、いよいよモデルの構築に入ります。

目的変数と説明変数の準備

目的変数をyに代入します。

 

次に、学習データから説明変数を取り出してtrainXという変数に代入します。

ilocを使えばデータフレームの指定の範囲を取り出すことができます。(_dfの「全ての行」と「2列目から最後の列まで」のデータを取り出しています)pandasでは一番左の列を0列目と数えるので、上記でAlcoholから最後の列までを取り出すことができます。

モデルの作成

モデルを作成します。今回は勾配ブースティング木ということで、scikit-learnというライブラリの「GradientBoostingClassifier」という関数を使います。

()内には引数としてパラメーターを指定しています。

  • 決定木の深さ:2
  • 学習率:0.1
  • 使用する説明変数の最大数:3
  • 作成する決定木の数:1000
  • 乱数のシード:3

パラメータの設定値については、後述する交差検証をしながら良さそうな値を決めました。調整したパラメータは「決定木の深さ」「学習率」「使用する説明変数の最大数」「作成する決定木の数」の4つですが、どれも値が大きくなると過学習を起こしやすくなり、反対に値が小さいと精度が出なくなる性質を持っています。ここを上手く調整するのがモデルを作る上で難しい所ですね。

乱数のシードについては、3という数字に特に意味はなく、乱数によって結果がばらけないように固定しているだけです。

交差検証によるパラメーターの調整

続いて、交差検証を行っていきます。

交差検証とは、モデルの精度と信頼性を調べる手法のことです。

  • モデルの精度がきちんと出ているか
  • 過学習を起こしていないか(汎化性能が十分か)

を調べることができます。

しゃおろん
しゃおろん

過学習や交差検証については、冒頭で紹介したUdemy講座で解説されています。また、一般的な機械学習の書籍でも多く記載がありますので、分からない方は調べてみてください。

 

私の場合、各パラメーターの値を色々変えながら交差検証を行って、よさそうなパラメーターを選んでいます。(パラメーター調整にはグリッドサーチと言う有名な方法がありますが、今回は手動調整したほうがよい結果が出たのでこちらを記載しています。)

 

では実際にやってみましょう。

今回は学習用データを3つに分けて交差検証を行いました。(cv=3で指定)

 

注目するのは、test_scoreとtrain_scoreです。

  • test_score:検証用データに対しての精度
  • train_score:訓練用データに対しての精度

この2つの値の差が大きい(train_scoreの方が異常に高い)場合に過学習を起こしている可能性が高いです。今回の場合、train_scoreがすべて1になっているのが気になりますが、test_scoreも平均して約0.96と高い数値を記録しています。

交差検証の結果問題なしと判断し、次の工程に移ります。

 

モデルの学習

作成したモデルを、データを使って学習させます。

 

予測値の算出~ファイル出力

モデルが作成できたので、あとは予測値の算出です。

今回は前処理において「説明変数の追加」などは行わなかったので、ほとんど加工せずに評価用データを使っています。予測にはpredict関数を使います。

これで提出用のCSVデータが起動中のJupyterNotebookと同じフォルダに作成されます。

 

いざ提出!結果は…

作成したファイルをコンペティションのサイトから提出します。

結果は 18位(71人中)でした!(2019/3/24 時点)

スコアは1.00となっているので、「評価用データの全ての品種予測に成功した」ということになります。

未知のデータを完璧に予測できるというのは普通あり得ないのですが、今回は評価用データの数が少ない(89個)だったので、的中率100%という結果になったのだと思います。

 

まとめ

いかがでしたでしょうか。

初心者なりに頑張って分析してみました。

スコア自体は最高の結果となったのですが、実はこの結果に至るまでに何度も結果投稿をしています。

↑ランダムフォレストという他のモデルも試しましたし、パラメータ調整ではグリッドサーチも試しました。

 

良い結果となったのは「数を撃ったら偶然当たった」という要素が強いので、どのように分析の質を上げるかが今後の課題だと思っています。

しゃおろん
しゃおろん

グリッドサーチをもっとうまく使いこなせるようになりたい。。

以上、しゃおろんでした。

コメント

タイトルとURLをコピーしました