こんにちは、しゃおろんです。
SIGNATEというサイトで開催されているデータ分析コンペに参加しましたので、そのレポートをしたいと思います。
順位は37/64位(2019/03/16 時点)で、悪くない結果は出せたかなと思います。(5位~38位が同率なので、混戦でした。)
こんな人におすすめ
- データ分析コンペに参加してみたいけど、何から始めたらよいか分からない
- データ分析コンペってどんなものなのか、イメージを掴みたい
ご注意
- 機密情報保持の観点から、提供された生データは記載していません。(グラフ等で実際の数値は分からない形にしています。)
- 主は勉強を始めたばかりの初心者です。考え方など間違っている部分があると思います。もし気づいた方はコメントにて指摘いただけると助かります。
- コードは全て記載しているわけではありません。
テーマの確認
今回参加したのはコンペのテーマは、「アヤメの分類」です。
アヤメという花があるのですが、与えられたデータからその種類を予想してくださいという問題です。
↑アヤメの画像。きれいな花ですね。
練習問題と書いてある通り、賞金が出るような問題ではなくデータ分析を体感してみたいという人向けに作られた問題となっています。
データは「学習用データ」「評価用データ」「応募用サンプルファイル」の3つが用意されています。
- 学習用データ:モデルを学習させるために使用するデータ(説明変数と目的変数)
- 評価用データ:実際に予測をするために使用するデータ(説明変数のみ)
- 応募用ファイル:予測した値を記載するためのファイル
分析に使う環境とモデル
今回の分析で使用する環境及びモデルは以下です。
- プログラミング言語:Python
- 実行環境(分析する環境):JupyterNotebook
- モデル(分析手法):ランダムフォレスト分析
JupyterNotebookって何という方は、以下のUdemy講座で環境構築から解説されているので参考にされるとよいと思います。(普段は高額なので、セール時に購入することをおすすめします。)
【ゼロから始めるデータ分析】 ビジネスケースで学ぶPythonデータサイエンス入門
【キカガク流】人工知能・機械学習 脱ブラックボックス講座 – 初級編 –
モデルについては、今回はランダムフォレスト分析というものを使っていきます。今回はアヤメの種類を「分類」して予測する問題なので、分類系の手法であるランダムフォレスト分析を選択しました。

色んな手法を比較して決めたわけではなく、「ランダムフォレスト分析を勉強中なので使ってみたかった」というだけです。
ランダムフォレスト分析について知りたい方は、以下のサイトでイメージを掴むとよいと思います。
ランダムフォレスト分析の元になっている決定木分析について知りたい方は、下記のサイトもおすすめです。
データの確認
では実際に分析を行っていく前に、諸々準備を行います。
ライブラリのインストール
まず最初に必要なライブラリをインストールします。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
#いつも使うライブラリ import numpy as np import pandas as pd import seaborn as sns from matplotlib import pyplot as plt %matplotlib inline #ランダムフォレストモデル from sklearn.ensemble import RandomForestClassifier #訓練データとテストデータの分割用 from sklearn.model_selection import train_test_split #交差検証用 from sklearn.model_selection import cross_validate #表の列を省略せずに表示(50列まで) pd.set_option('display.max_columns', 50) |
データの読み込み
ライブラリがインストールできたら、サイトからダウンロードしたデータを読み込みます。(あらかじめ、JupyterNotebookを実行しているフォルダにダウンロードしたデータを入れておく必要があります。)
ファイルがTSV形式なので、pandas(インストールしたライブラリ)のread_table関数を使っていきます。(csvならread_csv)
1 2 3 |
train = pd.read_table("train.tsv") test = pd.read_table("test.tsv") sample = pd.read_csv("sample_submit.csv", header = None) |
データの確認
きちんと読み込めているかどうかは、head関数で確認します。
1 |
train.head() |
生データは見せられないのですが、項目は以下の通りです。
説明変数(予測に使うデータ)は、全部で4種類です。かなりコンペにしては少ない方ではないでしょうか。
「がく」とか「花弁」とかって久しぶりに聞きました。確か中学校くらいの理科の授業習いましたね。それらの長さや幅を使って、種類を見分けるわけですね。
目的変数となるのはアヤメの品種は全部で3種類となっています。「setosa」「virginica」「versicolor」どれも聞いたことないです。
基本統計量の確認
describe関数を使えば、基本統計量(データの平均値や標準偏差など)を簡単に調べることができます。
1 |
train.describe() |
countのところを見ると、各データの個数が分かります。それぞれ75となっているので、全部で75サンプルあることが分かります。コンペにあるデータの中では、かなり少ない方ではないでしょうか。
データ型の確認
info関数を使えば、データの型を調べることができます。
1 |
train.info() |
float64というのは、簡単に言うと数値形式のデータという意味です。objectは文字列形式のデータです。
全てnon-null(欠けているデータがない)となっており、分析しやすそうなデータですね。
基礎分析
次に、基礎分析として目的変数と各説明変数の関連性を調べていきます。このフェーズの中で、どの変数が予測に使えそうか考えます。
「がく片の長さ」と「アヤメの種類」
箱ひげ図を使って、アヤメの種類ごとのがく片の長さを調べます。

箱ひげ図はデータの分布がどうなっているかを可視化するのに便利です。
箱ひげ図の作成には、seabornというライブラリのboxplot関数を使います。
1 |
sns.boxplot(x = "class",y = "sepal length in cm", data = train) |
classによってとる値が違うことが分かります。分析に使えそうですね。
「がく片の幅」と「アヤメの種類」
同じように、各変数についても箱ひげ図を作っていきます。
青色のsetosaはだけ高い数値になっていますね。オレンジ色のversicolorと緑色のvirginicaはあまり差がありません。
「花弁の長さ」と「アヤメの種類」
青色のsetosaだけかなり離れたところにあります。先ほどまでの変数よりもはっきりとした差が表れており、この変数を使えばsetosaとそれ以外を予測するのは簡単そうです。
オレンジと緑にも差がありますが、重複しているエリア(4,5~5くらい)もあるので、完全に分離するのは難しそうです。
「花弁の幅」と「アヤメの種類」
こちらも同じくですね。青色のsetosaだけ離れており、かつデータのばらつきが非常に少ないために箱ひげ図が潰れたようになっています。
オレンジと緑も結構離れているので、かなり使えそうな変数だと分かります。
考察
分析した内容を踏まえて、どれが予測に使えそうかを考えます。
今回見てきた4変数はどれも目的変数と関連がありそうなので、分析に使用することにしました。(全くアヤメの種類と関係ないのであれば、箱ひげ図は横並びになるはず)
説明変数の作成
次に、新たな説明変数を作っていきます。
なぜ説明変数を作るのかということですが、以下の2点が理由になります。
- 今ある説明変数で一度分析をかけたところ、あまり精度が出なかった(といっても0.96のスコアは出た)
- versicolorとvirginicaの分類精度をより上げるために、今ある特徴量を組み合わせるといいのではないかと思ったから
今回追加した変数は以下の4つです。
- がく片の長さ+幅
- がく片の長さー幅
- 花弁の長さ+幅
- 花弁の長さー幅
1 2 3 4 |
train["sepal sum in cm"] = train["sepal length in cm"] + train["sepal width in cm"] train["sepal dif in cm"] = train["sepal length in cm"] - train["sepal width in cm"] train["petal sum in cm"] = train["petal length in cm"] + train["petal width in cm"] train["petal dif in cm"] = train["petal length in cm"] - train["petal width in cm"] |
なぜこのように和や差を使おうと思ったかには理由があります。
例えば花弁の長さと幅について見てみましょう。
どちらも緑がオレンジより上に来ています。そのため、「2つの変数を足し合わせれば、さらに緑がオレンジとの差が顕著になる(緑が上でオレンジが下)のではないか」と思い、2つの和を変数として使ってみようと考えました。
実際に足し合わせたものを見てみると、わずかですが差が顕著になっているような気がします。
また、差を使おうと思ったのは花弁の形が分類に影響するかもしれないなと思ったからです。
- 長さと幅の差が少ない:正方形に近い
- 長さと幅の差が大きい:長方形で細長い形
ひとまず変数も追加できたので、実際の分析に移っていきましょう。
モデルの構築
これからいよいよモデルの構築に入ります。
目的変数と説明変数の準備
目的変数をyに代入します。
1 2 |
#yに目的変数を代入 y = train["class"] |
次に、学習データから説明変数を取り出してtrainXという変数に代入します。
1 2 3 4 |
trainX = train[["sepal length in cm","sepal width in cm", "petal length in cm", "petal width in cm", "sepal sum in cm","sepal dif in cm", "petal sum in cm","petal dif in cm"]] |
モデルの作成
モデルを作成します。ランダムフォレスト分析なので「RandomForestClassifier」という関数を使います。
1 |
clf = RandomForestClassifier(max_depth=5, min_samples_leaf=5, max_features=4, n_estimators=100) |
()内には引数としてパラメーターを指定しています。
- 決定木の深さ:5
- 葉の最小サンプル数:5
- 使用する説明変数の数:4
- 作成する決定木の数:100
パラメータの設定値については、後述する交差検証をしながら良さそうな値を決めました。
作成したモデルを、データを使って学習させます。
1 |
clf.fit(trainX,y) |
交差検証による確認
続いて、交差検証を行っていきます。
交差検証とは、モデルの精度と信頼性を調べる手法のことです。
- モデルの精度がきちんと出ているか
- 過学習を起こしていないか(汎化性能が十分か)
を調べることができます。

過学習や交差検証については、冒頭で紹介したUdemy講座で解説されています。また、一般的な機械学習の書籍でも多く記載があります。
では実際にやってみましょう。
1 |
cross_validate(clf, trainX, y, cv=4, n_jobs=-1) |
今回は学習用データを4つに分けて交差検証を行いました。(cv=4で指定)
注目するのは、test_scoreとtrain_scoreです。
この2つの値の差が大きい(train_scoreの方が異常に高い)場合に過学習を起こしている可能性が高いのですが、そこまで大きな差はありませんでした。(0.888と1が若干怪しいですが)
交差検証の結果問題なしと判断し、次の工程に移ります。(もし結果がうまくいかなければ、ランダムフォレスト分析のパラメーターを変える、特徴量の入れ替えをするなどの工夫する必要があります。)
予測値の算出~ファイル出力
モデルが作成できたので、あとは予測値の算出です。もう一息ですね。
評価用データ(test)の加工
評価用データにも、学習データと同様に変数を追加します。
1 2 3 4 |
test["sepal sum in cm"] = test["sepal length in cm"] + test["sepal width in cm"] test["sepal dif in cm"] = test["sepal length in cm"] - test["sepal width in cm"] test["petal sum in cm"] = test["petal length in cm"] + test["petal width in cm"] test["petal dif in cm"] = test["petal length in cm"] - test["petal width in cm"] |
予測~ファイル出力
予測値を算出し、提出用ファイルに書き込みます。
1 2 3 4 5 6 |
# 予測値を算出してpredに代入 pred = clf.predict(testX) #sampleに予測結果を書き込む [1]は1という列を指す sample[1] = pred #CSVへ出力 sample.to_csv("submit.csv",header=None, index = None) |
いざ提出!結果は…
起動中のJupyterNotebookと同じフォルダにファイルが作成されるので、それをコンペティションのサイトから提出します。
結果は、37位(64人中)でした!(2019/3/16現在)
スコアは0.973となっており、0~1の値をとる評価基準のなのでかなり精度の高い分析ができたのではないでしょうか。
順位が思ったより低いかなと思ったのですが、すごい接戦のコンペで5位~38位までが同じスコアになっていました(笑)
考えようによっては5位ということで、ひとまず安心できる結果を出せました。
まとめ
いかがでしたでしょうか。
初心者なりに頑張って分析してみました。
正直改善できる余地はたくさんあると思うので、「もっとこうしたほうがいいよ!」というアドバイスやアイデアなどあればコメントに書いてくださると嬉しいです。
以上、しゃおろんでした。
コメント