MachineLearning

ロバスト回帰とは?Pythonを使ったハンズオンで解説【機械学習】

ロバスト回帰 Python
ロバスト回帰が分からない人
ロバスト回帰が分からない人
ロバスト回帰ってなんだろう…。

よく分からないから、Pythonを使った実装を合わせて勉強していきたいな…。

この記事では、上記のような悩みを解決していきます。

 

この記事の想定読者

想定している読者は、次のとおりです。

  • 機械学習を勉強している人
  • ロバスト回帰がよく分からない人
  • Pythonを使ったロバスト回帰の実装も知りたい人

 

この記事では「ロバスト回帰とその実装」について紹介していきます。

ロバスト回帰って、若干マイナーなので、あまり資料が出ていなくて困りますよね。

 

でも本記事を読み終えれば、ロバスト回帰とは何か分かるだけでなく、Pythonを使った実装まで学習できるようになります。

この記事を書いている僕は、大学時代は数学科に所属していて、今はデータサイエンティストとして働いています。

とはいえ、分かりやすいような解説を心がけているので、最後まで読んでいただけたらと思います(`・ω・´)!

 

ロバスト回帰とは?

ロバスト回帰 Python

ロバスト回帰とは、データに含まれている外れ値の影響を、自動的に軽減するための学習手法です。

なぜ外れ値の影響を軽減するのかといえば、間違った学習をおこなわないためですよね。

 

たとえば、イヌとネコを判別させるモデルを作成するとき、以下のような学習データを用意するかと思います。

  • イヌの画像 × 100枚
  • ネコの画像 × 100枚

このとき、イヌの画像100枚のうち、誤って1枚だけキツネの画像を入れてしまったとします。

ロバスト回帰 外れ値

そうすると、キツネの画像を避けておけば良い精度が出るはずだったモデルが出来上がってしまいます。

 

あらかじめキツネの画像があったことを分かっていれば、手動で削除できるかもしれませんが、手作業で消すのはメンドイですよね。

こういった面倒な「外れ値」の影響を、自動的に軽減してくれるのが、ロバスト回帰になります。

 

【具体例】ロバスト回帰を、Pythonを使ったハンズオンで解説

ロバスト回帰 Python

ざっくりと理解したところで、Pythonのコードを書きつつロバスト回帰を学習していきましょう。

テーマとしては、体重と身長の関係を回帰するタスクを扱っていきます。

 

この記事で使うコード

import numpy as np
import pandas as pd
import statsmodels.api as sm

import matplotlib.pyplot as plt

np.random.seed(seed=1)

def get_data():
    x1 = np.random.randint(45, 55, (1,25))
    y1 = np.random.randint(155, 165, (1,25))

    x2 = np.random.randint(56, 80, (1,24))
    y2 = np.random.randint(167, 177, (1,24))

    outlier_x = np.random.randint(170, 173, (1,1))
    outlier_y = np.random.randint(50, 52, (1,1))

    x = np.concatenate([x1, x2], 1)
    y = np.concatenate([y1, y2], 1)
    x = np.concatenate([x, outlier_x], 1)
    y = np.concatenate([y, outlier_y], 1)

    matrix = np.concatenate([x.T, y.T], 1)
    df = pd.DataFrame(matrix, columns=['x', 'y'])
    return df

def fit_model(df, robust_flg=False):
    if robust_flg:
        model = sm.RLM(df.y, sm.add_constant(df.x))
    else:
        model = sm.OLS(df.y, sm.add_constant(df.x))
    result = model.fit()
    
    print(result.params)
    return result

def plot_graph(df, ols_model=None, robust_model=None):
    plt.scatter(df.x,df.y)
    if (ols_model or robust_model) is not None:
        plt.plot(df.x, ols_model.predict(sm.add_constant(df.x)), label='Simple Regression') 
        plt.plot(df.x, robust_model.predict(sm.add_constant(df.x)), label='Robust Regression')
    plt.xlim(0,180)
    plt.xlim(40,200)
    plt.xlabel("weight(kg)")
    plt.ylabel("height(cm)")
    plt.legend()
    plt.tight_layout()
    plt.show()


if __name__ == "__main__":
    df = get_data()
    # plot_graph(df)

    ols_model = fit_model(df, robust_flg=False)
    rlm_model = fit_model(df, robust_flg=True)

    plot_graph(df, ols_model, rlm_model)

※①Pythonファイルで書いています。notebookが良い方は、このファイルをimportして使ってください。

※②転記OKです。その場合、この記事のURLを「参考URL」として付けてください。

 

STEP① : データの作成と確認

 

まずは、今回のハンズオンで使うデータを作成していきましょう。

データの作成には、以下の関数を使います。

def get_data():
    x1 = np.random.randint(45, 55, (1,25))
    y1 = np.random.randint(155, 165, (1,25))

    x2 = np.random.randint(56, 80, (1,24))
    y2 = np.random.randint(167, 177, (1,24))

    outlier_x = np.random.randint(170, 173, (1,1))
    outlier_y = np.random.randint(50, 52, (1,1))

    x = np.concatenate([x1, x2], 1)
    y = np.concatenate([y1, y2], 1)
    x = np.concatenate([x, outlier_x], 1)
    y = np.concatenate([y, outlier_y], 1)

    matrix = np.concatenate([x.T, y.T], 1)
    df = pd.DataFrame(matrix, columns=['x', 'y'])
    return df

中身が若干ややこしいですが、x1, x2, y1, y2では身長と体重のデータを、ランダムで作成しています。

さらに、outlier_xoutlier_yで、今回のデータにおける外れ値を作成してあります。

 

そして、これらを扱いやすくするために、データフレームの形で所持している感じですね。

この関数を呼び出すと、データフレームを返してくれるようになっているので、df = get_data()のようにして使ってあげましょう。

 

作成したデータの可視化

以下のように、作成したデータフレームをplot_graph()を使ってあげると、可視化できるようになっています。

if __name__ == "__main__":
    df = get_data()
    plot_graph(df)
ロバスト回帰 身長と体重

上の画像のように、基本的には左上にデータが固まっているのに対し、1つだけ右下にデータがある感じになっています。

右下は、体重が170cmくらいで身長が48kgになっており、これはデータ入力が間違っていることを想定して作成しました。

なので、本来であれば170cmで48kgという、モデル級の体型になります。

 

STEP② : 単回帰とロバスト回帰のモデルを作成

 

データの確認ができたら、さっそく単回帰とロバスト回帰のモデルを作成していきます。

モデルを作成するコードは、以下のとおりです。

def fit_model(df, robust_flg=False):
    if robust_flg:
        model = sm.RLM(df.y, sm.add_constant(df.x))
    else:
        model = sm.OLS(df.y, sm.add_constant(df.x))
    result = model.fit()
    
    print(result.params)
    return result

robust_flg=Falseのときは単回帰モデルが、robust_flg=Trueのときはロバスト回帰モデルを作成するようになっています。

 

これを呼び出してあげれば、学習済みのモデルが返される感じです。

if __name__ == "__main__":
    df = get_data()
    # plot_graph(df)
    
    ols_model = fit_model(df, robust_flg=False)
    rlm_model = fit_model(df, robust_flg=True)

 

STEP③ : 作成したモデルの予測値を散布図に出力

 

最後に、作成したモデルの予測値を、データが描かれていた散布図にプロットしていきます。

使う関数は、こちらのとおり。

def plot_graph(df, ols_model=None, robust_model=None):
    plt.scatter(df.x,df.y)
    if (ols_model or robust_model) is not None:
        plt.plot(df.x, ols_model.predict(sm.add_constant(df.x)), label='Simple Regression') 
        plt.plot(df.x, robust_model.predict(sm.add_constant(df.x)), label='Robust Regression')
    plt.xlim(0,180)
    plt.xlim(40,200)
    plt.xlabel("weight(kg)")
    plt.ylabel("height(cm)")
    plt.legend()
    plt.tight_layout()
    plt.show()

これを使うと、単回帰とロバスト回帰の両方のグラフが出力されるようになっています。

 

グラフ出力前に : 単回帰式だけ出力

あとは関数を呼び出してあげるだけで、ロバスト回帰の実装は終了してしまうのですが、その前に「単回帰のみ」で見てみましょう。

ロバスト回帰 外れ値

上が単回帰モデルの予測値になっているのですが、モロに右下の外れ値の影響を受けていますよね。

この予測モデルの場合だと、体重が増えるに連れて、身長が低くなっていくという結果になってしまいます。

 

これは、単回帰モデルが右下にある「外れ値」の影響を軽減できていないからですね。

直感的に考えてみても、身長が高くなればなるほど、骨の重量が増えていくので体重は増えるように感じます。

なので、体重から身長を予測するモデルとしては、単回帰モデルのままでは微妙に感じます。

 

ロバスト回帰を実装

というわけで、前置きが長くなりましたが、ロバスト回帰を実装していきましょう。

使う関数は、plot_graph()で、以下のように呼び出してあげます。

if __name__ == "__main__":
    df = get_data()
    # plot_graph(df)
    
    ols_model = fit_model(df, robust_flg=False)
    rlm_model = fit_model(df, robust_flg=True)

    plot_graph(df, ols_model, rlm_model)

デフォルトだと散布図のみを出力するようになっていますが、学習したモデルを関数に渡してあげると予測値もプロットしてくれる感じです。

 

ロバスト回帰の結果を見てみると、外れ値の影響を軽減できていることがわかりますね。

ロバスト回帰 Python

身長が増えると体重も重くなっていくので、直感的にも理解しやすいモデルになったかと思います。

 

このように、データの中に外れ値がある可能性があるなら、単回帰を使うよりもロバスト回帰を使ってあげた方が、信頼性も説得力も高いモデルを作成できるようになります。

 

まとめ : ロバスト回帰以外にも、データサイエンスを学習しよう

 

というわけで、回帰モデルの「ロバスト回帰」について紹介してきました。

テーブルデータだとGBDTが強いですが、基本的な線形モデルは非データサイエンティスト向けに説明しやすいこともあり、まだまだ使い道は残されています。

なので、しっかりとおさえておいて損はないかと(`・ω・´)!

 

あとは、ざっくりとブログ記事で理解したあとに、書籍を使って体型的に学習していくのもオススメですね。

データサイエンスでおすすめの本は、以下の記事にて紹介しています。

データサイエンス 本 おすすめ
【2020年最新】データサイエンスでおすすめの本10冊【現役が紹介】 【2020年最新】データサイエンスでおすすめの本10冊【現役が紹介】 2020年最新版にて、データサイエン...

 

さらにスキルアップすべく、学習を継続していきましょう(`・ω・´)!

おしまいです。

 

おすすめの記事