ロジスティック回帰

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

予測モデルを、以下のロジスティック関数(シグモイド関数)を使って作成。
<img width="119" alt="スクリーンショット 2016-05-03 16.47.40.png" src="https://qiita-image-store.s3.amazonaws.com/0/40159/c776935c-d750-594f-1593-9800faeed50a.png">

ロジスティック関数の形は以下となる。0〜1の値を取り、単調増加。
<img width="395" alt="スクリーンショット 2016-05-03 16.48.21.png" src="https://qiita-image-store.s3.amazonaws.com/0/40159/5db61a65-6902-076b-370a-79169280751f.png">

目的変数の行列xと説明変数yの関係は以下。(y=ax+bの右辺をexpの-1乗する形。)
<img width="164" alt="スクリーンショット 2016-05-03 16.49.51.png" src="https://qiita-image-store.s3.amazonaws.com/0/40159/055b6678-eadd-0c34-8631-0b0fb621d8ef.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()
```

<img width="782" alt="スクリーンショット 2016-05-03 16.53.17.png" src="https://qiita-image-store.s3.amazonaws.com/0/40159/000b22f4-660b-0cae-ae05-5e2b2a78727f.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')
```

<img width="399" alt="スクリーンショット 2016-05-03 16.57.17.png" src="https://qiita-image-store.s3.amazonaws.com/0/40159/187969ba-2df5-743d-45b6-8eb77ff62e4f.png">

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

<img width="416" alt="スクリーンショット 2016-05-03 16.57.21.png" src="https://qiita-image-store.s3.amazonaws.com/0/40159/388feefc-f54b-2911-e9b0-a59a283c1655.png">

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

<img width="422" alt="スクリーンショット 2016-05-03 16.57.35.png" src="https://qiita-image-store.s3.amazonaws.com/0/40159/5a02cfaa-4106-acce-de64-8fd703408ca0.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()
```

<img width="276" alt="スクリーンショット 2016-05-03 17.13.59.png" src="https://qiita-image-store.s3.amazonaws.com/0/40159/34e63a8a-1414-6501-ad31-68e8dfa19085.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()
```

ここまでの説明変数用データセット
<img width="1044" alt="スクリーンショット 2016-05-03 17.18.57.png" src="https://qiita-image-store.s3.amazonaws.com/0/40159/150e4ea5-2c09-e75f-1d2b-91f5c196dd62.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()
```

最終的な形

<img width="885" alt="スクリーンショット 2016-05-03 17.28.45.png" src="https://qiita-image-store.s3.amazonaws.com/0/40159/4bc44dae-fcaf-75dc-da55-9c0e7456e878.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
```

<img width="220" alt="スクリーンショット 2016-05-03 17.36.33.png" src="https://qiita-image-store.s3.amazonaws.com/0/40159/15abe194-8358-311f-eb0a-31943734d614.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%くらいの精度が出てることがわかる。