scikit-learnを使ってみる

scikit-learnを使ってみたので、そのメモです。
scikit-learnはPythonから使える機械学習ライブラリです。
https://scikit-learn.org/stable/index.html

# 線形回帰

## 一次関数

一次関数 y = 2x + 3 を求めます。
ｘの値を0〜10の範囲で50個準備します。
最初の75%をトレーニングデータ、残り25%をテストデータとして使用します。

```python
import numpy as np
from sklearn import linear_model
from sklearn.model_selection import train_test_split
import matplotlib.pyplot as plt

# Y = 2X + 3を求める関数とする。
X = np.linspace(0, 10, num=50)
Y = 2 * X + 3

train_X, test_X, train_Y, test_Y = train_test_split(X, Y, shuffle=False)
train_X2 = train_X.reshape(-1, 1)
test_X2 = test_X.reshape(-1, 1)

clf = linear_model.LinearRegression()
train_X2 = train_X.reshape(-1, 1)
clf.fit(train_X2, train_Y)

print(f'回帰係数={clf.coef_}')
print(f'切片={clf.intercept_}')
print(f'決定係数={clf.score(train_X2, train_Y)}')

plt.scatter(X, Y, label='data')
plt.plot(train_X, clf.predict(train_X2), color='green', label='train')
plt.plot(test_X, clf.predict(test_X2), color='red', label='test')
plt.legend()
plt.savefig('linear_regression1.png')
plt.show()
```
結果をグラフにしてみます。

![linear_regression1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1106967/e33c276a-4858-6791-7daf-d0cf259aaf72.png)

完璧です！

## 二次関数

同じような感じで二次関数を求めます。
求める式は、y = x^2 + 2x + 3 です。

```python
import numpy as np
from sklearn import linear_model
from sklearn.model_selection import train_test_split
import matplotlib.pyplot as plt

# Y = X^2 + 2X + 3を求める関数とする。
X = np.linspace(0, 10, num=50)
Y = X**2 + 2 * X + 3

train_X, test_X, train_Y, test_Y = train_test_split(X, Y, shuffle=False)
train_X2 = train_X.reshape(-1, 1)
test_X2 = test_X.reshape(-1, 1)

clf = linear_model.LinearRegression()
train_X2 = train_X.reshape(-1, 1)
clf.fit(train_X2, train_Y)

print(f'回帰係数={clf.coef_}')
print(f'切片={clf.intercept_}')
print(f'決定係数={clf.score(train_X2, train_Y)}')

plt.scatter(X, Y, label='data')
plt.plot(train_X, clf.predict(train_X2), color='green', label='train')
plt.plot(test_X, clf.predict(test_X2), color='red', label='test')
plt.legend()
plt.savefig('linear_regression2.png')
plt.show()
```

結果をグラフにしてみます。

![linear_regression2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1106967/15eb7035-1952-82a5-ef5c-8111ddc38898.png)

一次関数を求めようとしているので、結果は予想通りフィットしていません。

## 二次関数 - 多項式を使う

前の例をPolynomialFeaturesを使って二次関数として求めてみます。

```python
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn.preprocessing import PolynomialFeatures
import matplotlib.pyplot as plt

# Y = X^2 + 2X + 3を求める関数とする。
X = np.linspace(0, 10, num=50)
Y = X**2 + 2 * X + 3

train_X, test_X, train_Y, test_Y = train_test_split(X, Y, shuffle=False)
train_X2 = train_X.reshape(-1, 1)
test_X2 = test_X.reshape(-1, 1)

pf = PolynomialFeatures(degree=2, include_bias=False)
train_X2 = pf.fit_transform(train_X2)

lr = LinearRegression()
lr.fit(train_X2, train_Y)

test_X2 = pf.fit_transform(test_X2)

print(f'回帰係数={lr.coef_}')
print(f'切片={lr.intercept_}')
print(f'決定係数={lr.score(train_X2, train_Y)}')

plt.scatter(X, Y, label='data')
plt.plot(train_X, lr.predict(train_X2), color='green', label='train')
plt.plot(test_X, lr.predict(test_X2), color='red', label='test')
plt.legend()
plt.savefig('linear_regression3.png')
plt.show()
```
結果をグラフにしてみます。
![linear_regression3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1106967/b944148f-4de3-516f-ab14-02183da887ac.png)

フィットしました！

## 三角関数

次に三角関数で同じことをやってみます。
求める関数はsin関数です。
やる前から結果は見えているような気もしますが...

```python
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn.preprocessing import PolynomialFeatures
import matplotlib.pyplot as plt

# 三角関数 Y = sin(X)を求める。
X = np.linspace(0, 20, num=200)
Y = np.sin(X)

train_X, test_X, train_Y, test_Y = train_test_split(X, Y, shuffle=False)
train_X2 = train_X.reshape(-1, 1)
test_X2 = test_X.reshape(-1, 1)

pf = PolynomialFeatures(degree=2, include_bias=False)
train_X2 = pf.fit_transform(train_X2)

lr = LinearRegression()
lr.fit(train_X2, train_Y)

test_X2 = pf.fit_transform(test_X2)

print(f'回帰係数={lr.coef_}')
print(f'切片={lr.intercept_}')
print(f'決定係数={lr.score(train_X2, train_Y)}')

plt.scatter(X, Y, label='data')
plt.plot(train_X, lr.predict(train_X2), color='green', label='train')
plt.plot(test_X, lr.predict(test_X2), color='red', label='test')
plt.legend()
plt.savefig('linear_regression4.png')
plt.show()
```
結果をグラフにしてみます。

![linear_regression4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1106967/2c29a30c-5d89-88ae-2cd2-6f2497534999.png)

三角関数を二次関数として求めているので予想通りの結果です。
では何次関数ならフィットするのでしょうか？
2〜5次で試してみます。

```python
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn.preprocessing import PolynomialFeatures
import matplotlib.pyplot as plt

# 三角関数 Y = sin(X)を求める。
X = np.linspace(0, 20, num=200)
Y = np.sin(X)

train_X, test_X, train_Y, test_Y = train_test_split(X, Y, shuffle=False)

for degree in np.arange(2, 6):
    train_X2 = train_X.reshape(-1, 1)
    test_X2 = test_X.reshape(-1, 1)

    pf = PolynomialFeatures(degree=degree, include_bias=False)
    train_X2 = pf.fit_transform(train_X2)

    lr = LinearRegression()
    lr.fit(train_X2, train_Y)

    test_X2 = pf.fit_transform(test_X2)

    print(f'degree={degree}')
    print(f'  回帰係数={lr.coef_}')
    print(f'  切片={lr.intercept_}')
    print(f'  決定係数={lr.score(train_X2, train_Y)}')

    plt.plot(train_X, lr.predict(train_X2))
    plt.plot(test_X, lr.predict(test_X2), label=f'degree={degree}')

plt.scatter(X, Y, label='data', marker='.')
plt.legend()
plt.savefig('linear_regression5.png')
plt.show()
```
結果をグラフにしてみます。

![linear_regression5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1106967/39ac401e-d6d0-a918-6664-d8124486d479.png)

次数が多くなると発散していく感じがします。

# サポートベクターマシン

サポートベクターマシンを使って学習させてみます。

```python
import numpy as np
from sklearn import svm
from sklearn.model_selection import train_test_split
import matplotlib.pyplot as plt

# 三角関数 Y = sin(X)を求める。
X = np.linspace(0, 20, num=200)
Y = np.sin(X)

train_X, test_X, train_Y, test_Y = train_test_split(X, Y, shuffle=False)
train_X2 = train_X.reshape(-1, 1)
test_X2 = test_X.reshape(-1, 1)

regr = svm.SVR()
regr.fit(train_X2, train_Y)

plt.scatter(X, Y, label='data', marker='.')
plt.plot(train_X, regr.predict(train_X2), color='green', label='train')
plt.plot(test_X, regr.predict(test_X2), color='red', label='test')
plt.legend()
plt.savefig('svm_regression1.png')
plt.show()
```

結果をグラフにします。
![svm_regression1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1106967/cb5c3148-afb5-5a38-b59f-1e0c9f58d190.png)

n次関数の予想よりはだいぶ良くなりました。
トレーニングデータはいい感じですが、テストデータに関しては今ひとつです。