【SIGNATE】本の知識だけでSIGNATEの練習問題に挑戦してみた


書籍「[第2版]Python機械学習プログラミング 達人データサイエンティストによる理論と実践」から得た知識を基に、
SIGNATEの練習問題に挑戦してみた

開発環境

  • MacOS Catalina 10.15.3
  • Anaconda Navigator 1.9.7
  • Python 3.7
  • Jupiter Notebook 6.0.1

今回挑戦した練習問題

【練習問題】自動車の評価

  • 6つの自動車の属性データから、評価値(unacc, acc, good, vgood)を予測する
  • 属性データ(特徴量)は以下の6つ
属性名 説明
buying 車の売値(vhigh, high, med, low)
maint 整備代(vhigh, high, med, low)
doors ドアの数(2, 3, 4, 5, more.)
persons 定員(2, 4, more.)
lug_boot トランクの大きさ(small, med, big.)
safety 安全性(low, med, high)

問題を解いてみた

まずはデータセットの内容を確認

# データセットを読み込むためにpandasをインポートする
import pandas as pd

# pandasのread_csvメソッドを用いてトレーニングデータ(train.tsv)を読み込む
# トレーニングデータはサイトからダウンロード済み
train_data = pd.read_csv('./train.tsv', delimiter='\t')

# トレーニングデータを表示
train_data

特徴量の文字列データは数値に変換すべしと本に書いてあったので、データの文字列を数値に変換する
 ※今回用いたデータセットに含まれる特徴量は全て順序特徴量に分類されるものなので、単純に文字列を順序通りに数値に変換した

# 各特徴量の変換用の辞書を設定する
buying_mapping = {'vhigh': 4, 'high': 3, 'med': 2, 'low': 1}
maint_mapping = {'vhigh': 4, 'high': 3, 'med': 2, 'low': 1}
doors_mapping = {'5more': 5, '4': 4, '3': 3, '2': 2}
persons_mapping = {'more': 6, '4': 4, '2': 2}
lug_boot_mapping = {'big': 3, 'med': 2, 'small': 1}
safety_mapping = {'high': 3, 'med': 2, 'low': 1}

# クラスラベル(class)の変換用の辞書を設定する
class_mapping = {'vgood': 4, 'good': 3, 'acc': 2, 'unacc': 1}

# トレーニングデータの各特徴量を変換する
train_data['buying'] = train_data['buying'].map(buying_mapping)
train_data['maint'] = train_data['maint'].map(maint_mapping)
train_data['doors'] = train_data['doors'].map(doors_mapping)
train_data['persons'] = train_data['persons'].map(persons_mapping)
train_data['lug_boot'] = train_data['lug_boot'].map(lug_boot_mapping)
train_data['safety'] = train_data['safety'].map(safety_mapping)

# トレーニングデータのクラスラベル(class)を変換する
train_data['class'] = train_data['class'].map(class_mapping)

# 変換後のトレーニングデータを表示
train_data

変換完了

トレーニングデータを特徴量とクラスラベルに分ける

# pandasのilocメソッドを用いてトレーニングデータを特徴量(train_data_X)とクラスラベル(train_data_Y)に分離する
# idは学習に用いないため別に保管する
train_data_X = train_data.iloc[:,2:]
train_data_Y = train_data.iloc[:,1:2]
train_data_id = train_data.iloc[:,0:1]

最後に、トレーニングデータを学習用データと検証用データに分割する

from sklearn.model_selection import train_test_split

# トレーニングデータを学習用データ(learning_data)と検証用データ(learning_data)に分割する
learning_data_X, validation_data_X, learning_data_Y, validation_data_Y = train_test_split(
    train_data_X, train_data_Y, test_size=0.3, random_state=1, stratify=train_data_Y)

これで学習のための準備はできた

とりあえずロジスティック回帰でやってみた

ロジスティック回帰が一番簡単そうだったので、とりあえずロジスティック回帰でやってみた

特徴量はスケーリングすべしと本に書いてあったので、まずは特徴量の標準化を行う

from sklearn.preprocessing import StandardScaler

stdsc = StandardScaler()

stdsc.fit(learning_data_X)

# トレーニングデータの特徴量の標準化を行う
learning_data_X_std = stdsc.transform(learning_data_X)
validation_data_X_std = stdsc.transform(validation_data_X)

標準化前のデータ(learning_data_X)はこんな感じ

標準化後のデータ(learning_data_X_std)はこんな感じ

データを見てもよく分からないが、標準化できたっぽい

学習用データを用いてロジスティック回帰クラスを学習する

from sklearn.linear_model import LogisticRegression

lr = LogisticRegression(C=100.0, random_state=1)

# 標準化した学習用データを用いてロジスティック回帰クラスを学習する
lr.fit(learning_data_X_std, learning_data_Y)

最後に、検証用データを用いて予測する

score = lr.score(validation_data_X_std, validation_data_Y)
score

今回作成したモデルのスコアは79.23%
ちなみに、SIGNATEではこの問題に対するモデルのランキングを公表しており、現時点での1位は100%、100位で96.875%
(今回作ったモデル、絶望的に精度悪いな。。)

本をちょろっと読んだだけだとまだまだ駄目やね。精進しなければ。

おわり

今回のロジスティック回帰のモデルはハイパーパラメータ(C)の最適化も正則化項の最適化も行っていません
(C=1.0で計算したらscoreが77.69%に下がったのでひょっとしたら奇跡的にええ感じのパラメータを選択したかもしれませんが)

まだまだ改良の余地があるので、今後このモデルを改良していきます
(とりあえず90%のscoreが出るまで頑張りますか)