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

俺って、おバカさんなので、とっても優秀な人工知能を作って代わりに頑張ってもらうことにしました。世界の端っこでおバカな俺が夢の達成に向けてチマチマ頑張る、そんな小さなお話です。現在はG検定、E資格に合格し、KaggleやProbSpaceのコンペに参画しながら、Pythonや機械学習、統計学、Dockerなどの勉強中です。学習したことをブログにアウトプットすることで、自分の身に着けていきたいと思います。まだまだ道半ばですが、お時間がありましたら見て行ってください。

エピソード3-8: 説明変数の追加で精度を向上する。(KaggleでKickstarter Projectsに挑戦する。)

「Kaggle」のデータセットKickstarter Projects」にて、更に精度を向上させるためにほかの説明変数についても検討します。

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

oregin-ai.hatenablog.com

1.【仮説1】'country' によって成功、失敗が変わる。

 国別によって成功率が変わると仮説を立ててみました。

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

#成功と、失敗でデータを分ける。
df_f18_S = df_f18_SorF[df_f18_SorF['state']==1]
df_f18_F = df_f18_SorF[df_f18_SorF['state']==0]

#それぞれを'country'についてヒストグラムを書いてみる
plt.hist([df_f18_S["country"], df_f18_F["country"]], stacked=False)
plt.show() 

 

 

国ごとに成功率が違うことが確認できました。

さっそく、国ごとの成功率を列に追加します。

#'country'ごとにグループ化し、平均をとったデータフレームを作成する
df_f18_gb_ct = df_f18_SorF.groupby('country',as_index=False)
df_f18_gb_ct_mn = df_f18_gb_ct.mean()

#'state'は成功が'1',失敗が'0'なので、'country'毎の'state'の平均は
#その国の成功する割合(確率)と等価なので名称変更
df_f18_gb_ct_mn = df_f18_gb_ct_mn.rename(columns={'state': 'country_rate'}) 
display(df_f18_gb_ct_mn[['country','country_rate']])

#元のデータフレームに、国ごとの成功する確率を結合
df_f18_SRate = pd.merge(df_f18_SorF, df_f18_gb_ct_mn[['country','country_rate']], on='country')
plt.hist([df_f18_S["country"], df_f18_F["country"]], stacked=False)
plt.show() 

国ごとにグループ化してその後、平均をとることで成功する確率を求めました。

それを、 もとのデータフレームに追加します。

2.【仮説2】'main_category','category' によって成功、失敗が変わる。

 カテゴリーによっても成功率が変わると仮説を立ててみました。

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

#成功と、失敗でデータを分ける。
df_f18_S = df_f18_SorF[df_f18_SorF['state']==1]
df_f18_F = df_f18_SorF[df_f18_SorF['state']==0]

#それぞれについてヒストグラムを書いてみる
plt.hist([df_f18_S["category"], df_f18_F["category"]], stacked=False)
plt.show()

plt.hist([df_f18_S["main_category"], df_f18_F["main_category"]], stacked=False)
plt.show() 

f:id:kanriyou_h004:20190518164705p:plain

f:id:kanriyou_h004:20190518164742p:plain

カテゴリーにも成功率に違いがあることがわかりました。

'country'と同様に成功率を列に追加します。

まずは、'main_category'を追加します。

#"main_category"ごとにグループ化し、平均をとったデータフレームを作成する
df_f18_gb_mc = df_f18_SorF.groupby("main_category",as_index=False)
df_f18_gb_mc_mn = df_f18_gb_mc.mean()

#'state'は成功が'1',失敗が'0'なので、'main_category'毎の'state'の平均は
#そのメインカテゴリーの成功する割合(確率)と等価なので名称変更
df_f18_gb_mc_mn = df_f18_gb_mc_mn.rename(columns={'state': 'main_category_rate'}) 
display(df_f18_gb_mc_mn[['main_category','main_category_rate']])

#元のデータフレームに、国ごとの成功する確率を結合
df_f18_SRate = pd.merge(df_f18_SRate, df_f18_gb_mc_mn[['main_category','main_category_rate']], on='main_category')

 続いて、'category'も追加します。

#"category"ごとにグループ化し、平均をとったデータフレームを作成する
df_f18_gb_cg = df_f18_SorF.groupby("category",as_index=False)
df_f18_gb_cg_mn = df_f18_gb_cg.mean()

#'state'は成功が'1',失敗が'0'なので、'category'毎の'state'の平均は
#そのカテゴリーの成功する割合(確率)と等価なので名称変更
df_f18_gb_cg_mn = df_f18_gb_cg_mn.rename(columns={'state': 'category_rate'}) 
display(df_f18_gb_cg_mn[['category','category_rate']])

#国別の成功率を追加したデータフレームに、カテゴリーごとの成功する確率を結合
df_f18_SRate = pd.merge(df_f18_SRate, df_f18_gb_cg_mn[['category','category_rate']], on='category')

これで、カテゴリーごとの成功率の列も追加できました。

 

3.【仮説3】期間の長さによって成功、失敗が変わる。

今度は、'launched':開始と'deadline':期限に着目して、それぞれ単独では成功、失敗に関連していなくても、差し引きした期間の長さという観点では相関があるのではないかと仮定しました。

まずは、期間を求めます。

# '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'] #'period'の日数を'days'に抽出 days = [] 
for i in df_f18_SorF.index: days.append(df_f18_SorF['period'][i].days) #元のデータフレームに'days'の列を追加 df_f18_SRate['days'] = days

 

では、'days'について、成功、失敗のヒストグラムを見てみます。

#成功と、失敗でデータを分ける。
df_f18_S = df_f18_SorF[df_f18_SorF['state']==1]
df_f18_F = df_f18_SorF[df_f18_SorF['state']==0]

#それぞれを'days'についてヒストグラムを書いてみる
plt.hist([df_f18_S["days"], df_f18_F["days"]], stacked=False)
plt.show()

f:id:kanriyou_h004:20190518170922p:plain

期間が長いほど成功率が上がっていることがわかりました。

 

 

これまでの検討から、新たに作成した以下を説明変数を追加します。

'country_rate','main_category_rate','category_rate','days' 

 

 4.'country_rate','main_category_rate','category_rate','days'を追加してロジスティック回帰で分類してみる。

 追加した説明変数を加えてロジスティック回帰で分類してみます。

#********************************************************************
#.ロジスティック回帰で分類してみる。
#「goal」「backers」「days」「country_rate」
#「main_category_rate」「categoryrate」を説明変数とする。
#********************************************************************
#目的変数'state'を正解としてyに格納
y = df_f18_SRate['state'].values
#説明変数'goal','backers'を入力としてXに格納
X = df_f18_SRate[['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)))

4235 14040
109182 79532
Accuracy = 91.171%
Recall = 94.944%
Precision = 84.996%

説明変数を追加することで、Accuracyが88.938%から、91.171%まで上昇しました!!!

Recallが、96.423%から94.944%に下がっているのは気になるところですが、まずは性能が上がったといえるのではないでしょうか。

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

 

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

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

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

g-kentei.hatenablog.com