機械学習入門(演習)#


必要なライブラリのimportとデータのダウンロード#

以下のセルで演習に必要なライブラリのimportとデータをダウンロードしています.初めに実行してください.

import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline

from matplotlib import rcParams
rcParams['font.family'] = 'sans-serif'
rcParams['font.sans-serif'] = ['Hiragino Sans', 'Yu Gothic', 'Meirio', 'Takao', 'IPAexGothic', 'IPAPGothic', 'VL PGothic', 'Noto Sans CJK JP']
!mkdir -p data

!wget -P data https://raw.githubusercontent.com/ground-zero-programming/zero-pro-data/refs/heads/main/data/machine_learning/exercise/data_N.npy -O data/data_N.npy
!wget -P data https://raw.githubusercontent.com/ground-zero-programming/zero-pro-data/refs/heads/main/data/machine_learning/exercise/target_N.npy -O data/target_N.npy

!wget -P data https://raw.githubusercontent.com/ground-zero-programming/zero-pro-data/refs/heads/main/data/machine_learning/exercise/data_noise_scale.npy -O data/data_noise_scale.npy
!wget -P data https://raw.githubusercontent.com/ground-zero-programming/zero-pro-data/refs/heads/main/data/machine_learning/exercise/target_noise_scale.npy -O data/target_noise_scale.npy

!wget -P data https://raw.githubusercontent.com/ground-zero-programming/zero-pro-data/refs/heads/main/data/machine_learning/exercise/data_a.npy -O data/data_a.npy
!wget -P data https://raw.githubusercontent.com/ground-zero-programming/zero-pro-data/refs/heads/main/data/machine_learning/exercise/target_a.npy -O data/target_a.npy

!wget -P data https://raw.githubusercontent.com/ground-zero-programming/zero-pro-data/refs/heads/main/data/machine_learning/exercise/data_b.npy -O data/data_b.npy
!wget -P data https://raw.githubusercontent.com/ground-zero-programming/zero-pro-data/refs/heads/main/data/machine_learning/exercise/target_b.npy -O data/target_b.npy
--2025-12-11 15:27:47--  https://raw.githubusercontent.com/ground-zero-programming/zero-pro-data/refs/heads/main/data/machine_learning/exercise/data_N.npy
raw.githubusercontent.com (raw.githubusercontent.com) をDNSに問いあわせています... 185.199.109.133, 185.199.108.133, 185.199.111.133, ...
raw.githubusercontent.com (raw.githubusercontent.com)|185.199.109.133|:443 に接続しています... 接続しました。
HTTP による接続要求を送信しました、応答を待っています... 
200 OK
長さ: 208 [application/octet-stream]
`data/data_N.npy' に保存中


data_N.npy            0%[                    ]       0  --.-KB/s               
data_N.npy          100%[===================>]     208  --.-KB/s 時間 0s       

2025-12-11 15:27:47 (6.20 MB/s) - `data/data_N.npy' へ保存完了 [208/208]
--2025-12-11 15:27:47--  https://raw.githubusercontent.com/ground-zero-programming/zero-pro-data/refs/heads/main/data/machine_learning/exercise/target_N.npy
raw.githubusercontent.com (raw.githubusercontent.com) をDNSに問いあわせています... 185.199.109.133, 185.199.108.133, 185.199.111.133, ...
raw.githubusercontent.com (raw.githubusercontent.com)|185.199.109.133|:443 に接続しています... 接続しました。
HTTP による接続要求を送信しました、応答を待っています... 
200 OK
長さ: 208 [application/octet-stream]
`data/target_N.npy' に保存中


target_N.npy          0%[                    ]       0  --.-KB/s               
target_N.npy        100%[===================>]     208  --.-KB/s 時間 0s       

2025-12-11 15:27:48 (6.40 MB/s) - `data/target_N.npy' へ保存完了 [208/208]
--2025-12-11 15:27:48--  https://raw.githubusercontent.com/ground-zero-programming/zero-pro-data/refs/heads/main/data/machine_learning/exercise/data_noise_scale.npy
raw.githubusercontent.com (raw.githubusercontent.com) をDNSに問いあわせています... 185.199.109.133, 185.199.108.133, 185.199.111.133, ...
raw.githubusercontent.com (raw.githubusercontent.com)|185.199.109.133|:443 に接続しています... 接続しました。
HTTP による接続要求を送信しました、応答を待っています... 
200 OK
長さ: 368 [application/octet-stream]
`data/data_noise_scale.npy' に保存中


data_noise_scale.np   0%[                    ]       0  --.-KB/s               
data_noise_scale.np 100%[===================>]     368  --.-KB/s 時間 0s       

2025-12-11 15:27:48 (8.77 MB/s) - `data/data_noise_scale.npy' へ保存完了 [368/368]
--2025-12-11 15:27:48--  https://raw.githubusercontent.com/ground-zero-programming/zero-pro-data/refs/heads/main/data/machine_learning/exercise/target_noise_scale.npy
raw.githubusercontent.com (raw.githubusercontent.com) をDNSに問いあわせています... 185.199.109.133, 185.199.108.133, 185.199.111.133, ...
raw.githubusercontent.com (raw.githubusercontent.com)|185.199.109.133|:443 に接続しています... 接続しました。
HTTP による接続要求を送信しました、応答を待っています... 
200 OK
長さ: 368 [application/octet-stream]
`data/target_noise_scale.npy' に保存中


target_noise_scale.   0%[                    ]       0  --.-KB/s               
target_noise_scale. 100%[===================>]     368  --.-KB/s 時間 0s       

2025-12-11 15:27:49 (6.75 MB/s) - `data/target_noise_scale.npy' へ保存完了 [368/368]
--2025-12-11 15:27:49--  https://raw.githubusercontent.com/ground-zero-programming/zero-pro-data/refs/heads/main/data/machine_learning/exercise/data_a.npy
raw.githubusercontent.com (raw.githubusercontent.com) をDNSに問いあわせています... 185.199.109.133, 185.199.108.133, 185.199.111.133, ...
raw.githubusercontent.com (raw.githubusercontent.com)|185.199.109.133|:443 に接続しています... 接続しました。
HTTP による接続要求を送信しました、応答を待っています... 
200 OK
長さ: 368 [application/octet-stream]
`data/data_a.npy' に保存中


data_a.npy            0%[                    ]       0  --.-KB/s               
data_a.npy          100%[===================>]     368  --.-KB/s 時間 0s       

2025-12-11 15:27:49 (7.02 MB/s) - `data/data_a.npy' へ保存完了 [368/368]
--2025-12-11 15:27:49--  https://raw.githubusercontent.com/ground-zero-programming/zero-pro-data/refs/heads/main/data/machine_learning/exercise/target_a.npy
raw.githubusercontent.com (raw.githubusercontent.com) をDNSに問いあわせています... 185.199.109.133, 185.199.108.133, 185.199.111.133, ...
raw.githubusercontent.com (raw.githubusercontent.com)|185.199.109.133|:443 に接続しています... 接続しました。
HTTP による接続要求を送信しました、応答を待っています... 
200 OK
長さ: 368 [application/octet-stream]
`data/target_a.npy' に保存中


target_a.npy          0%[                    ]       0  --.-KB/s               
target_a.npy        100%[===================>]     368  --.-KB/s 時間 0s       

2025-12-11 15:27:49 (10.3 MB/s) - `data/target_a.npy' へ保存完了 [368/368]
--2025-12-11 15:27:50--  https://raw.githubusercontent.com/ground-zero-programming/zero-pro-data/refs/heads/main/data/machine_learning/exercise/data_b.npy
raw.githubusercontent.com (raw.githubusercontent.com) をDNSに問いあわせています... 185.199.109.133, 185.199.108.133, 185.199.111.133, ...
raw.githubusercontent.com (raw.githubusercontent.com)|185.199.109.133|:443 に接続しています... 接続しました。
HTTP による接続要求を送信しました、応答を待っています... 
200 OK
長さ: 368 [application/octet-stream]
`data/data_b.npy' に保存中


data_b.npy            0%[                    ]       0  --.-KB/s               
data_b.npy          100%[===================>]     368  --.-KB/s 時間 0s       

2025-12-11 15:27:50 (10.0 MB/s) - `data/data_b.npy' へ保存完了 [368/368]
--2025-12-11 15:27:50--  https://raw.githubusercontent.com/ground-zero-programming/zero-pro-data/refs/heads/main/data/machine_learning/exercise/target_b.npy
raw.githubusercontent.com (raw.githubusercontent.com) をDNSに問いあわせています... 185.199.109.133, 185.199.108.133, 185.199.111.133, ...
raw.githubusercontent.com (raw.githubusercontent.com)|185.199.109.133|:443 に接続しています... 接続しました。
HTTP による接続要求を送信しました、応答を待っています... 
200 OK
長さ: 368 [application/octet-stream]
`data/target_b.npy' に保存中


target_b.npy          0%[                    ]       0  --.-KB/s               
target_b.npy        100%[===================>]     368  --.-KB/s 時間 0s       

2025-12-11 15:27:50 (11.3 MB/s) - `data/target_b.npy' へ保存完了 [368/368]

演習1: 線形回帰#

演習1-1: データの読み込みと可視化#

以下に示すようにデータ数 N,ノイズの大きさ noise_scale,データを生成するときの関数の傾きと切片 abのパラメータを講義資料から変更したデータを用意した.

  1. データ数 N を変更したデータのパス

    • X: ‘data/data_N.npy’

    • y: ‘data/target_N.npy’

  2. ノイズの大きさ noise_scale を変更したデータのパス

    • X: ‘data/data_noise_scale.npy’

    • y: ‘data/target_noise_scale.npy’

  3. データを生成するときの関数の傾き a を変更したデータのパス

    • X: ‘data/data_a.npy’

    • y: ‘data/target_a.npy’

  4. データを生成するときの関数の切片 b を変更したデータのパス

    • X: ‘data/data_b.npy’

    • y: ‘data/target_b.npy’

どれか一つで良いので np.load関数を使って読み込み,読み込んだデータを可視化せよ.

# 解答例:originalの読み込み
X = np.load('data/data_original.npy')
y = np.load('data/target_original.npy')

plt.scatter(X, y, marker='x', label='観測されたデータ')
plt.title('データの可視化')
plt.xlabel('x') # x軸のラベルを追加
plt.ylabel('y') # y軸のラベルを追加
plt.legend()
---------------------------------------------------------------------------
FileNotFoundError                         Traceback (most recent call last)
Cell In[3], line 2
      1 # 解答例:originalの読み込み
----> 2 X = np.load('data/data_original.npy')
      3 y = np.load('data/target_original.npy')
      5 plt.scatter(X, y, marker='x', label='観測されたデータ')

File ~/Workspace/python-recurrent-public/.venv/lib/python3.13/site-packages/numpy/lib/_npyio_impl.py:454, in load(file, mmap_mode, allow_pickle, fix_imports, encoding, max_header_size)
    452     own_fid = False
    453 else:
--> 454     fid = stack.enter_context(open(os.fspath(file), "rb"))
    455     own_fid = True
    457 # Code to distinguish from NumPy binary files and pickles.

FileNotFoundError: [Errno 2] No such file or directory: 'data/data_original.npy'
# 解答例:データ数Nを変更したデータの読み込み
X = np.load('data/data_N.npy')
y = np.load('data/target_N.npy')

plt.scatter(X, y, marker='x', label='観測されたデータ')
plt.title('データの可視化')
plt.xlabel('x') # x軸のラベルを追加
plt.ylabel('y') # y軸のラベルを追加
plt.legend()
# 解答例:ノイズの変動量noise_scaleを変更したデータの読み込み
X = np.load('data/data_noise_scale.npy')
y = np.load('data/target_noise_scale.npy')

plt.scatter(X, y, marker='x', label='観測されたデータ')
plt.title('データの可視化')
plt.xlabel('x') # x軸のラベルを追加
plt.ylabel('y') # y軸のラベルを追加
plt.legend()
# 解答例:傾きaを変更したデータの読み込み
X = np.load('data/data_a.npy')
y = np.load('data/target_a.npy')

plt.scatter(X, y, marker='x', label='観測されたデータ')
plt.title('データの可視化')
plt.xlabel('x') # x軸のラベルを追加
plt.ylabel('y') # y軸のラベルを追加
plt.legend()
# 解答例:切片bを変更したデータの読み込み
X = np.load('data/data_b.npy')
y = np.load('data/target_b.npy')

plt.scatter(X, y, marker='x', label='観測されたデータ')
plt.title('データの可視化')
plt.xlabel('x') # x軸のラベルを追加
plt.ylabel('y') # y軸のラベルを追加
plt.legend()
# 参考:以下のコードは上記のデータを生成するときに利用した
import os

def make_data(N, a, b, noise_scale):
    X = np.linspace(0, 1, N) # xの値
    y_gt = a * X + b # y=ax+bの真の値
    y = a * X + b + noise_scale * np.random.randn(N) # 一定のノイズがのった観測データ
    return (X, y, y_gt)

names = ['original', 'N', 'a', 'b', 'noise_scale']
params = [[30, 2, 1, 0.1],
          [10, 2, 1, 0.1],
          [30, -2, 1, 0.1],
          [30, 2, -1, 0.1],
          [30, 2, 1, 1.0]]

os.makedirs('data', exist_ok=True)
for name, param in zip(names, params):
    N, a, b, noise_scale = param
    X, y, y_gt = make_data(N, a, b, noise_scale)
    X = X[:,np.newaxis]
    y = y[:,np.newaxis]
    y_gt = y_gt[:,np.newaxis]
    
    np.save(f'data/data_{name}.npy', X)
    np.save(f'data/target_{name}.npy', y)
    np.save(f'data/gt_{name}.npy', y_gt)

演習1-2: 線形回帰#

読み込んだデータを使って線形回帰を実行せよ.また得られた傾きと切片を元に結果を可視化せよ.

# 解答例:
from sklearn.linear_model import LinearRegression

reg = LinearRegression()
reg = reg.fit(X, y)

a = reg.coef_[0]
b = reg.intercept_
y_pred = a * X + b

plt.scatter(X, y, marker='x', label='観測されたデータ')
plt.plot(X, y_pred, c='g', label='線形回帰によって得られた関数')
plt.title('LinearRegressionの結果')
plt.xlabel('x') # x軸のラベルを追加
plt.ylabel('y') # y軸のラベルを追加
plt.legend()

発展演習1: Numpyの操作#

発展演習1-1: ベクトルの定義#

Numpyを用いて以下に示すベクトル \(\mathbf{a},\mathbf{b}\) を定義して.shapeでベクトルの形状を以下の目標出力に従って出力せよ.

\[\begin{split} \mathbf{a}=\begin{bmatrix} 1 \\ 2 \\ 3 \\ 4 \end{bmatrix}, \mathbf{b}=\begin{bmatrix} 5 \\ 6 \\ 7 \\ 8 \end{bmatrix} \end{split}\]

目標出力

a.shape: (4, 1), b.shape: (4, 1)
# 解答例
a = np.array([[1], [2], [3], [4]])
b = np.array([[5], [6], [7], [8]])
print(f'a.shape: {a.shape}, b.shape: {b.shape}')

発展演習1-2: ベクトルの内積#

定義したベクトル \(\mathbf{a},\mathbf{b}\) の内積 \(\mathbf{a}^\top \mathbf{b}\)Numpyを用いて計算せよ.

# 解答例
np.dot(a.T, b)

発展演習1-3: Numpyを用いない実装#

演習1-1,1-2をNumpyを用いずリストと繰り返し文のみを使って実装せよ.

# 解答例
a = [1, 2, 3, 4]
b = [5, 6, 7, 8]
result = 0
for i in range(4):
    result = result + a[i] * b[i]
print(result)

発展演習1-4: 行列の定義#

Numpyを用いて以下に示す行列 \(\mathbf{A},\mathbf{B}\) を定義し,.shapeで行列の形状を以下の目標出力に従って出力せよ.

\[\begin{split} \mathbf{A}=\begin{bmatrix} 1 & 2 & 3 \\ 4 & 5 & 6 \\ \end{bmatrix}, \mathbf{B}=\begin{bmatrix} 1 & 2 \\ 3 & 4 \\ 5 & 6 \\ \end{bmatrix} \end{split}\]

目標出力

A.shape: (2, 3), B.shape: (3, 2)
# 解答例
A = np.array([[1, 2, 3],
              [4, 5, 6]])
B = np.array([[1, 2],[3, 4], [5, 6]])

print(f'A.shape: {A.shape}, B.shape: {B.shape}')

発展演習1-5: 行列の積#

定義した行列 \(\mathbf{A},\mathbf{B}\) の積 \(\mathbf{A}\mathbf{B}\)Numpyを用いて計算せよ.

# 解答例
np.dot(A,B)

発展演習1-6: 固有値計算#

以下の行列 \(\mathbf{C}\) の固有値と固有ベクトルを計算せよ.ただし,Numpy, Sympy, Scipy,…など利用するライブラリや計算方法は自由で良い.講義中で固有値計算の話題に触れていないので各自利用するライブラリのリファレンス等を参考に取り組むこと.

\[\begin{split} \mathbf{C}=\begin{bmatrix} 3 & 0 \\ 1 & 2 \\ \end{bmatrix} \end{split}\]
# 解答例
C = np.array([[3, 0], [1, 2]])
eigenvalues, eigenvectors = np.linalg.eig(C)
print(f'eigenvalues={eigenvalues}')
print(f'eigenvectors={eigenvectors}')

発展演習2: 線形回帰#

講義で扱った線形回帰は \(y=ax+b\) という線形のモデルを仮定してデータを当てはめる.利用する入出力のペア \((x,y)\)\(y=ax+b\) ではなく二次関数 \(y=ax^2+bx+c\) から生成されるときどのような結果となるかPythonのプログラミングを通して検証せよ.ただし,パラメータN, noise_scale, a, b, cは自由に設定して良い.

# 解答例
from sklearn.linear_model import LinearRegression

N = 50
noise_scale = 1.0
a = 2
b = -1
c = 1

# データの生成用の関数
def make_data(N, noise_scale, a, b, c):
    x_data = np.linspace(-1, 3, N)
    y_gt = a * (x_data ** 2) + b * x_data + c
    y_data = a * (x_data ** 2) + b * x_data + c + noise_scale * np.random.randn(N)
    return (x_data, y_data, y_gt)

x_data, y_data, y_gt = make_data(N, noise_scale, a, b, c)

# 線形回帰の実行
X = x_data[:,np.newaxis]
y = y_data[:,np.newaxis]

reg = LinearRegression()
reg = reg.fit(X, y)

a = reg.coef_[0]
b = reg.intercept_
y_pred = a * x_data + b

plt.scatter(x_data, y_data, marker='x', label='観測されたデータ')
plt.plot(x_data, y_gt, c='r', linestyle='--', label='ノイズがない真の関係性')
plt.plot(x_data, y_pred, c='g', label='線形回帰によって得られた関数')
plt.title('LinearRegressionの結果')
plt.xlabel('x') # x軸のラベルを追加
plt.ylabel('y') # y軸のラベルを追加
plt.legend()