Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

クラウドファンディングの目標額に到達するか否か?

はじめに

データの取り扱い、前処理、モデル構築、評価までを自分のための備忘録として残しました。
データはこちら
https://www.kaggle.com/kemical/kickstarter-projects

データセット

import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
%matplotlib inline
plt.style.use('ggplot')

df = pd.read_csv('ks-projects-201801.csv')
df.head()

image.png

#型
df.info()

image.png

#基本統計量
df.describe()

image.png

#欠損値
df.isnull().sum()

欠損値

#何種類含まれているか
df[['category', 'main_category']].nunique()

欠損値

#それぞれのデータが何個ずつ含まれているか
df['category'].value_counts()

欠損値

#それぞれのデータを割合でみる
success_rate = round(df['state'].value_counts() / len(df['state']) * 100, 2)
success_rate

欠損値

考察

学習に使ってはいけないデータを取り除くことが大事。

  • pledged

  • backers

  • usd pledged

  • usd_pledged_real

前処理

#stateを「failed」「successful」の2種に分ける
print('before: ', df.shape)
df = df[(df['state'] == 'failed') | (df['state'] == 'successful')]

#文字列は扱えないので、数値に変換
df['state'] = df['state'].map({
    'failed': 0,
    'successful': 1         
})
print('after: ', df.shape)

欠損値

plt.figure(figsize=(12, 8))
plt.hist(df['usd_goal_real'], bins=100)
plt.show()
#偏ってる時の対処法
#①四分位範囲で処理
#②対数をとって処理

image.png

#np.log1p(a)…底をeとするa+1の対数
df['usd_goal_real'] = np.log1p(df['usd_goal_real'])

plt.figure(figsize=(12, 8))
plt.hist(df['usd_goal_real'], bins=100)
plt.show()
#なぜ正規分布にしたい?
#>>>モデルの中には正規分布を仮定しているものもあるから

image.png

df['deadline'] = pd.to_datetime(df['deadline'], format='%Y-%m-%d %H:%M:%S')
df['launched'] = pd.to_datetime(df['launched'], format='%Y-%m-%d %H:%M:%S')

#何日間クラウドファンディングが行われているか?
df['duration']=(df['deadline'] - df['launched']).dt.days

#1~3月=1,4~6月=2…と四半期に分けている。
df['quarter']= df['launched'].dt.quarter
df['month']= df['launched'].dt.month
df['year']= df['launched'].dt.year
#* Series.dt.dayofweekを使うと、月曜日= 0、日曜日= 6にして返してくれます
df['dayofweek']= df['launched'].dt.dayofweek

df.head()

image.png

#不要カラムを削除
#IDは意味ない
#goalはusd_goal_realで代用できる
#launched,deadlineも他で代用できる
#その他は使ってはいけない
df = df.drop(columns=['ID', 'deadline', 'goal', 'launched', 'pledged', 'backers', 'usd pledged', 'usd_pledged_real'])
df.head()
#名前(文字列)の処理

#文字数を取得
df['name_len'] = df['name'].str.len()

#単語ごとに分割して単語数を取得
df['name_words'] = df['name'].apply(lambda x: len(str(x).split(' ')))

df.drop(columns=['name'], inplace=True)
df.head()

image.png

#欠損値
df.isnull().sum()

欠損値

#欠損値を0で埋める
df["name_len"]=df["name_len"].fillna(0)

#カテゴリカルなデータの処理(ダミー変数化)
#頻繁に使う手法
df = pd.get_dummies(df , ['category', 'main_category', 'currency', 'country'])
df.columns

image.png

モデル構築

import xgboost as xgb
from sklearn.model_selection import train_test_split
X = df.drop(columns=['state'])
y = df['state']

print(X.shape)
print(y.shape)

image.png

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2,
                                                   random_state=0)

print(X_train.shape, y_train.shape)
print(X_test.shape, y_test.shape)

欠損値

#デフォルト
params = {
    'silent': 1,
    'max_depth': 6,
    'min_child_weight': 1,
    'eta': 0.1,
    'tree_method': 'exact',
    'objective': 'binary:logistic',#ここだけ注意(2分値)
    'eval_metric': 'logloss',
    'predictor': 'cpu_predictor'
}

dtrain = xgb.DMatrix(X_train, label=y_train)
dtest = xgb.DMatrix(X_test, label=y_test)
model = xgb.train(params=params,
                  dtrain=dtrain, 
                  num_boost_round=1000,
                  early_stopping_rounds=5, 
                  evals=[(dtest, 'test')])
#どのくらいの精度か確認
#「正解率」を用いて確認
from sklearn.metrics import accuracy_score

#一番良いモデルで予測
y_pred = model.predict(xgb.DMatrix(X_test), ntree_limit=model.best_ntree_limit)

#確率を表しているので、「0 or 1」にするために「0.5より大きいとき1」「0.5より小さいとき0」
prediction = [round(pred) for pred in y_pred]

acc = accuracy_score(y_test, prediction)
print(round(acc * 100, 2))

image.png

fig, ax = plt.subplots(figsize=(12,12))
xgb.plot_importance(model, max_num_features=20, height=0.5, ax=ax)
plt.show()

image.png

アンサンブル学習で正解率を上げる

#モデルを4つ作ってアンサンブル学習
from sklearn.ensemble import RandomForestClassifier, ExtraTreesClassifier, \
                             AdaBoostClassifier, GradientBoostingClassifier
class SklearnHelper(object):
    def __init__(self, clf, seed=0, params=None):
        params['random_state'] = seed
        self.clf = clf(**params)

    def fit(self, x, y):
        return self.clf.fit(x, y)

    def predict(self, x):
        return self.clf.predict(x) 

    def predict_proba(self, x):
        return self.clf.predict_proba(x)
#ランダムフォレストのパラメータ
rfc_params = {
    'n_jobs': -1,
    'n_estimators': 500,
    'warm_start': True, 
    'max_depth': 6,
    'min_samples_leaf': 2,
    'max_features' : 'sqrt',
    'verbose': 1
}

#エクストラツリーのパラメータ
etc_params = {
    'n_jobs': -1,
    'n_estimators':500,
    'max_depth': 8,
    'min_samples_leaf': 2,
    'verbose': 1
}

#アダーブーストのパラメータ
ada_params = {
    'n_estimators': 500,
    'learning_rate' : 0.75
}

#グラディエントブーストのパラメータ
gbc_params = {
    'n_estimators': 500,
    'max_depth': 5,
    'min_samples_leaf': 2,
    'verbose': 1
}
SEED = 0

rfc = SklearnHelper(clf=RandomForestClassifier, seed=SEED, params=rfc_params).fit(X_train, y_train)
etc = SklearnHelper(clf=ExtraTreesClassifier, seed=SEED, params=etc_params).fit(X_train, y_train)
ada = SklearnHelper(clf=AdaBoostClassifier, seed=SEED, params=ada_params).fit(X_train, y_train)
gbc = SklearnHelper(clf=GradientBoostingClassifier, seed=SEED, params=gbc_params).fit(X_train, y_train)
#予測値を出力

rfc_pred = rfc.predict_proba(X_train)
etc_pred = etc.predict_proba(X_train)
ada_pred = ada.predict_proba(X_train)
gbc_pred = gbc.predict_proba(X_train)

#「失敗の確率,成功の確率」と2列で出力される
#成功の確率のみを抽出

 preds_train = pd.DataFrame({'rfc_pred': rfc_pred[:, 1],
                             'etc_pred': etc_pred[:, 1],
                             'ada_pred': ada_pred[:, 1],
                             'gbc_pred': gbc_pred[:, 1]})

preds_train.head()

image.png

preds_train

image.png

y_train

image.png

preds_test_array = np.load('preds_test.npy')
preds_test = pd.DataFrame(preds_test_array, columns=['rfc_pred', 'etc_pred', 'ada_pred', 'gbc_pred'])
preds_test.head()

image.png

#Xgboost利用

params = {
    'silent': 1,
    'max_depth': 2,
    'min_child_weight': 1,
    'eta': 0.1,
    'tree_method': 'exact',
    'objective': 'binary:logistic',
    'eval_metric': 'logloss',
    'predictor': 'cpu_predictor'
}

dtrain = xgb.DMatrix(preds_train, label=y_train)
dtest = xgb.DMatrix(preds_test, label=y_test)
model = xgb.train(params=params,
                  dtrain=dtrain, 
                  num_boost_round=1000,
                  early_stopping_rounds=5, 
                  evals=[(dtest, 'test')])
from sklearn.metrics import accuracy_score

y_pred = model.predict(xgb.DMatrix(preds_test), ntree_limit=model.best_ntree_limit)
prediction = [round(pred) for pred in y_pred]

acc = accuracy_score(y_test, prediction)
print(round(acc * 100, 2))

image.png

考察

4つのモデルを組み合わせたアンサンブル学習によって正答率が69.76→69.81に上がったことが確認できた。

tomoxxx
こまったことを記事にするよ
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away