Pythonでグラフを書く (3)

次に、データに近似直線を引く方法を整理します。

Numpyで直線近似

import numpy as np
import matplotlib.pyplot as plt

データを準備します。
結果が適切かどうかを見たいので、直線状に乗るデータにランダムなノイズを加えたものを作ります。

# シードを固定
# ランダム値が実行ごとに変わらないようにするため (必須ではない)
np.random.seed(0)

# xは-10〜+10までの整数をインクリメント
# yはxの2倍

x = np.linspace(-10, 10, 21)
y_ = x*2

# ±10の範囲でノイズを加える
random_noise = np.random.rand(21)*10
y = y_ + random_noise

# 各データの値を表示
for n in range(len(x)):
    print('x: {}, y_: {}, y: {}'.format(x[n], y_[n], np.round(y[n], 2)))

出力結果は以下のようになります。
2列目(y_)がノイズを加える前の値で、3列目(y)がノイズを加えたあとの値です。

x: -10.0, y_: -20.0, y: -14.51
x: -9.0, y_: -18.0, y: -10.85
x: -8.0, y_: -16.0, y: -9.97
x: -7.0, y_: -14.0, y: -8.55
x: -6.0, y_: -12.0, y: -7.76
x: -5.0, y_: -10.0, y: -3.54
x: -4.0, y_: -8.0, y: -3.62
x: -3.0, y_: -6.0, y: 2.92
x: -2.0, y_: -4.0, y: 5.64
x: -1.0, y_: -2.0, y: 1.83
x: 0.0, y_: 0.0, y: 7.92
x: 1.0, y_: 2.0, y: 7.29
x: 2.0, y_: 4.0, y: 9.68
x: 3.0, y_: 6.0, y: 15.26
x: 4.0, y_: 8.0, y: 8.71
x: 5.0, y_: 10.0, y: 10.87
x: 6.0, y_: 12.0, y: 12.2
x: 7.0, y_: 14.0, y: 22.33
x: 8.0, y_: 16.0, y: 23.78
x: 9.0, y_: 18.0, y: 26.7
x: 10.0, y_: 20.0, y: 29.79

では、xとy(ノイズ付加)を図に表します。

# ノイズを加えた結果を散布図で表示
fig = plt.figure()
ax = fig.add_subplot(111)

ax.scatter(x,y)
fig.show()

ばらつきはあるものの、元になった直線がうっすらと見えてはいますね。
この値を使って直線近似を行います。

直線近似

# 1次 (直線) 近似
z1 = np.polyfit(x, y, 1) # 1次式の係数がzに格納される
print(z1)

# # 2次近似
# z2 = np.polyfit(x, y, 2) # 2次式の係数がzに格納される
# print(z2)

結果は以下のとおりです。
1つ目が傾き、2つ目が切片を示しています。
元々は、\(y=2x+5\)でしたので、それなりの値が出せています。

[1.98233716 4.64964655]

今回はコメントアウトしていますが、polyfit()の3番目の引数を2に設定すると、2次の近似ができます。

近似結果を重ねる

では、データの近似結果が本当にそれらしくなっているかを見てみます。
求めた近似直線の係数を使って、xに該当するyの値を求めます。
ここでは、y1_predという配列に格納しました。

fig2 = plt.figure()
ax = fig2.add_subplot(111)

# 求めた係数を用いて、xを代入してyの値を算出する
y1_pred = np.poly1d(z1)(x)
# y2_pred = np.poly1d(z2)(x) # 2次近似の場合

# オレンジ色で近似直線を引く
ax.scatter(x,y)
ax.plot(x, y1_pred, '-', color='orange')  
fig.show()

いい感じです。

決定係数(\(R^2\))の計算

もうひとつ、この近似結果がどれくらい使えるのかを示す指標を出してみます。
実際の値と、近似結果によって推定した値とがどれくらい一致するかを表す決定係数 (\R^2\)です。
エクセルでも近似を行ったときに出してくれますね。

\(R^2\)を求めるためには、sklearnをインポートする必要があります。

from sklearn.metrics import r2_score

使用する関数はその名のとおり、r2_score()です。
真(実測)値と推定値を関数に入れることで、\(R^2\)を計算してくれます。

r2 = r2_score(y, y1_pred) 
print(r2)

0.949794904242459

ここで\(R^2\)は、0~1の範囲の値を取り、1に近くなるほど真値と推定値との相関が高いことを示します。つまり、上の数値0.95は真値を表すのに非常によい近似ができていると言えます。

元のデータ自体に外れ値もありませんし、見てわかるように近似した直線に沿ってデータが並んでいますので、納得のできる結果です。

とりあえず、図の描画についてはここまでにします。

コメントを残す

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