📈
`statsmodels`と`sklearn`でのロジスティック回帰の挙動の違いについて
TL;DR
- Pythonでロジスティック回帰をする方法には
sklearn
とstatsmodels
がある -
sklearn.linear_model.LogisticRegression
はデフォルトで正則化(L2=1)がついている -
statsmodels.api.Logit
は正則化がついていない - 備えよう
本編
問題設定
seaborn
に含まれるiris
データセットにおいて、versicolor
種であるかどうかを判断するロジスティック回帰モデルを考える。
# %% loading data
iris_df = sns.load_dataset("iris")
iris_df = iris_df[(iris_df['species']=='versicolor')
| (iris_df['species']=='virginica')].reset_index(drop=True)
# %% utility function to comparison.
def result_to_df(features, params):
out_dict = {
'features': features,
'params':params
}
out = pd.DataFrame(out_dict)
return out
# %% settings target and features
# features
X = iris_df.drop("species",axis=1)
# versicolor convert from category to binary values.
y = iris_df['species'].map({'versicolor': 0, 'virginica': 1})
モデル実装
statsmodels
statsmodels
は切片を定数項としてX
に入れないといけないっぽいので、
切片なしでモデルを作ることにする。
clf_statsmodels = sm.Logit(y, X)
clf_statsmodels = clf_statsmodels.fit()
statsmodels_params = result_to_df(features=clf_statsmodels.params.index.values,
params=clf_statsmodels.params.values)
statsmodels_params
# features params
# sepal_length -6.327719
# sepal_width -6.618187
# petal_length 8.433801
# petal_width 10.282544
sklearn
statsmodels
に合わせて切片なしモデルを組む
clf_sklearn_default = LogisticRegression(random_state=0, fit_intercept=False)
clf_sklearn_default.fit(X, y)
sklearn_default_params = result_to_df(features=X.columns.values,
params=clf_sklearn_default.coef_[0])
sklearn_default_params
結果を見ると明らかに回帰係数の値が異なる。これはsklearnのロジスティック回帰モデルは、
デフォルトでL2正則化がついていることに起因する。
official document
# features params
# sepal_length -1.863342
# sepal_width -1.646021
# petal_length 2.477247
# petal_width 2.593144
回避策
あんまりstatsmodels
と並行して使うことはないと思うが、値を近くする方法はいくつかある。
1. 正則化パラメータをめっちゃ小さくする
C
という引数が、正則化の強さの逆数であるので、こいつをめっちゃでっかくする。
clf_sklearn_low_penalty = LogisticRegression(
random_state=0,
fit_intercept=False,
C = 1e9)
clf_sklearn_low_penalty.fit(X, y)
sklearn_low_penalty_params = result_to_df(features=X.columns.values,
params=clf_sklearn_low_penalty.coef_[0])
sklearn_low_penalty_params
結果的に近くなる。
# features params
# sepal_length -6.327718
# sepal_width -6.618181
# petal_length 8.433797
# petal_width 10.282542
2. 正則化しない
penalty=None
にすると正則化しないらしい。こっちの方が良い。
clf_sklearn_None_penalty = LogisticRegression(
random_state=0,
fit_intercept=False,
penalty=None)
clf_sklearn_None_penalty.fit(X, y)
sklearn_None_penalty_params = result_to_df(features=X.columns.values,
params=clf_sklearn_None_penalty.coef_[0])
sklearn_None_penalty_params
# features params
# sepal_length -6.327718
# sepal_width -6.618181
# petal_length 8.433798
# petal_width 10.282542
結論
統計モデリングの上では、パラメータの一致性・不偏性を意識する場面があるので、
正則化のないモデルを組んだほうが良いことがある。
sklearn
は機械学習の領域で広く使われるライブラリの1つであるから、統計モデリングをこれを使って実施する場面も多いだろうが、正則化項については気をつけた方が良い。
また今回は記述していないが、statsmodels
は回帰診断(モデル適合度など)の評価が可能であったり、パラメータの有意性検定も可能であるので、R等で回帰分析に親しんでいる場合は、こちらを援用した方が障壁は少ないと思う。
実装元
githubに記載している。
https://github.com/8-u8/learning_Python/blob/main/sklearn_logistic/logistic_regression_test.py
Discussion