俺人〜OREGIN〜俺、バカだから人工知能に代わりに頑張ってもらうまでのお話

俺って、おバカさんなので、とっても優秀な人工知能を作って代わりに頑張ってもらうことにしました。世界の端っこでおバカな俺が夢の達成に向けてチマチマ頑張る、そんな小さなお話です。現在はG検定に合格し、E資格取得とKaggle参画に向けて、Pythonや機械学習の勉強中です。まだまだ道半ばですが、お時間がありましたら見て行ってください。

ep4-1: オライリー・ジャパン社「実践 機械学習システム」に学ぶ。

「Kaggle」のデータセットKickstarter Projects」の取り組みで、かなり苦戦したので、今一度、基礎から学ぶために、オライリージャパン社の「実践 機械学習システム」に取り組んでまいります。

今回は、データの読み込みと欠損値の処理を学びます。

では、順に取り組んでいきます。

この書籍では、実践というだけあって、さっそく、増加するWebアクセスに対応するために、サーバなどのインフラ整備が必要となっているWeb関連のベンチャー企業を想定して、分析がはじまります。

 1.まずは、ライブラリのインポート。

#各ライブラリのインポート
import matplotlib.pyplot as plt
import scipy as sp 

図形描画用にmatplotlib、機械学習処理用にscipyをインポート。

2.データを読み込みます。

#経過時間ごとのアクセス数のデータをタブ区切りで読み込む
data = sp.genfromtxt("web_traffic.tsv", delimiter="\t")
#最初の10個を表示
print(data[:10])
[[1.000e+00 2.272e+03]
[2.000e+00 1.656e+03]
[3.000e+00 1.386e+03]
[4.000e+00 1.365e+03]
[5.000e+00 1.488e+03]
[6.000e+00 1.337e+03]
[7.000e+00 1.883e+03]
[8.000e+00 2.283e+03]
[9.000e+00 1.335e+03]
[1.000e+01 1.025e+03]]
タブ区切りで、一列目が経過時間、二列目がアクセス数にんっている敵sとファイルからデータを読み込みます。
scipyのgenfromtxtメソッドの引数にファイル名と、区切り文字(delimiter)を指定することでファイルを読み込みます。

3.欠損値を取り除く。

#経過時間の列(0)をxに格納
x = data[:, 0]
#アクセス数の列(1)をyに格納
y = data[:, 1]

#isnanメソッドを使って欠損値を表示
print("欠損値:", sp.sum(sp.isnan(y)))

#欠損値を除外
x = x[~sp.isnan(y)]
y = y[~sp.isnan(y)]
欠損値: 4

scipyのisnanメソッドにアクセス数の列(y)を渡すことで、yが「nan」欠損値であるデータを、真理型(ブーリアン型)で取得。

sumメソッドで、欠損値の数を合計して表示。

欠損値が4個あったので、~sp.isnan(y)とすることで、欠損以外のインデックスを取得して、欠損以外のx,yを取得。 

 4.データを散布図描画する。

plt.scatter(x,y)
plt.title("Web traffic over the last month")
plt.xlabel("Time")
plt.ylabel("Hits/hour")
plt.xticks([w*7*24 for w in range(10)],['week %i'%w for w in range(10)])
plt.autoscale(tight=True)
plt.grid()
plt.show()
 

f:id:kanriyou_h004:20190623224733p:plain

データを分析にあたって、まずは、散布図にプロットしてみます。

この図から、最初のほうは、あまりアクセスが伸びていませんが、4週目から急激にアクセスが高まっていることが分かります。

今回は、データの内容を確認するところまで取り組みました。

次回からは、この情報をもとに将来のアクセス数を予測する回帰モデルを考えていきます。

 

 2019年3月9日(土)にG検定を受験し、見事合格できました!

受験の体験記や勉強法などを別のブログにまとめました。

これから受験される方がいらっしゃいましたらご参考まで。

g-kentei.hatenablog.com

 

 

 

エピソード3-14: AdaBoostのまとめ(KaggleでKickstarter Projectsに挑戦する。)

「Kaggle」のデータセットKickstarter Projects」に取り組んでいます。

前回挑戦した、木モデルのAdaBoostのコードをまとめました。

前回の記事は、以下にありますので、ご参照ください。

oregin-ai.hatenablog.com

 

では、さっそくまとめです。

 1.まずは、データ読み込み、モデルの定義、学習、評価です。

#********************************************************************
# pandas,numpy,matplotlib,codecs,sklearnの各ライブラリをインポート
#********************************************************************

%matplotlib inline
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import codecs as cd
from sklearn.preprocessing import LabelEncoder
# ホールドアウト法に関する関数
from sklearn.model_selection import train_test_split
# 交差検証法に関する関数
#from sklearn.model_selection import KFold
# 回帰問題における性能評価に関する関数
#from sklearn.metrics import mean_absolute_error
from sklearn.ensemble import AdaBoostClassifier
from sklearn.tree import DecisionTreeClassifier

#********************************************************************
#.該当課題のデータを読み込む
#********************************************************************
#201801のデータを読み込んでみる
with cd.open('ks-projects-201801.csv', 'r', 'utf-8', 'ignore') as f18:
    df_f18 = pd.read_csv(f18)
#df_f18 = pd.read_csv('ks-projects-201801.csv')

#********************************************************************
#.欠損値がある行は、とりあえずなくしてみる
#********************************************************************
#1個でも欠損値がある行はとりあえず削除してみる。
df_f18_dna = df_f18.dropna(how='any')

#********************************************************************
#.成功('successful')と失敗('failed')に絞って考える。
#********************************************************************
#成功だけを抽出したDFと失敗だけを抽出したDF
df_f18_success = df_f18_dna[df_f18_dna['state']=='successful']
df_f18_failed =  df_f18_dna[df_f18_dna['state']=='failed']
#両方を結合
df_f18_SorF = pd.concat([df_f18_success,df_f18_failed])

#********************************************************************
#.'state'をカテゴリ変数(文字列)から数値化してみる。
#********************************************************************
#LabelEncoderのインスタンスを生成
le = LabelEncoder()

#stateに出てくるカテゴリを覚えて
#stateを数値に変換
le = le.fit(df_f18_SorF['state'])
df_f18_SorF['state'] = le.transform(df_f18_SorF['state'])

#********************************************************************
#.'deadline' 'launched' の項目から期間'days'を日数で割り出す
#********************************************************************
# 'deadline' 'launched' の項目をdatetimeに変更
df_f18_SorF['deadline'] = pd.to_datetime(df_f18_SorF['deadline'], errors = 'coerce')
df_f18_SorF['launched'] = pd.to_datetime(df_f18_SorF['launched'], errors = 'coerce')
# 'deadline' 'launched' の間の日数を示す'period'を作成
df_f18_SorF['period'] = df_f18_SorF['deadline'] - df_f18_SorF['launched']

days = []

#'period'の日数を'days'に抽出
for i in df_f18_SorF.index:
    days.append(df_f18_SorF['period'][i].days)
#'days'列を追加
df_f18_SorF['days'] = days

#####################################
#異常値を除いたデータフレームを作る。
#####################################
#goalの異常値を除いたデータフレーム
df_train = df_f18_SorF[df_f18_SorF['goal']<99999999]

#####################################
#country,main_category,categoryをOne-Hotに変換する。
#####################################
df_train = pd.get_dummies(df_train, columns=['country', 'category', 'main_category'])

#####################################
#stateを正解データに格納
#####################################
train_label = df_train['state']

##########################################################################
#相関が強いカラムやLeakageにになるデータを訓練データに格納
##########################################################################
train_data = df_train.drop(['state','name','currency','deadline','goal','launched','pledged','backers','usd pledged','usd_pledged_real','period'], axis=1)

##########################################################################
#訓練データを標準化
##########################################################################
train_data = (train_data - train_data.mean()) / train_data.std()
train_data = train_data.astype('float32')

##########################################################################
#ホールドアウト法用に、正解データ、訓練データ30%をテストデータに分割
##########################################################################

#正解データをadB_train_labelに格納
adB_train_label = train_label

#訓練データをadB_train_dataに格納
adB_train_data = train_data

#目的変数として格納
adB_y = adB_train_label.values
#説明変数として格納
adB_X = adB_train_data.values

# 全データのうち、30%をテストデータにする
test_size = 0.3

# ホールドアウト法を実行(テストデータはランダム選択)
#X_train : 学習用データの説明変数
#X_test : テスト用データの説明変数
#y_train : 学習用データの目的変数
#y_test : テスト用データの目的変数
adB_X_train, adB_X_test, adB_y_train, adB_y_test = train_test_split(adB_X, adB_y, test_size=test_size,shuffle=True, random_state=1234) 

print(adB_X_train.shape, adB_X_test.shape, adB_y_train.shape, adB_y_test.shape)


##########################################################################
# AdaBoost で学習して、検証する
##########################################################################

#AdaBoostのモデルを定義する。
clf = AdaBoostClassifier(DecisionTreeClassifier(max_depth=5,min_samples_split=2,random_state=1234,criterion="gini"),
                                           n_estimators=10, random_state=1234)

#学習用データの説明変数、目的変数を投入して学習させる。
clf.fit(adB_X_train, adB_y_train)

#テスト用データの説明変数、目的変数を投入して精度を計測
print("score=", clf.score(adB_X_test, adB_y_test))

 
 

 (144879, 199) (62091, 199) (144879,) (62091,)
score= 0.6750253659950718

 

精度約67.5%になりました。

2.AdaBoostでつかわれた説明変数の重要度を表示する。

##########################################################################
# AdaBoost でつかわれた説明変数の重要度を表示する
##########################################################################
# 説明変数の重要度を出力する
# scikit-learnで算出される重要度は、ある説明変数による不純度の減少量合計である。
print(clf.feature_importances_)

# 説明変数の重要度を棒グラフに出力する。
pd.DataFrame(clf.feature_importances_, index=adB_train_data.columns).plot.barh(figsize=(12,50))
plt.ylabel("Importance")
plt.xlabel("Features")
plt.show()
 
[3.50707810e-02 2.30742752e-01 1.58811101e-01 9.69195292e-05
 0.00000000e+00 0.00000000e+00 2.77095603e-03 0.00000000e+00
 0.00000000e+00 0.00000000e+00 0.00000000e+00 7.29870047e-03
 7.67638063e-03 0.00000000e+00 0.00000000e+00 9.52794058e-03
 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00
 0.00000000e+00 0.00000000e+00 9.33016278e-04 0.00000000e+00
 2.09143949e-02 0.00000000e+00 0.00000000e+00 0.00000000e+00
 0.00000000e+00 0.00000000e+00 0.00000000e+00 6.02587494e-03
 7.03440515e-03 2.30263896e-02 0.00000000e+00 8.04301672e-03
 6.45899611e-03 0.00000000e+00 0.00000000e+00 0.00000000e+00
 0.00000000e+00 7.40386380e-03 0.00000000e+00 0.00000000e+00
 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00
 1.39750219e-02 0.00000000e+00 0.00000000e+00 0.00000000e+00
 0.00000000e+00 0.00000000e+00 0.00000000e+00 1.41854324e-02
 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00
 1.17201244e-02 0.00000000e+00 8.72104061e-04 0.00000000e+00
 1.03643882e-02 0.00000000e+00 0.00000000e+00 1.03431189e-02
 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00
 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00
 0.00000000e+00 0.00000000e+00 0.00000000e+00 1.59313470e-02
 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00
 1.45405034e-02 2.36162592e-03 9.82046628e-04 0.00000000e+00
 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00
 8.66177741e-03 1.86984038e-02 0.00000000e+00 1.07456405e-02
 0.00000000e+00 4.14680957e-03 0.00000000e+00 0.00000000e+00
 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00
 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00
 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00
 0.00000000e+00 1.31248527e-02 0.00000000e+00 0.00000000e+00
 0.00000000e+00 0.00000000e+00 1.67098393e-02 7.55402554e-03
 1.22862312e-02 0.00000000e+00 0.00000000e+00 0.00000000e+00
 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00
 5.14933165e-03 0.00000000e+00 8.62415738e-03 9.11693043e-03
 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00
 0.00000000e+00 0.00000000e+00 1.97530331e-02 1.42642270e-02
 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00
 1.07982519e-02 0.00000000e+00 0.00000000e+00 0.00000000e+00
 8.72895402e-03 0.00000000e+00 0.00000000e+00 0.00000000e+00
 0.00000000e+00 0.00000000e+00 1.73620667e-02 0.00000000e+00
 1.61140446e-02 0.00000000e+00 0.00000000e+00 0.00000000e+00
 0.00000000e+00 1.41038421e-02 0.00000000e+00 1.08539936e-02
 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00
 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00
 0.00000000e+00 1.26968044e-02 0.00000000e+00 0.00000000e+00
 1.48688407e-02 0.00000000e+00 0.00000000e+00 0.00000000e+00
 9.61709583e-04 0.00000000e+00 0.00000000e+00 0.00000000e+00
 0.00000000e+00 1.75750763e-02 1.07361126e-02 1.40192152e-02
 0.00000000e+00 1.48441349e-02 0.00000000e+00 3.37067926e-03
 0.00000000e+00 0.00000000e+00 2.34368301e-02 0.00000000e+00
 0.00000000e+00 1.33985757e-02 2.01844068e-02]
 

 f:id:kanriyou_h004:20190622222312p:plain

 

以上、AdaBoostのまとめでした。

次回からは、先日購入した、オライリー・ジャパンの「実践 機械学習システム」にて勉強していきたいと思います。

 2019年3月9日(土)にG検定を受験し、見事合格できました!

受験の体験記や勉強法などを別のブログにまとめました。

これから受験される方がいらっしゃいましたらご参考まで。

g-kentei.hatenablog.com

 

 

 

エピソード3-13: AdaBoostに挑戦してみる。Acc66%→67.5%(KaggleでKickstarter Projectsに挑戦する。)

「Kaggle」のデータセットKickstarter Projects」に取り組んでいます。

今回は、一度NNモデルから離れて、木モデルのAdaBoostに挑戦します。

NNモデルの記事は、以下にありますので、ご参照ください。

oregin-ai.hatenablog.com

 

では、さっそく取り組んでまいります。

 1.まずは、Leakageになりそうなカラム、相関が強いカラムをドロップする。

# ラベルデータとして’state’を採用する。
train_label = df_train['state']

# Leakageになりそうなカラム、相関が強いカラムをドロップする
train_data = df_train.drop(['state','name','currency','deadline','goal','launched','pledged','backers','usd pledged','usd_pledged_real','period'], axis=1) 

 

2.標準化する。

# 標準化 
train_data = (train_data - train_data.mean()) / train_data.std()
train_data = train_data.astype('float32') 

平均との差分を、標準偏差で割って、値を標準化します。 

3.ホールドアウト法で、最終的に性能を見るためのテストデータを別にする。

テストデータは30%にします。

#ホールドアウト法に関する関数をインポートする。
from sklearn.model_selection import train_test_split
# 交差検証法に関する関数をインポートする。
from sklearn.model_selection import KFold
#目的変数'state'を正解としてyに格納
adB_y = adB_train_label.values
#カラムをドロップした説明変数を、Xに格納
adB_X = adB_train_data.values

# 全データのうち、30%をテストデータにする
test_size = 0.3

# ホールドアウト法を実行(テストデータはランダム選択)
#X_train : 学習用データの説明変数
#X_test : テスト用データの説明変数
#y_train : 学習用データの目的変数
#y_test : テスト用データの目的変数
adB_X_train, adB_X_test, adB_y_train, adB_y_test = train_test_split(adB_X, adB_y, test_size=test_size,shuffle=True, random_state=1234) 

print(adB_X_train.shape, adB_X_test.shape, adB_y_train.shape, adB_y_test.shape)

 (144879, 199) (62091, 199) (144879,) (62091,)

学習用のデータが144879個、テスト用のデータが62091個に分離できました。

4.max_depth(木の深さ)を変化させて、Accuracyが最大になる値を探す。

AdaBoostを使って、木の深さを変化させて、検証データのAccuracyが最大になる値を探索することにしました。
探索にあたっては、交差検証法(クロスバリデーション)を利用しました。
#木の深さ毎のAccuracy格納用データフレームを初期化
df_md_Acc = pd.DataFrame(index=[], columns=['max_depth','val_acc'])
#木の深さ毎に検証する。 for max_depth in np.arange(1,10,1): #クロスバリデーションの検証毎のAccuracy格納用データフレームを初期化 df_val_Acc = pd.DataFrame(index=[], columns=['val_acc']) #クロスバリデーションでの検証ステップを初期化 #クロスバリデーションで検証 for train_index, test_index in KFold(n_splits=2,shuffle=True,random_state=1234).split(adB_X_train, adB_y_train): adB_X_val_train, adB_X_val_test = adB_X[train_index], adB_X[test_index] adB_y_val_train, adB_y_val_test = adB_y[train_index], adB_y[test_index] clf = AdaBoostClassifier(DecisionTreeClassifier(max_depth=max_depth,min_samples_split=2,random_state=1234,criterion="gini"),n_estimators=10, random_state=1234) clf.fit(adB_X_val_train, adB_y_val_train) score = clf.score(adB_X_val_test, adB_y_val_test) print("max_depth=",max_depth) print("score=", score) val_se = pd.Series( [score], index=df_val_Acc.columns ) df_val_Acc = df_val_Acc.append(val_se, ignore_index = True,sort=False) md_df = pd.DataFrame(index=[],columns=['max_depth','val_acc']) md_df = md_df.append(df_val_Acc.mean(),ignore_index = True,sort=False) md_df['max_depth'] = max_depth df_md_Acc = df_md_Acc.append(md_df, ignore_index = True,sort=False)

以下の結果が得られました。

display(df_md_Acc)
display(df_md_Acc.max())
  max_depth val_acc
0 1 0.723286
1 2 0.758233
2 3 0.764852
3 4 0.765508
4 5 0.765784
5 6 0.763789
6 7 0.763658
7 8 0.761898
8 9 0.759385

val_acc 0.765784 dtype: float64

df_md_Acc[['val_acc']].plot()
plt.show()

f:id:kanriyou_h004:20190616170607p:plain

グラフ上の横軸とmax_depthの値が1ずれているのでわかりにくいですが、四番目(max_depth=5)のVal_Accが最大になっているので、5をmax_depthとして採用する。

5.訓練データをすべて投入し、テストデータでの精度を確認する。

AdaBoostに訓練データをすべて投入し、max_depth=5で学習させます。
clf = AdaBoostClassifier(DecisionTreeClassifier(max_depth=5,min_samples_split=2,random_state=1234,criterion="gini"),n_estimators=10, random_state=1234)
clf.fit(adB_X_train, adB_y_train)
print("score=", clf.score(adB_X_test, adB_y_test))
 
score= 0.6750253659950718
クロスバリデーション時から、精度が下がりましたが、なんとか精度が67.5%まで改善し、NNモデルより精度が向上しました。

 

6.木モデルでつかわれている説明変数を確認する。

AdaBoostのfeature_importance_を利用して、このモデルでつかわれている説明変数を確認します。
# 説明変数の重要度を出力する
# 棒グラフで出力する。 pd.DataFrame(clf.feature_importances_, index=adB_train_data.columns).plot.barh(figsize=(12,50)) plt.ylabel("Importance") plt.xlabel("Features") plt.show()

f:id:kanriyou_h004:20190616172104p:plain

LassoCVで選択した特徴量よりも大幅に少なくなっています。また、usd_goalも利用されていて、直感的な特徴量が採用されている気がします。

 

今回は、視点を変えて、木モデル(AdaBoost)を試したのですが、これまでより、少ない特徴量で効率的な分類モデルができたと思われます。でも、まだまだ、全く役に立たないレベルの精度なので、いったん初心に戻って、テキスト等を参考に、理論を学びなおしたいと思います。

 

 2019年3月9日(土)にG検定を受験し、見事合格できました!

受験の体験記や勉強法などを別のブログにまとめました。

これから受験される方がいらっしゃいましたらご参考まで。

g-kentei.hatenablog.com

 

 

 

エピソード3-12: 選択した特徴量を使ってNNモデルの学習率をグリッドサーチする。Acc62%→66%(KaggleでKickstarter Projectsに挑戦する。)

「Kaggle」のデータセットKickstarter Projects」に取り組んで、前回、LassoCVを使った特徴量選択を実施したので、その特徴量を使ってNNモデルを作り学習率をグリッドサーチします。

前回の記事は、以下にありますので、ご参照ください。

oregin-ai.hatenablog.com

 

では、さっそく取り組んでまいります。

 

1.まずは、選択された特徴量だけに絞り込んで、学習用の訓練データと、性能検証用のテストデータに分割します。

# ラベルデータとして’state’を採用する。

train_label = df_train['state']



# Leakageになりそうなカラム、相関が強いカラムをドロップする

train_data = df_train.drop(['state','name','currency','deadline','goal','launched','pledged','backers','usd pledged','usd_pledged_real','period'], axis=1)
# Lassoで削除するべき特徴量に選ばれたカラムをドロップする train_data = train_data.drop(train_data.columns[removed_idx], axis=1) #目的変数'state'を正解としてyに格納 y = train_label.values
#カラムをドロップした説明変数を、Xに格納 X = train_data.values # 全データのうち、30%をテストデータにする test_size = 0.3 # ホールドアウト法を実行(テストデータはランダム選択) X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=test_size,shuffle=True, random_state=1234) #X_train : 学習用の訓練データの説明変数
#X_test : 検証用のテストデータの説明変数
#y_train : 学習用の訓練データの目的変数
#y_test : 検証用のテストデータの目的変数
print(X_train.shape, X_test.shape, y_train.shape, y_test.shape)

(144879, 172) (62091, 172) (144879,) (62091,)

 

144,879個の訓練データと、62,091個のテストデータに分かれて、説明変数は172個になりました。

 

2.1,2層目tanh 3,4層目ReLU、5層目Sigmoid の2値分類ニューラルネットワークモデルを採用, それぞれの層でバッチ正規化の処理を入れる。

モデルを一から作るのは大変なので、Kerasでくみ上げることにしました。

import keras

from keras.models import Sequential

from keras.layers import Dense, Dropout, Activation

from keras.layers.normalization import BatchNormalization

from keras.optimizers import Adam



model = Sequential()

#Lassoで削除された説明変数を削除する場合

model.add(Dense(256, activation='tanh', input_dim=172))

model.add(BatchNormalization())

model.add(Dense(256, activation='tanh'))

model.add(BatchNormalization())

model.add(Dense(128, activation='relu'))

model.add(BatchNormalization())

model.add(Dense(64, activation='relu'))

model.add(BatchNormalization())

model.add(Dense(1, activation='sigmoid')

3.最適化手法にAdamを採用し学習率を交差検証法で探索する。

最適化手法にはAdamを採用し学習率を変化させて、テストデータAccuracyが最大になる値を探索することにしました。
探索にあたっては、交差検証法(クロスバリデーション)を利用しました。

#学習率毎のAccuracy格納用データフレームを初期化

df_lr_Acc = pd.DataFrame(index=[], columns=['lr','step','loss', 'val_loss','acc', 'val_acc'])

for lr in np.arange(0.001,0.01,0.001):

    #クロスバリデーションの検証毎のAccuracy格納用データフレームを初期化

    df_val_Acc = pd.DataFrame(index=[], columns=['step','loss', 'val_loss','acc', 'val_acc'])

    #クロスバリデーションでの検証ステップを初期化

    step = 1

    #クロスバリデーションで検証(訓練データを三分割して、2つを学習用、1つを検証用に使うを三回実施)

    for train_index, test_index in KFold(n_splits=3,shuffle=True, random_state=1234).split(X_train, y_train):

        X_val_train, X_val_test = X[train_index], X[test_index]

        y_val_train, y_val_test = y[train_index], y[test_index]

        print(X_val_train.shape, X_val_test.shape,y_val_train.shape, y_val_test.shape)

        

        # ------ 最適化手法 ------

        adam = Adam(lr=lr)

        # -----------------------------



        model.compile(loss='binary_crossentropy',

                      optimizer=adam,

                      metrics=['accuracy'])

    

        # 計算の実行

        fit = model.fit(X_val_train, y_val_train,epochs=5,batch_size=256,validation_data=(X_val_test, y_val_test))



        # 各epochにおける損失と精度をdfに入れる

        df = pd.DataFrame(fit.history)

        

        val_df = pd.DataFrame(index=[],columns=['step','loss', 'val_loss','acc', 'val_acc'])

        val_df = val_df.append(df,ignore_index = True,sort=False)

        val_df[['step']] = step

        

        df_val_Acc = df_val_Acc.append(val_df, ignore_index = True,sort=False) 

        step = step + 1



    lr_df = pd.DataFrame(index=[],columns=['lr','step','loss', 'val_loss','acc', 'val_acc'])

    lr_df = lr_df.append(df_val_Acc.mean(),ignore_index = True,sort=False)

    lr_df['lr'] = lr

    

    df_lr_Acc = df_lr_Acc.append(lr_df, ignore_index = True,sort=False)

計算にはすごく時間がかかりましたが、何とか以下の結果が得られました。

display(df_lr_Acc)

 
  lr step loss val_loss acc val_acc
0 0.001 2.0 0.616865 0.629140 0.656589 0.644717
1 0.002 2.0 0.614168 0.626992 0.659109 0.646534
2 0.003 2.0 0.612774 0.626886 0.660399 0.647079
3 0.004 2.0 0.611683 0.622813 0.661034 0.648478
4 0.005 2.0 0.610517 0.622491 0.662487 0.646077
5 0.006 2.0 0.610405 0.627468 0.662440 0.646147
6 0.007 2.0 0.611132 0.625084 0.661896 0.647473
7 0.008 2.0 0.612308 0.627778 0.660742 0.646867
8 0.009 2.0 0.616417 0.631615 0.656790 0.639158
df_lr_Acc[['acc', 'val_acc']].plot()

plt.show()
 

f:id:kanriyou_h004:20190608165947p:plain


三番目のVal_Accが最大になっているので、0.004を学習率として採用する。

4.訓練データをすべて投入し、epoch数を増やしてみて学習後、テストデータでの精度を確認する。

エポック数は100にしてみます。

# ------ 最適化手法 ------

adam = Adam(lr=0.004)

# -----------------------------



model.compile(loss='binary_crossentropy',

              optimizer=adam,

              metrics=['accuracy'])



# 計算の実行

fit = model.fit(X_train, y_train,epochs=100,batch_size=256,validation_data=(X_test, y_test))



# 各epochにおける損失と精度をdfに入れる

df = pd.DataFrame(fit.history)

    

# グラフ化

df[['loss', 'val_loss']].plot()

plt.ylabel('loss')

plt.xlabel('epoch')

plt.show()



df[['acc', 'val_acc']].plot()

plt.ylabel('acc')

plt.xlabel('epoch')

plt.show()

 

f:id:kanriyou_h004:20190608171122p:plain

f:id:kanriyou_h004:20190608171137p:plain

結構、過学習気味(?)ですが、なんとか精度が66%まで改善しました。

前回のLeakageの気づきで大きく手戻りしましたが、ロジスティック回帰で分類した62%から、66%まで改善することができました。

次回は、別のモデルを採用してさらなる改善を目指します。

 

 2019年3月9日(土)にG検定を受験し、見事合格できました!

受験の体験記や勉強法などを別のブログにまとめました。

これから受験される方がいらっしゃいましたらご参考まで。

g-kentei.hatenablog.com

 

 

 

エピソード3-11: 正則化L1ノルム(Lasso)を使って特長量選択。(KaggleでKickstarter Projectsに挑戦する。)

「Kaggle」のデータセットKickstarter Projects」に取り組んで、Leakageにハマってしまいましたが、気を取り直して、再度取り組み開始です。

ハマってしまった「Leakage」については、以下にまとめてあるのでご参照ください。

oregin-ai.hatenablog.com

さて、今回は、前回country,main_category,categoryをOne-Hotに変換したことで、説明変数の数(次元)が大幅に増えてしまったので、正則化L1ノルム(Lasso)を使って特長量選択に取り組んでみたいと思います。

正則化L1ノルム(Lasso)は、過学習を予防するために重みの絶対値の合計を損失関数にくっつけることで、重みが大きくなりすぎないようにする仕組みです。

重みの合計を小さくするために、関係なさそうな特長量の重みがどんどん小さくなり、結果として特長量選択につながるといった感じです。

 では、頑張ってみます。

 

1.まずは、関係するモジュールをインポートする。

sklearnから、モデルから特長量選択をするSelectFromModelと、線形モデルとしてLassoCVをインポートします。

from sklearn.feature_selection import SelectFromModel
from sklearn.linear_model import LassoCV

2.正則化L1ノルム(Lasso)を使って特長量選択をしてみる

# LassoCVを使って、正則化の強さを自動決定したモデル(estimator)を作成
estimator = LassoCV(normalize=True, cv=10)

# モデルの情報を使って特徴選択を行うためSelectFromModelを使う
# 今回は係数がしきい値(threshold)が1e-5以下である特徴を削除する
sfm = SelectFromModel(estimator, threshold=1e-5)

# fitで特徴選択を実行
sfm.fit(X_train, y_train)

予測モデルにLassoCVを利用し、SelectFromModel()の引数に、モデルとしきい値(threshold)を指定することで、特長量削除を行うインスタンスができます。

当該インスタンスで、fit()の引数に、説明変数と、目的変数を渡すことで、特長量選択が実行されます。 

3.特長量選択された結果を確認する。

特長量選択の結果を確認します。

# 削除すべき特徴の名前を取得 
removed_idx  = ~sfm.get_support()
train_data.columns[removed_idx] 

Index(['ID', 'usd_goal_real', 'country_CA', 'country_CH',
'category_Children's Books', 'category_Comics', 'category_Crafts',
'category_Design', 'category_Fabrication Tools', 'category_Fashion',
'category_Food', 'category_Glass', 'category_Graphic Design',
'category_Literary Spaces', 'category_Music', 'category_Photography',
'category_Poetry', 'category_Pop', 'category_Romance',
'category_Taxidermy', 'category_Woodworking', 'category_World Music',
'main_category_Art', 'main_category_Film & Video',
'main_category_Games', 'main_category_Journalism',
'main_category_Publishing'],
dtype='object')

get_support()関数で特長量ごとのTrue、Falseが得られるので、Falseのインデックスをremoved_idxに格納して、削除すべき特長量のカラム名を取得。

「usd_goal_real」まで削除対象に入っているのが驚き。

結果的に、期間と国とカテゴリできまるということでしょうか?

4.特長量選択された結果を確認する。(グラフでも見てみる。)

各特長量の係数(重み)をグラフでも見てみます。

# 係数を棒グラフで表示
fig = plt.figure(figsize=(12, 50))
plt.barh(np.arange(0, len(abs_coef)), abs_coef, tick_label=train_data.columns.values) plt.show()

f:id:kanriyou_h004:20190602174611p:plain


 削除対象になった特長量(カラム)の係数(重み)が小さくなっていることが視覚的にもわかりました。  

前回のLeakageの気づきで大きく手戻りしましたが、特長量の新たな選択方法の勉強ができたので、大きな前進でした。

次回は、この選択した特長量で再度分類に挑戦です。

 

 2019年3月9日(土)にG検定を受験し、見事合格できました!

受験の体験記や勉強法などを別のブログにまとめました。

これから受験される方がいらっしゃいましたらご参考まで。

g-kentei.hatenablog.com

 

 

 

エピソード3-10: 大幅手戻り、Leakageにはまる。(KaggleでKickstarter Projectsに挑戦する。)

「Kaggle」のデータセットKickstarter Projects」に取り組んで、順調に精度を向上させているかに見えたのですが、ここにきて、知人に「それ、Leakageじゃない?」と指摘され、今回は、Leakageの回避に取り組みました。

これまでの流れは以下にまとめてあるのでご参照ください。

oregin-ai.hatenablog.com

 

Leakageとは、学習時の説明変数に、目的変数と同等の変数を使ってしまうことで、予測精度や分類精度が、大幅に向上してしまうことです。

今回のデータセットで言えば、結果として集まった金額や、後援者の数などをつかってしまうことになります。

 

1.Leakageに該当すると思われる説明変数を除外してみる。

これまでの検証で「backers」を使ってしまったのですが、これは、クラウドファンディングの結果、集まった後援者を表しているので、目的変数の’state'と同様、結果として得られる数値なので、予測や分類につかってしまうと、Leakageに該当します。

また、訓練データの’state’の成功、失敗をもとに自分で作った、'country_rate'や'main_category_rate'や'category_rate'も数値を作るときに、目的変数の'state'を使ってしまっているので、Leakageになってしまいます。

これらは、説明変数からのぞかないとLeakageになってしまい、訓練時は精度が良くても実際には精度がでないという結果になってしまします。

どうりで、80%だ90%だのAccuracyがバンバン出せたわけだ・・・。

 

2.代わりに、country,main_category,categoryをOne-Hotに変換してみる。

 上記で、変数を減らしたので、代わりにcountry,main_category,categoryをOne-Hotベクトルに変換する。

One-Hotベクトルとは、Countryのようなカテゴリーデータを、各カテゴリの列(country_US,country_UKなどの列)に変換し、その列のカテゴリに該当する行は「1」、該当しない行は「0」に変換することで出来上がる表現です。

#####################################
#country,main_category,categoryをOne-Hotに変換する。
#####################################
df_train = pd.get_dummies(df_train, columns=['country', 'category', 'main_category'])
 

pandasのget_dummies()に、変換したいデータフレームと、変換したいカラムをcolumns=[変換したいカラムリスト]とすることで、変換したデータフレームが取得できます。

結果としては、以下のような感じになります。

f:id:kanriyou_h004:20190602163834j:plain

 

3.Leakageにあたる変数を除外して、One-Hotを採用したデータフレームで改めてロジスティック回帰で分類してみる。

今回、変数を除外してOne-Hotを採用したデータフレームでロジスティック回帰で分類してみました。

One-Hotは、全部採用すると時間がかかりそうだったので、いったんいくつかに絞り込んで分類を実施。

#********************************************************************
#.ロジスティック回帰で分類してみる。
#********************************************************************

#目的変数'state'を正解としてyに格納
y = df_train['state'].values
#説明変数'goal','days','country'のOne-Hotをいくつか,'main_category'のOne-Hotをいくつか,'category'のOne-Hotをいくつか、を入力としてXに格納
X = df_train[['goal','days','country_GB','country_HK','country_SG','country_US','main_category_Art','main_category_Comics','main_category_Dance','main_category_Design','main_category_Film & Video','main_category_Games','main_category_Music','main_category_Theater','category_Anthologies','category_Chiptune','category_Classical Music','category_Comic Books','category_Country & Folk','category_Dance','category_Indie Rock','category_Jazz','category_Letterpress','category_Performances','category_Plays','category_Residencies','category_Tabletop Games','category_Theater','category_Typography']].values

#ロジスティック回帰で学習
clf = SGDClassifier(loss='log', penalty='none', max_iter=10000, fit_intercept=True, random_state=1234)
clf.fit(X, y)

#********************************************************************
#.予測精度または識別精度を確認する
# 混同行列を作成し、Accuracy、Recall、Precisionを求める
#********************************************************************
# 学習した結果を使って説明変数を入力して予測
y_est = clf.predict(X)

#混同行列を作成
tn, fp, fn, tp = confusion_matrix(y, y_est).ravel()
print(fn, fp)
print(tn, tp)

#'Accuracy、Recall、Precisionを求めて表示
print('Accuracy  = {:.3f}%'.format(100 * (tn+tp)/(tn+fp+fn+tp)))
print('Recall    = {:.3f}%'.format(100 * (tp)/(fn+tp)))
print('Precision = {:.3f}%'.format(100 * (tp)/(fp+tp)))
 

Accuracy = 62.700%
Recall = 43.186%
Precision = 54.991%

 

結果としては、 Accuracyが、大幅に下がって、62.7%になりました。

Leakageに気づかず、精度が向上して喜んでいましたが、Leakageにならないように考慮した結果62.7%になりました。

成功と失敗で絞り込んだデータのうち、失敗の割合が約60%なので、全部失敗と予測するモデルとあまり変わらない精度に落ちてしまいました・・・。

改めて、検討しなおしです。

 

 2019年3月9日(土)にG検定を受験し、見事合格できました!

受験の体験記や勉強法などを別のブログにまとめました。

これから受験される方がいらっしゃいましたらご参考まで。

g-kentei.hatenablog.com

 

 

 

エピソード3-9: 異常値(外れ値)を除いてみて精度を向上するか確認する。(KaggleでKickstarter Projectsに挑戦する。)

「Kaggle」のデータセットKickstarter Projects」にて、更に精度を向上させるために異常値の除去についても検討します。

これまでの流れは以下にまとめてあるのでご参照ください。

oregin-ai.hatenablog.com

 

国別とカテゴリーは成功率なので異常値はないと判断し、「goal」と「backers」の異常値について考えます。

 

1.「goal」の異常値について考えてみる。

「goal」異常値について考えます。

まずは「ヒストグラムを見てみます。

#'goal'についてヒストグラムを書いてみる
plt.hist(df_f18_SRate['goal'],log=True)
plt.show() 

f:id:kanriyou_h004:20190519210127p:plain


 

1e8あたりに外れ値がありそうなので、件数と、近辺のグラフと、データを見てみまする。

#ヒストグラムで少し離れている1e8のあたりに着目してみる。 
df_tmp = df_f18_SRate['goal'][df_f18_SRate['goal']>99999999]
#件数数える
display(df_tmp.shape)
#ヒストグラム描いてみる
plt.hist(df_tmp) plt.show()
#データ見てみる
display(df_tmp)
(19,)

f:id:kanriyou_h004:20190519210606p:plain

1514      100000000.0
58470     100000000.0
68612     100000000.0
86687     100000000.0
93295     100000000.0
93426     100000000.0
95647     100000000.0
96653     100000000.0
128171    100000000.0
135722    100000000.0
166919    100000000.0
170659    100000000.0
172789    100000000.0
184178    100000000.0
185267    100000000.0
186427    100000000.0
194729    100000000.0
196342    100000000.0
201782    100000000.0
Name: goal, dtype: float64

データの数は19件で、すべて100,000,000なので、上限値で頭打ちにされていそうなので、この19件は学習から除外することにします。

2.「backers」の異常値について考察してみる。

 「backersl」の異常値についても考えます。

まずは「ヒストグラムを見てみます。

#'backers'についてヒストグラムを書いてみる
plt.hist(df_f18_SRate['backers'],log=True)
plt.show()
 

f:id:kanriyou_h004:20190519211110p:plain

150,000以上に外れ値がありそうです。

#ヒストグラムで少し離れている150000のあたりに着目してみる。
df_tmp = df_f18_SRate['backers'][df_f18_SRate['backers']>150000]
#件数数える
display(df_tmp.shape)
#ヒストグラム描いてみる
plt.hist(df_tmp)
plt.show()
#データ見てみる
display(df_tmp)
 

(2,)

f:id:kanriyou_h004:20190519211254p:plain

98446 154926.0
122168 219382.0
Name: backers, dtype: float64


 この2件も外れ値として学習からのぞくことにします。

 

3.異常値(外れ値)を除いたデータフレームを作る。

これまで検討してきた異常値(外れ値)を除いたデータフレームを作ります。

#####################################
#異常値を除いたデータフレームを作る。
#####################################
#goalの異常値を除いたデータフレーム
df_train = df_f18_SRate[df_f18_SRate['goal']<99999999]
#さらに、backersの異常値を除いたデータフレーム
df_train = df_train[df_train['backers']<150000]
df_train.shape

 (206968, 21)

 

4.異常値(外れ値)を除いたデータフレームを使ってロジスティック回帰で分類してみる。

 異常値(外れ値)を除いたデータフレームを使ってロジスティック回帰で分類してみます。


#********************************************************************
#.ロジスティック回帰で分類してみる。
#********************************************************************
#目的変数'state'を正解としてyに格納
y = df_train['state'].values
#説明変数'goal','backers','days','country_rate','main_category_rate',
#'category_rate'を入力としてXに格納

X = df_train[['goal', 'backers','days','country_rate','main_category_rate','category_rate']].values
#ロジスティック回帰で学習
clf = SGDClassifier(loss='log', penalty='none', max_iter=10000, fit_intercept=True, random_state=1234)
clf.fit(X, y)
#********************************************************************
#.予測精度または識別精度を確認する
# 混同行列を作成し、Accuracy、Recall、Precisionを求める
#********************************************************************
# 学習した結果を使って説明変数を入力して予測
y_est = clf.predict(X)
#混同行列を作成
tn, fp, fn, tp = confusion_matrix(y, y_est).ravel()
print(fn, fp)
print(tn, tp)
#'Accuracy、Recall、Precisionを求めて表示
print('Accuracy = {:.3f}%'.format(100 * (tn+tp)/(tn+fp+fn+tp)))
print('Recall = {:.3f}%'.format(100 * (tp)/(fn+tp)))
print('Precision = {:.3f}%'.format(100 * (tp)/(fp+tp)))

4330 13839
109364 79435
Accuracy = 91.221%
Recall = 94.831%
Precision = 85.163%

異常値(外れ値)を除くことで、わずかですが、Accuracyが91.171%から、91.221%まで上昇しました。

次回は、このデータをつかってSVMにも挑戦してみたいと思います。

今後もさらなる向上を目指して頑張ります!

 

 2019年3月9日(土)にG検定を受験し、見事合格できました!

受験の体験記や勉強法などを別のブログにまとめました。

これから受験される方がいらっしゃいましたらご参考まで。

g-kentei.hatenablog.com