「不倫」データセットを機械学習して妻の説明変数パラメータを与えたところ、結果は…

結果はシロでした! 不倫しないそうです。(本人に結果報告したら「わかんないよ」と言われましたが…)
まずは学習データをロードします。

import pandas as pd
import numpy as np
from pandas import DataFrame, Series
import statsmodels.api as sm
X = sm.datasets.fair.load_pandas().data

学習データに対する正解を作ります。
未知のデータ(妻パラメータ)に対する不倫するか(1)しないか(0)の結果を知りたいんですよね。

def is_affairs(affairs):
    return 1 if affairs > 0 else 0
Y = X.affairs.apply(is_affairs)

affairsは「不倫情事に費やした時間」です。生々しい表現だなぁ・・・。

print(sm.datasets.fair.NOTE)
::
    Number of observations: 6366
    Number of variables: 9
    Variable name definitions:
        rate_marriage   : How rate marriage, 1 = very poor, 2 = poor, 3 = fair,
                        4 = good, 5 = very good
        age             : Age
        yrs_married     : No. years married. Interval approximations. See
                        original paper for detailed explanation.
        children        : No. children
        religious       : How relgious, 1 = not, 2 = mildly, 3 = fairly,
                        4 = strongly
        educ            : Level of education, 9 = grade school, 12 = high
                        school, 14 = some college, 16 = college graduate,
                        17 = some graduate school, 20 = advanced degree
        occupation      : 1 = student, 2 = farming, agriculture; semi-skilled,
                        or unskilled worker; 3 = white-colloar; 4 = teacher
                        counselor social worker, nurse; artist, writers;
                        technician, skilled worker, 5 = managerial,
                        administrative, business, 6 = professional with
                        advanced degree
        occupation_husb : Husband's occupation. Same as occupation.
        affairs         : measure of time spent in extramarital affairs
    See the original paper for more details.

正解をYに入れてあるので、その目的変数に強く相関する値affairsを説明変数から除きます。

X.drop("affairs", inplace=True, axis=1)

ちょっとめんどくさいんですが、数字の大小に意味がない変数、職業をダミー変数に変換しつつ、多重共線性を排除して、説明変数に連結します。

occs = pd.get_dummies(X.occupation)
occs.columns = Series(["occ" + str(num) for num in range(1,7)])
occs.drop("occ1", axis=1, inplace=True)
occs_husb = pd.get_dummies(X.occupation_husb)
occs_husb.columns = Series(["occ_husb" + str(num) for num in range(1,7)])
occs_husb.drop("occ_husb1", axis=1, inplace=True)
X = pd.concat([X, occs, occs_husb], axis=1)

occ, occ_husbの元となったデータを削除します。強く相関してますしね。

X.drop(["occupation", "occupation_husb"], inplace=True, axis=1)

学習用データと、答えあわせ用データに分けてモデルを作ります。9割を学習用データとして使います。より正確さを追求したいので。

from sklearn.linear_model import LogisticRegression
from sklearn.cross_validation import train_test_split
X_train, X_test, Y_train, Y_test = train_test_split(X, Y, train_size=0.9)
model = LogisticRegression()
model.fit(X_train, Y_train)

答えあわせをしてみます。

from sklearn.metrics import accuracy_score
predicted = model.predict(X_test)
print(accuracy_score(Y_test, predicted))
0.70800627943485084

正答率70%。
愛妻の説明変数を与えて、不倫するかしないかを予測してみると・・・

my_wife = Series([2, 31, 6, 2, 3, 16, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0])
model.predict(my_wife)

結果は array([0]) = 不倫しない となりました。
こういう一見アホらしいことを全力でやるのは、やっぱり楽しいですね。
今度は別のモデルを使って予測してみよう。

Close Bitnami banner
Bitnami