LoginSignup
187
186

More than 5 years have passed since last update.

ロジスティック回帰

Posted at

ロジスティック回帰とは

線形回帰と似ているが、目的変数が2値のときに利用する。
例えば、この人は商品を購入するか否か、棒に当たるか否か、引っ越すか否か、転職するか否かなどなど。

予測モデルを、以下のロジスティック関数(シグモイド関数)を使って作成。
スクリーンショット 2016-05-03 16.47.40.png

ロジスティック関数の形は以下となる。0〜1の値を取り、単調増加。
スクリーンショット 2016-05-03 16.48.21.png

目的変数の行列xと説明変数yの関係は以下。(y=ax+bの右辺をexpの-1乗する形。)
スクリーンショット 2016-05-03 16.49.51.png

利用データ用意

sklearnで不倫用のデータを使う。

get_affair_dataset.py
from sklearn.linear_model import LogisticRegression # ロジスティック回帰用
from sklearn.cross_validation import train_test_split # クロスバリデーションのsplit用
import statsmodels.api as sm

df = sm.datasets.fair.load_pandas().data # 不倫データのロード

不倫データの概要

describe_affair.py
df.head()

スクリーンショット 2016-05-03 16.53.17.png

rate_marriage:幸せ度、age:年齢、yrs_married:結婚年数、children:子供の数、religious:信仰度、educ:最終学歴、occupation:妻の職業、occupation_husb:旦那の職業、affairs:不倫経験(0より大きいと不倫経験あり)、Had_Affair:不倫フラグ(affairsが0>なら1がセットされてる)

簡単に不倫有無と適当なサンプルの関係をみる

easy_display1.py
# 年齢と不倫有無
sns.countplot('age', data = df.sort('age'), hue = 'Had_Affair', palette='coolwarm')

スクリーンショット 2016-05-03 16.57.17.png

easy_display2.py
# 結婚年数と不倫有無
sns.countplot('yrs_married', data = df.sort('yrs_married'), hue = 'Had_Affair', palette='coolwarm')

スクリーンショット 2016-05-03 16.57.21.png

easy_display3.py
# 子供の人数と不倫有無
sns.countplot('children', data = df.sort('children'), hue = 'Had_Affair', palette='coolwarm')

スクリーンショット 2016-05-03 16.57.35.png

年齢が上がる/結婚年数が多い/子供がいる方が不倫率が高い

※ ただし年齢が上がれば結婚年数が増えたり、子供の数が増えるなど、説明変数間でも関係性があると思われる。

ロジスティック回帰やってみる

前処理

やる前に、職業の変数がカテゴリ変数になっているので、これをダミー変数に置き換える。
カテゴリ変数とは、中の値の大小に意味がないもの。

change_dummy_value.py
# numpyのget_dummiesでdummy変数に変換。
occ_dummies = pd.get_dummies(df.occupation)
hus_occ_dummies = pd.get_dummies(df.occupation_husb)

# カラム名セット
occ_dummies.columns = ['occ1','occ2','occ3','occ4','occ5','occ6']
hus_occ_dummies.columns = ['hocc1','hocc2','hocc3','hocc4','hocc5','hocc6']

occ_dummies.head()

スクリーンショット 2016-05-03 17.13.59.png

上の感じで、occ1〜6のうちどれに当たるかが0,1のフラグで置き換えてあげる。

続けて、説明変数を取得する。

get_x.py
# Xに、元のデータフレームから職業、旦那の職業、結婚有無を削除したものをセット。
X = df.drop(['occupation', 'occupation_husb', 'Had_Affair'], axis =1) 
# 職業をダミー変数化したデータフレームを用意
dummys = pd.concat([occ_dummies, hus_occ_dummies], axis =1)
# 職業等を削除したデータフレームに、職業ダミー変数データフレームを結合
X = pd.concat([X, dummys], axis=1)

X.head()

ここまでの説明変数用データセット
スクリーンショット 2016-05-03 17.18.57.png

多重共線性

ある説明変数が、他の説明変数を1つまたは複数で表現できる場合、多重共線性があるという。例えば今回は、occ1は、occ2〜occ6の値で一意に決まる関係にある。(occ2〜6に1が1個以上あれば、occ1=0、そうでなければocc1=1)
この場合、逆行列が計算できなかったり、計算できても得られる結果の信頼性が低くなってしまう。
なので、これをなくすべく、occ1とhocc1を削除する。

drop_nonavailable_value.py
X = X.drop('hocc1', axis = 1)
X = X.drop('hocc1', axis = 1)
# affairsは、目的変数を作成するのに使っているので、これも説明変数から除く。
X = X.drop('affairs', axis =1 )

X.head()

最終的な形

スクリーンショット 2016-05-03 17.28.45.png

sklearnを使って実行

do_logistic_regression.py
# 目的変数セット
Y = df.Had_Affair
Y = np.ravel(Y)    # np.ravelでYを1次元配列にする

# ロジスティック回帰実行
log_model = LogisticRegression() # インスタンス生成 
log_model.fit(X, Y)              # モデル作成実行
log_model.score(X, Y)            # モデルの予測精度確認(72.6%)
> 0.7260446120012567

各変数の係数を確認

confirm_coefficient.py
# インスタンスの.coef_[0]に、係数が入っている
coeff_df = DataFrame([X.columns, log_model.coef_[0]]).T
coeff_df

スクリーンショット 2016-05-03 17.36.33.png

この係数が大きいところが、影響が多いところになる。
ただし、説明変数のデータの単位が統一されていないので、単純に横並びで比較はできない。
例えば、occ5はyrs_marriedの9倍くらいあるから、結婚年数は見なくてOK!!とは単純にならない。

ついでに

いつものごとく、trainとtestに分ける方法も書いとく。

do_logistic_regression_train_test.py
# trainとtest用データ用意
X_train, X_test, Y_train, Y_test = train_test_split(X, Y)

log_model2 = LogisticRegression() 
log_model2.fit(X_train, Y_train)           # trainデータでモデル作成
class_predict = log_model2.predict(X_test) # testデータを予測

from sklearn import metrics # 予測精度確認用

metrics.accuracy_score(Y_test, class_predict) # 精度確認
>0.73115577889447236

73%くらいの精度が出てることがわかる。

187
186
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
187
186