#最初に
この未完成のコードをこちらに投稿することで多くの方の目に留まり、自分の何がいけなかったのかや、どうすればよかったのかなど改善点や改善策をもらえると思いこの記事を書きました。
なので、正直なぜこういうことをしているのか?など疑問点が数多くあると思いますが、温かい目で見てもらえたらうれしいです。
#自己紹介とコンペ
今回こちらの10月1日から開催されたコンペに参加しました。
https://signate.jp/competitions/295
簡単に私の自己紹介をしますと、今年の4月よりAI系のプログラミングスクールに通い始め、
現在転職活動中の身でプログラミング未経験で文系学部出身です。
まず、今回参加したのがちょっと遅くて10月の13日からゆっくりと始めました。
最初の1週間はただただデータを眺めて、これをどうすればいいのか習ったことを参考にコードを書いてみました。しかし、度重なるエラーに振り回されsubmitすらできませんでした......
そして、コンペ終了1週間前にKaggleスタートブックがようやく手に入りこれを写経してそれっぽいものを作ろうと思いました。EDAについては、SIGNATEが無料でQUESTを開放していたため、そちらを参考にしました。
#今回使ったライブラリ
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.preprocessing import LabelEncoder
import optuna
import optuna.integration.lightgbm as lgb
from sklearn.model_selection import train_test_split
from sklearn.metrics import log_loss
#特徴量抽出
とりあえずデータをインポートして中身を見ます。(開発環境はKaggleのnotebookを活用しました)
train = pd.read_csv("../input/signatecomp/train.csv",header=0)
test = pd.read_csv("../input/signatecomp/test.csv",header=0)
print(train.info())
print(train.head())
print(train.info())
print(train.head())
ここからデータの特徴を見ていきます。
まず数値変数を見ます。
test.hist(figsize=(20,20), color='r')
つぎに、カテゴリ変数を見ていきます。
emplength_var = train['employment_length'].value_counts()
# グラフタイトルを指定
emplength_var.plot.bar(title="employment_lengthの頻度")
# x軸名を指定
plt.xlabel('employment_length')
# y軸名を指定
plt.ylabel('count')
# 作成したグラフを表示するために必要なコード
plt.show()
# purposeの棒グラフの可視化
purpose_var = train['purpose'].value_counts()
purpose_var.plot.bar()
# purposeの棒グラフの表示
plt.show()
# application_typeの棒グラフの可視化
application_var = train['application_type'].value_counts()
application_var.plot.bar()
# application_typeの棒グラフの表示
plt.show()
# gradeの棒グラフの可視化
grade_var = train['grade'].value_counts()
grade_var.value_counts()
# gradeの棒グラフの表示
plt.show()
つぎに目的変数とカテゴリ変数の関係を見ていきます
# termカラムをインデックス(行)、loan_statusカラムをカラム(列)としてクロス集計
cross_term = pd.crosstab(train['term'],train['loan_status'], margins = True)
# ChargedOffカラムをAllカラムで割り、変数c_rateに代入
c_rate = cross_term['ChargedOff'] / cross_term['All']
# FullyPaidカラムをAllカラムで割り、変数f_rateに代入
f_rate = cross_term['FullyPaid'] / cross_term['All']
# 変数c_rate及び変数f_rateを変数cross_termに新たなカラムc_rate、f_rateとしてそれぞれ代入
cross_term['c_rate'] = c_rate
cross_term['f_rate'] = f_rate
# クロス集計表の表示
print(cross_term)
# ChargedOffカラムをAllカラムで割り、変数c_rateに代入
c_rate = cross_term['ChargedOff'] / cross_term['All']
# FullyPaidカラムをAllカラムで割り、変数f_rateに代入
f_rate = cross_term['FullyPaid'] / cross_term['All']
# 変数c_rate及び変数f_rateを変数cross_termに新たなカラムc_rate、f_rateとしてそれぞれ代入
cross_term['c_rate'] = c_rate
cross_term['f_rate'] = f_rate
# 変数cross_termからAll行を削除して変数cross_termに再代入
cross_term = cross_term.drop(index = ["All"])
# クロス集計表を表示
print(cross_term)
# 積み上げ棒グラフに使用したいカラムだけのDataFrameを作成
df_bar = cross_term[['c_rate', 'f_rate']]
# 積み上げ棒グラフを作成
df_bar.plot.bar(stacked=True)
# グラフタイトルの設定
plt.title('返済期間ごとの貸し倒れ率と完済率')
# x軸ラベルの設定
plt.xlabel('期間')
# y軸ラベルの設定
plt.ylabel('割合')
# グラフの表示
plt.show()
この作業をすべてのカテゴリ変数に適用させます
(コードを全部載せてもいいのですが、ほぼ同じ作業のため申し訳ないですが割愛させていただきます)
#特徴量追加
とりあえず平均をとって、credit_scoreは偏っていたため対数変換しました。
#特徴量追加
train["log_cre"] = np.log(train.credit_score - train.credit_score.min() + 1)
test["log_cre"] = np.log(test.credit_score - test.credit_score.min() + 1)
train['loam_median'] = train['loan_amnt'] - train['loan_amnt'].median()
train['inter_median'] = train['interest_rate'] - train['interest_rate'].median()
test['loam_median'] = test['loan_amnt'] - test['loan_amnt'].median()
test['inter_median'] = test['interest_rate'] - test['interest_rate'].median()
#データ前処理
今回はラベルエンコーディングしました。
#trainデータを変換
Label_Enc_list = ['term','grade','purpose','application_type',"employment_length","loan_status"]
# Label Encodingの実施
import category_encoders as ce
ce_oe = ce.OrdinalEncoder(cols=Label_Enc_list,handle_unknown='impute')
#文字を序数に変換
train = ce_oe.fit_transform(train)
#値を1の始まりから0の始まりにする
for i in Label_Enc_list:
train[i] = train[i] - 1
#testデータを変換
from sklearn.preprocessing import LabelEncoder
category = test.select_dtypes(include='object')
for col in list(category):
le = LabelEncoder()
le.fit(test[col])
le.transform(test[col])
test[col] = le.transform(test[col])
print(train.head())
print(test.head())
#モデル作成
# trainの目的変数と説明変数の値を取得
target = train['loan_status'].values
features = train.drop(['id','loan_status'],axis=1).values
# testデータ
test_X = test.drop(['id'],axis=1).values
# trainを学習データと検証データに分割
(features , val_X , target , val_y) = train_test_split(features, target , test_size = 0.2)
def objective(trial):
lgb_params = {'objective': 'binary',
'max_bin': trial.suggest_int("max_bin", 255, 500),
"learning_rate": 0.05,
"num_leaves": trial.suggest_int("num_leaves", 32, 128)
}
lgb_train = lgb.Dataset(features, target) #学習用
lgb_eval = lgb.Dataset(val_X, val_y,reference=lgb_train) #Boosting用
#学習
model = lgb.train(lgb_params, lgb_train,
valid_sets=[lgb_train,lgb_eval],
num_boost_round=1000,
early_stopping_rounds=10,
verbose_eval=10)
y_pred = model.predict(val_X,
num_iteration=model.best_iteration)
score = log_loss(val_y,y_pred)
return score
study = optuna.create_study(sampler=optuna.samplers.RandomSampler(seed=0))
study.optimize(objective, n_trials=20)
study.best_params
lgb_params = {'boosting_type': 'gbdt',
'objective': 'binary',
'max_bin': study.best_params["max_bin"],
"learning_rate": 0.05,
"num_leaves": study.best_params["num_leaves"]
}
lgb_train = lgb.Dataset(features, target) #学習用
lgb_eval = lgb.Dataset(val_X, val_y,reference=lgb_train) #Boosting用
#学習
model = lgb.train(lgb_params, lgb_train, valid_sets=[lgb_train,lgb_eval],
num_boost_round=1000,
early_stopping_rounds=10,
verbose_eval=10)
pred = model.predict(test_X,num_iteration=model.best_iteration)
#ファイル提出
スタートブック上では0.5より大きければという条件で二値分類していたのですが、50行くらい表示させ0.1より大きいと指定したほうがスコアが出たため、条件を変えましたがどう扱っていいかわからなかったです....
また代入をしたつもりだったのですが、指定の仕方がわからなかったため一度行を追加しcsvファイルを開き削除するという愚行を行っております(;_;)
(Header=0で普通に列を指定すればよかったのかな?)
pred1 = (pred > 0.1).astype(int)
submit = pd.read_csv("../input/signatecomp/submit.csv")
# 予測結果ファイル出力
submit.loc[:,0] = pred1[1:]
submit.to_csv("submit1.csv", index = False)
print("Your submission was successfully saved!")
#結果
F1Score=0.355を超えれば昇格だったのですが、0.3275218だったため昇格できませんでした。
#反省点
まず、ほぼゼロベースでデータ分析をしようとしていたため、かなり無駄な時間を浪費しました。
つぎに、プログラミングスクールでならったのはE資格に向けてのものだったため知識は知あるし、実装もある程度学びましたが、実際に問題を解くということや復習などを私が怠っていたため、残念な結果になりました。
最後に、Kaggleで似たようなコンペを探したりコードの実装の仕方、データエンジニアリングの方法などを探すやり方がとても下手でいろんなものに振り回されたことです。
#学び
初めてコンペに足を踏み入れて、自分がどれだけ実力が足りなかったか、何をこれからすればいいのか、エラーの対処法etc...数多くのことが得られました。
#最後に
ここまで見てくださった方々本当にありがとうございました。
私はまだまだ未熟なため、これからも一層努力します。