【超初心者向け】重回帰分析を numpy と scikit-learn で実装して比較すると推論値が違う?!原因は?

オウルです。

今回は単回帰分析重回帰分析です。日頃からお世話になっている Chainer Tutorial7. 単回帰分析と重回帰分析 にある単回帰分析と重回帰分析を学ぶ理由が、しっくりきたので、まずはそれを最初に紹介します。

単回帰分析と重回帰分析を紹介することには 2 つの理由があります。 1 つ目は、単回帰分析と重回帰分析の数学がニューラルネットワーク含めたディープラーニングの数学の基礎となるためです。 2 つ目は、単回帰分析のアルゴリズムを通して微分、重回帰分析のアルゴリズムを通して線形代数に関する理解を深めることができるためです。

ということで、Chainer Tutorialで紹介されている単回帰分析と重回帰分析の内容を python で実装しながら理解を深めます。重回帰分析は、scikit-learnnumpy で実装して推論を比較してみます。

単回帰分析

そもそも回帰分析とは、何モノなんでしょう。

回帰(かいき、英: regression)とは、統計学において、Y が連続値の時にデータに Y = f(X) というモデル(「定量的な関係の構造[1]」)を当てはめる事。別の言い方では、連続尺度の従属変数(目的変数)Y と独立変数(説明変数)X の間にモデルを当てはめること。X が1次元ならば単回帰、X が2次元以上ならば重回帰と言う。Y が離散の場合は分類と言う。回帰分析(かいきぶんせき、英: regression analysis)とは、回帰により分析する事。回帰で使われる、最も基本的なモデルは Y = AX + B という形式の線形回帰である。

回帰分析の説明を確認したので、まずは単回帰分析からです。Chainer Tutorial 7.1. 単回帰分析 では、 1 つの説明変数(部屋の広さ)から 1 つの目的変数(家賃)を予測しています。 それでは、手を動かしながら理解を深めていきましょう。

「部屋の広さ」から「家賃」を予測

ライブラリのインポート

In [0]:

データ作成

In [1]:

データのプロット

In [2]:
Out [2]:

データの中心化

Chainer Tutorial にあるデータの中心化の数式を見ると、偏差を求める数式ですね。

In [3]:

パラメータの最適化

次に最適な \(w\) (重み)を以下の数式で求めます。

\(w = \frac{\sum_{n=1}^N x_n t_n}{\sum_{n=1}^N x^2_n}\)

7.1.5. Step 3:最適なパラメータを求める(単回帰分析) で上記の数式の導出を、僕でも分かるくらい分かり易く説明をしてくれています。

In [4]:
In [5]:
Out [5]:
In [6]:
Out [6]:
In [7]:
Out [7]:

推論

In [8]:

Chainer Tutorial 7.1.6. 数値例 の説明にあるように、モデル化の際に中心化を行っていた処理を推論の際には元に戻して計算します。

In [9]:
Out [9]:

Chainer Tutorial 7.1.6. 数値例 の結果と一致しています。 python での実装は、ひとまず問題なさそうです。

重回帰分析

続いて重回帰分析では、Chainer Tutorial 9. scikit-learn 入門 で出てくる Boston house prices dataset というデータセットを使用します。

まず、scikit-learn「サイキット・ラーン」で実装します。実装内容は、Chainer Tutorial scikit-learn の内容に沿っています。詳細は、Chainer Tutorial 9. scikit-learn 入門 を参照してください。その後、 numpy での実装と比較してみます。

scikit-learn

データセットのロード

In [0]:
In [1]:

データセットの分割

In [2]:

モデルの訓練

In [3]:
Out[3]:
In [4]:
Out[4]:
In [5]:
Out[5]:
In [6]:
Out[6]:

推論

In [7]:
Out[7]:

numpy

In [0]:

パラメータの最適化

パラメータの最適化に正規方程式を使用します。

\(\begin{split}\begin{aligned}
{\bf w} &= ({\bf X}^{\rm T}{\bf X})^{-1}{\bf X}^{\rm T}{\bf t}
\end{aligned}\end{split}\)

正規方程式の導出は、7.2.4. Step 3:パラメータを最適化する(重回帰分析) でとても丁寧に説明してくれています。

In [1]:
In [2]:
Out [2]:

推論

In [3]:
In [4]:
Out [4]:

推論値の比較

scikit-learn での x_test[:1]テストデータの推論値は ”24.9357079”、numpy でのx_test[:1]テストデータの推論値は ”24.22543525” ・・・違ってる・・・

実装では同じ訓練データを使用しているので、データの問題ではなさそう。LinearRegression 内部の最適化方法が違うのかもと思いつつ、もう一度「Chainer Tutorial 7. 単回帰分析と重回帰分析 」を読み直します。

すると、これだと思うところがありました。

重回帰分析では、 \(M\) 個の重み \(w_{1}, w_{2}, \dots, w_{M}\) と 1 個のバイアス \(b\) があり、合わせて \(M+1\) 個のパラメータが存在します。これらのパラメータをうまく定式化することを考えます。 そこで、今回は \(x_0 = 1\)、\(w_0 = b\) とおくことで、

\(\begin{split}\begin{aligned}
y
&= w_{1}x_{1} + w_{2}x_{2} + \cdots + w_{M}x_{M} + b \\
&= w_{1}x_{1} + w_{2}x_{2} + \cdots + w_{M}x_{M} + w_{0}x_{0} \\
&= w_{0}x_{0} + w_{1}x_{1} + \cdots + w_{M}x_{M} \\
&= \sum_{m=0}^M w_{m} x_{m}
\end{aligned}\end{split}\)

のように \(b\) を総和の内側の項に含めて、簡潔に表記できるようにします。

そういえば、バイアスを考慮していないです。ということで numpy の実装を修正します。

In [2]:
Out [2]:
In [3]:
In [4]:
Out [4]:

scikit-learn での x_test[:1]テストデータの推論値は ”24.9357079”、numpy での x_test[:1]テストデータの推論値は ”24.9357079” ・・・同じ。

手を動かしていなかったら、分かったつもりになっているところでした。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

CAPTCHA