🌟

【24日目】スパースモデリングをやってみる【2021アドベントカレンダー】

2021/12/24に公開

2021年1人アドベントカレンダー(機械学習)、24日目の記事になります。

https://qiita.com/advent-calendar/2021/solo_advent_calendar

テーマは Lasso回帰を使ったスパースモデリング になります。

Lasso回帰とは、正則化された線形回帰の一つで、線形回帰のコスト関数に対して重みの合計を足したもの。

詳細は下記サイトを参照。

https://aizine.ai/ridge-lasso-elasticnet/

Lasso 回帰と Ridge 回帰の違いについては下記参照。

https://www.acceluniverse.com/blog/developers/2020/01/ridgelasso.html

Colab のコードはこちら Open In Colab

LASSO 回帰によるスパースモデリング

alpha_lasso = []
coef_list = []
intercept_list = []
train_score = []
test_score = []
# 探索範囲
lasso_1 = np.linspace(0.01,100,1000)

for i in lasso_1:

    model = Lasso(
                    alpha = i, 
                    max_iter=10000, 
                    random_state=SEED
                    )

    # 学習
    model.fit(X_train,y_train)

    # 推論
    pre_train = model.predict(X_train)
    pre_test = model.predict(X_test)

    # スコアの集約
    alpha_lasso.append(i)
    coef_list.append(model.coef_) # 回帰係数
    intercept_list.append(model.intercept_) # 切片
    train_score.append(model.score(X_train, y_train))
    test_score.append(model.score(X_test, y_test)) # テストデータに対するR2スコア

# DataFrame、Series 化
df_count = pd.Series(alpha_lasso,name = 'alpha') # 正則化の強さ
df_coef= pd.DataFrame(coef_list, columns = X_train.columns) # 回帰係数
df_inter = pd.Series(intercept_list,name = 'intercept') # 切片
df_train_score = pd.Series(train_score,name = 'train_score') # 学習データに対するスコア
df_test_score = pd.Series(test_score,name = 'test_score') # テストデータに対するスコア

# alphaと回帰係数の可視化
plt.title('alpha vs coefficent graph like R/glmnet')
plt.xscale('log')
plt.xlabel('alpha')
plt.ylabel('coefficient')
plt.plot(df_count,df_coef)
plt.legend(labels = df_coef.columns,loc='uper right',fontsize=7)
plt.show()

# alphaとR2スコアのグラフ
df_score = pd.concat([df_train_score,df_test_score], axis=1)
plt.title('alpha vs R2 score(train/test)')
plt.xscale('log')
plt.xlabel('alpha')
plt.ylabel('r2_score')
plt.plot(df_count,df_score)
plt.legend(labels = df_score.columns,loc='uper right',fontsize=8)
plt.show()

alphaと回帰係数の可視化

alphaとR2スコアのグラフ

シンプルな学習・推論

alphaとR2スコアのグラフ をみると、alpha が 0.1 あたりが R2スコアが低くなっていますので、alpha に 0.1 を設定して学習・推論を行ってみます。

model = Lasso(
            alpha = 0.1, 
            max_iter=10000, 
            random_state=SEED
            )

# 学習
model.fit(X_train, y_train)

# 推論
y_pred = model.predict(X_test)

# 評価
rmse = mean_squared_error(y_test, y_pred, squared=False)
print("RMSE", rmse)

出力:
RMSE 0.9313807445033818

GroupKFold を使って Lasso 回帰

最も RMSE が小さくなる最適な alpha を可視化しながら探索してみます。

gkf = GroupKFold(n_splits=5)

groups = X_train["Genre"]

for i, (train_index, test_index) in enumerate(gkf.split(X_train, y_train, groups)):
    X_train_gkf, X_test_gkf = X_train.iloc[train_index], X_train.iloc[test_index]
    y_train_gkf, y_test_gkf = y_train.iloc[train_index], y_train.iloc[test_index]

    # 探索
    for alpha in range(-10, 20, 1):

        model = Lasso(
                    alpha = alpha/10 , 
                    max_iter=10000,
                    random_state=SEED
                    )

        # 学習
        model.fit(X_train_gkf, y_train_gkf)

        # 推論
        y_pred = model.predict(X_test_gkf)

        # 評価
        rmse = mean_squared_error(y_test_gkf, y_pred, squared=False)
        
        # 可視化
        plt.scatter(
            alpha/10, 
            rmse,
            color="red"
            )
        
    plt.title(f"fold {i}")
    plt.xlabel('alpha')
    plt.ylabel('rmse')
    plt.show()

alpha が 0 付近の時が 最も RMSE が小さくなっているようです。

LassoCV

LassoCV を使うとクロスバリデーションにより自動的に最適なパラメーターを探索することができます。

model = LassoCV(alphas=[0.01, -1, 2], cv = 5, max_iter=100000)

# 学習
model.fit(X_train, y_train)

# ベストスコア
print("Best alpha:", model.alpha_)
print("重み:", model.coef_)
print("切片:", model.intercept_)

# ベストスコア(alpha)を設定
best_model = Lasso(
                alpha=model.alpha_,
                max_iter=100000,
                random_state=SEED
                )

# ベストスコアで学習
best_model.fit(X_train, y_train)

# ベストスコアのモデルで推論
y_pred = best_model.predict(X_test)

# 評価
rmse = mean_squared_error(y_test, y_pred, squared=False)
print("RMSE", rmse)

出力:
Best alpha: 0.01
重み: [-0.00000000e+00 1.19582956e-01 5.16855133e-02 7.60801569e-03
0.00000000e+00 3.40944575e-02 0.00000000e+00 0.00000000e+00
4.57007862e-03 -0.00000000e+00 0.00000000e+00 -6.01479616e-04
-1.33607435e-05 3.14296420e-07 3.51993675e-04 -1.63156663e-06
6.92296310e-07]
切片: -0.05693081814503
RMSE 0.9232324622403981

24日目は以上になります、最後までお読みいただきありがとうございました。

参考サイト

https://scikit-learn.org/stable/modules/generated/sklearn.linear_model.Lasso.html

https://scikit-learn.org/stable/modules/generated/sklearn.linear_model.LassoCV.html#sklearn.linear_model.LassoCV

https://qiita.com/motoyuki1963/items/04d8ec264e4b016552aa

https://stats.biopapyrus.jp/sparse-modeling/python-glmnet.html

https://panda-clip.com/lasso-param/

Discussion