テービーテックのデータサイエンス

未経験リケジョがゼロからデータサイエンティストを目指す姿を記す奮闘記です

TAG index

Kaggleに挑戦しよう! ~コード説明2~

f:id:tbtech:20190422094235j:plain
今回はコード説明の後編です!解析結果はどうなったか!?
最後までどうぞお付き合いください^^

コード内容

前回の最後のデータの状態を表示します。
目的変数である'state'はbool型に、説明変数である'goal'~'usdpledged'はfloat型になっています。
'main_category'と'currency'はobject型のままです。
f:id:tbtech:20190423114858p:plain

前回インポートしたライブラリを再掲します。

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline  #matplotlibのグラフを表示する
import seaborn as sns #matplotlibより美しいグラフの描画
from sklearn.preprocessing import StandardScaler #preprocessing:前処理  StandardScaler:標準化
from sklearn.model_selection import train_test_split #データを訓練データとテストデータに分割する
from sklearn.linear_model import SGDClassifier #クラス分類をする
from sklearn.metrics import log_loss, accuracy_score, precision_recall_fscore_support, confusion_matrix 
#log_loss:対数尤度 ,accuracy_score:正答率 ,precision_recall_fscore_support:適合率,再現率,F1値 ,confusion_matrix:クロス集計表
from sklearn.metrics import mean_absolute_error #平均絶対誤差
import datetime as dt #日時を扱う


前処理(後半)

相関係数と無相関化
変数それぞれの相関係数(correlation coefficient)を求めます。

df.corr()

f:id:tbtech:20190423092323p:plain

さらに相関係数をヒートマップにして可視化することで
色で相関の強さが見易くなります。
ここでsnsはseabornのこと(ライブラリのインポート時に設定)です。

sns.heatmap(df.corr())
plt.show()

f:id:tbtech:20190423093637p:plain

相関が強い変数があると学習が不安定になり、係数の解釈性に信用性がなくなることがあります。
以上の結果から相関がとても強い'pledged'と'usdpledged'の無相関化をします。

df_pledged = pd.DataFrame({'pledged' : df['pledged'], 'usdpledged' : df['usdpledged']})
  #元のdf(データフレーム)から対象の変数を抽出して新たなdfに入れる
cov = np.cov(df_pledged, rowvar=0) # 分散・共分散を求める
_, S = np.linalg.eig(cov)           # 分散共分散行列の固有ベクトルをSへ代入
pledged_decorr = np.dot(S.T, df_pledged.T).T #データを無相関化 .Tは転置

無相関化した2つをグラフにプロットし、相関係数を求めます。

print('相関係数: {:.3f}'.format(np.corrcoef(pledged_decorr[:, 0], pledged_decorr[:, 1])[0,1])) #相関係数を表示
plt.grid(which='major',color='black',linestyle=':') #主罫線について
plt.grid(which='minor',color='black',linestyle=':') #副罫線について
plt.plot(pledged_decorr[:, 0], pledged_decorr[:, 1], 'o') #プロットするデータとプロットに使う記号について
plt.show()

f:id:tbtech:20190423113550p:plain

無相関化した'pledged'と'usdpledged'を元のデータフレームに戻します。

df['pledged'] = pledged_decorr[:,0]
df['usdpledged'] = pledged_decorr[:,1]

ダミー変換
最後にobject型のまま残っている'main_category'と'currency'をダミー変換します。
ダミー変換とは質的データを量的データに変換する方法です。
例)fruitsの中にいくつかのフルーツが入っています。
  ダミー変換をすることで0と1の数値(量的)データに変換することができます。
f:id:tbtech:20190423130706j:plain

まずは'main_category'の中身を確認します。

df['main_category'].unique()

f:id:tbtech:20190423132412p:plain

15個のカテゴリーに分かれていることがわかります。
これをダミー変換します。

df_dummy = pd.get_dummies(df['main_category'])
#ダミー変換した'main_category'をdf_dummyに入れる。
df = pd.concat([df.drop(['main_category'],axis=1),df_dummy],axis=1)
#元のdfにdf_dummyを結合する。axis=1を付けると横に結合する。
df_crdf

f:id:tbtech:20190423132710j:plain
'main_category'のダミー変換が出来ました。
同様に'currency'のダミー変換するとデータは以下のようになります。
f:id:tbtech:20190423133714j:plain

ホールドアウト法
ホールドアウト法とは、データを予め訓練用とテスト用に分割しておき、
学習させたモデルを評価データで把握し、モデルの精度を確かめる方法のことです。

y = df['state'].values #'state' の値をyに代入する
X = df.drop('state', axis=1).values #'state'以外の変数をXに代入する

test_size = 0.3 #テストデータの割合を決める
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=test_size, random_state=1234)
#訓練データとテストデータに分割し、それぞれ変数に代入する


標準化
標準化とは、与えられたデータを平均が0で分散が1のデータに変換することで、
データスケールを揃えて、計算や比較をしやすくします。

stdsc = StandardScaler()
X_train_stand = stdsc.fit_transform(X_train) #訓練データの標準化
X_test_stand = stdsc.transform(X_test) #テストデータの標準化


学習と結果

前処理長かったーー
いよいよ学習を行います!
今回は分類問題なので、ロジスティック回帰で解析をします。
学習のインスタンス化をした後、.fitで学習を実行します。

clf = SGDClassifier(loss='log', penalty='none', max_iter=10000, fit_intercept=True)
#loss:損失関数 max_iter:学習の最大回数 fit_intercept:切片を求める
clf.fit(X_train, y_train)

学習が終わったら結果の表示をします。
今回表示するのは、対数尤度・正答率・適合率・再現率・F1値です。

y_prd_train = clf.predict(X_train)

print('対数尤度 = {:.3f}'.format(- log_loss(y_train, y_prd_train))) # '対数尤度 を表示
print('正答率(Accuracy) = {:.3f}%'.format(100 * accuracy_score(y_train, y_prd_train))) # 正答率を表示
precision, recall, f1_score, _ = precision_recall_fscore_support(y_train, y_prd_train) #適合率・再現率・F1値を計算
print('適合率(Precision) = {:.3f}%'.format(100 * precision[0])) # 適合率を表示
print('再現率(Recall) = {:.3f}%'.format(100 * recall[0])) # 再現率を表示
print('F1値(F1-score) = {:.3f}%'.format(100 * f1_score[0])) #F1値を表示

結果はこのように表示されました。

f:id:tbtech:20190426233134j:plainf:id:tbtech:20190513131731p:plain
訓練用・テスト用データの結果
全ての値が高い!単純なモデルなのに高すぎる!!
これはどこかに誤りがあると考えられます。

次回はコードの修正をしていきたいと思います。
皆さんはどこに間違いがあったかわかりますか??わかったら教えてーー