Skip to content

4. 機械学習の基礎

本章では、機械学習の基礎について学びます。これまでに学んだ Python の文法やデータ可視化の技術を活用しながら、機械学習における基本的な考え方や実践的な流れを理解していきましょう。

4.1 機械学習の種類

4.1.1 機械学習の定義

機械学習(Machine Learning) とは、コンピュータがデータから自動的にパターンやルールを学習し、予測や判断を行う技術です。従来のプログラミングでは、人間が明示的にルールを記述する必要がありましたが、機械学習では、データから自動的にルールを見つけ出すことができます。

graph LR
    A("入力データ") --> C("プログラム<br/>ルール")
    B("人間が記述した<br/>ルール") --> C
    C --> D("出力結果")

    classDef data fill:#D9EAF3,stroke:#0072B2,stroke-width:2px,color:#000
    classDef proc fill:#D9F0EA,stroke:#009E73,stroke-width:2px,color:#000
    classDef out fill:#F5ECE2,stroke:#BF8040,stroke-width:2px,color:#000
    classDef hl fill:#F9E7D9,stroke:#D55E00,stroke-width:2px,color:#000
    class A data
    class B hl
    class C proc
    class D out

例: 「気温が 30 度以上なら "暑い"、20 度以上 30 度未満なら "快適"、20 度未満なら "寒い" と判定する」というルールを人間が明示的に記述する。

graph LR
    A("入力データ") --> C("学習アルゴリズム")
    B("出力結果<br/>教師データ") --> C
    C --> D("プログラム<br/>学習済みモデル")

    classDef data fill:#D9EAF3,stroke:#0072B2,stroke-width:2px,color:#000
    classDef proc fill:#D9F0EA,stroke:#009E73,stroke-width:2px,color:#000
    classDef model fill:#F7EBF2,stroke:#CC79A7,stroke-width:2px,color:#000
    class A,B data
    class C proc
    class D model

例: 過去の気温データと快適度のデータを大量に与えることで、コンピュータが自動的に判定ルールを学習する。

4.1.2 機械学習の応用例

機械学習は、私たちの身の回りのさまざまな場面で活用されています。

  • 画像認識: 顔認識、物体検出、医療画像診断
  • 自然言語処理: 機械翻訳、文章生成、感情分析
  • 音声認識: 音声アシスタント、文字起こし
  • 推薦システム: 動画配信サービスの推薦、EC サイトの商品推薦
  • 異常検知: 不正取引の検出、製造業における品質管理
  • 予測: 株価予測、需要予測、天気予報

機械学習と AI の関係

人工知能(AI: Artificial Intelligence) は、人間の知的活動をコンピュータで実現する技術全般を指します。機械学習は AI を実現するための手法の一つであり、近年の AI ブームを支える重要な技術となっています。

4.1.3 機械学習の 3 つの分類

機械学習は、学習方法の違いによって大きく 3 つに分類されます。

graph LR
    A("機械学習") --> B("教師あり学習")
    A --> C("教師なし学習")
    A --> D("強化学習")

    B --> B1("分類<br/>(例:スパムメール判定)")
    B --> B2("回帰<br/>(例:住宅価格予測)")

    C --> C1("クラスタリング<br/>(例:顧客セグメント)")
    C --> C2("次元削減<br/>(例:高次元データの可視化)")

    D --> D1("ゲームAI")
    D --> D2("ロボット制御")

    classDef data fill:#D9EAF3,stroke:#0072B2,stroke-width:2px,color:#000
    classDef proc fill:#D9F0EA,stroke:#009E73,stroke-width:2px,color:#000
    classDef hl fill:#F9E7D9,stroke:#D55E00,stroke-width:2px,color:#000
    classDef neu fill:#F2F2F2,stroke:#8C8C8C,stroke-width:2px,color:#000
    class A neu
    class B,B1,B2 data
    class C,C1,C2 proc
    class D,D1,D2 hl
学習方法 説明 例
教師あり学習 正解ラベル付きのデータから学習 スパムメール判定、住宅価格予測
教師なし学習 正解ラベルなしのデータから学習 データのグループ分け、異常検知
強化学習 試行錯誤を通じて最適な行動を学習 ゲーム AI、ロボット制御
  • 教師あり学習(Supervised Learning): 入力データとそれに対応する正解ラベル(教師データ)のペアから学習を行う手法です。大量の「問題と答え」のセットを与えることで、モデルは入力から出力を予測するための規則性を学びます。
  • 教師なし学習(Unsupervised Learning): 正解ラベルのないデータからパターンや構造を発見する手法です。データの中に隠された規則性を自動的に見つけ出すことが目的です。
  • 強化学習(Reinforcement Learning): エージェントが環境と相互作用しながら、試行錯誤を通じて報酬を最大化する行動を学習する手法です。教師あり学習や教師なし学習とは異なる枠組みであり、本テキストでは詳しく扱いません。

本テキストでは、機械学習の中でも最も基本的で応用範囲の広い 教師あり学習 を中心に学んでいきます。

4.2 教師あり学習

4.2.1 教師あり学習とは

教師あり学習(Supervised Learning) とは、入力データとそれに対応する正解ラベル(教師データ)のペアから学習を行う手法です。機械学習モデルは、入力と出力の関係性を学習し、新しい入力データに対して出力を予測できるようになります。

教師あり学習は、解決したい問題の種類によって、さらに 2 つに分類されます。

分類(Classification)

分類 は、入力データをあらかじめ定義されたカテゴリ(クラス)に分類する問題です。出力は 離散値(カテゴリラベル)となります。

graph LR
    A("入力データ<br/>メールの内容") --> B("分類モデル")
    B --> C("スパム")
    B --> D("通常メール")

    classDef data fill:#D9EAF3,stroke:#0072B2,stroke-width:2px,color:#000
    classDef model fill:#F7EBF2,stroke:#CC79A7,stroke-width:2px,color:#000
    classDef out fill:#F5ECE2,stroke:#BF8040,stroke-width:2px,color:#000
    class A data
    class B model
    class C,D out

例

  • メールがスパムかどうかを判定する(2 クラス分類)
  • 手書き数字を 0〜9 に分類する(10 クラス分類)
  • アヤメの品種を分類する(3 クラス分類)

回帰(Regression)

回帰 は、入力データから連続的な数値を予測する問題です。出力は 連続値 となります。

graph LR
    A("入力データ<br/>面積, 築年数, 駅距離") --> B("回帰モデル")
    B --> C("価格: 4500万円")

    classDef data fill:#D9EAF3,stroke:#0072B2,stroke-width:2px,color:#000
    classDef model fill:#F7EBF2,stroke:#CC79A7,stroke-width:2px,color:#000
    classDef out fill:#F5ECE2,stroke:#BF8040,stroke-width:2px,color:#000
    class A data
    class B model
    class C out

例

  • 住宅の面積や築年数から価格を予測する
  • 気温や湿度から電力消費量を予測する
  • 勉強時間から試験の点数を予測する

分類と回帰の見分け方

予測したい値が「カテゴリ」なら分類、「数値」なら回帰と考えると分かりやすいです。

  • 「この花は何という品種ですか?」 → 分類
  • 「この家の価格はいくらですか?」 → 回帰

4.2.2 特徴量とラベル

教師あり学習では、以下の 2 つの要素が重要になります。

  • 特徴量(Feature): 予測に使用する入力データ。説明変数とも呼ばれる
  • ラベル(Label): 予測したい出力データ。目的変数とも呼ばれる

例: 住宅価格予測の場合

面積(㎡) 築年数(年) 駅からの距離(分) 価格(万円)
80 5 10 4500
60 15 5 3200
100 2 15 5800
  • 特徴量: 面積、築年数、駅からの距離
  • ラベル: 価格

機械学習モデルは、特徴量からラベルを予測する関係性を学習します。

なお、複数の特徴量をまとめて 1 つの ベクトル(数値の並び)として扱うと、1 件のデータを空間上の 1 点として表現できます(たとえば上の表の 1 行目は \((80, 5, 10)\) という数値の組で表せます)。この見方は、本テキストのさまざまな場面で登場します。

4.2.3 学習と予測

教師あり学習のプロセスは、大きく「学習」と「予測」の 2 つのフェーズに分けられます。

学習(Training)

学習フェーズでは、訓練データ(Training Data)を用いてモデルのパラメータを調整します。モデルは、特徴量とラベルの関係性を学習し、予測能力を獲得します。

graph LR
    A("訓練データ") --> B("特徴量")
    A --> C("ラベル")
    B --> D("モデルの学習")
    C --> D
    D --> E("学習済みモデル")

    classDef data fill:#D9EAF3,stroke:#0072B2,stroke-width:2px,color:#000
    classDef proc fill:#D9F0EA,stroke:#009E73,stroke-width:2px,color:#000
    classDef model fill:#F7EBF2,stroke:#CC79A7,stroke-width:2px,color:#000
    class A,B,C data
    class D proc
    class E model

予測(Prediction)

予測フェーズでは、学習済みモデルを使って、新しい入力データに対する出力を予測します。

graph LR
    A("新しいデータ<br/>特徴量のみ") --> B("学習済みモデル")
    B --> C("予測結果<br/>ラベル")

    classDef data fill:#D9EAF3,stroke:#0072B2,stroke-width:2px,color:#000
    classDef model fill:#F7EBF2,stroke:#CC79A7,stroke-width:2px,color:#000
    classDef out fill:#F5ECE2,stroke:#BF8040,stroke-width:2px,color:#000
    class A data
    class B model
    class C out

重要な注意点

学習に使ったデータと同じデータで予測を行っても、モデルの真の性能は評価できません。未知のデータに対してどれだけ正確に予測できるかが重要です。これについては次のセクションで詳しく説明します。

4.2.4 データ分割の重要性

なぜデータを分割するのか

機械学習モデルの目的は、未知のデータに対して正確な予測を行うこと です。学習に使用したデータに対して高い精度が出ても、新しいデータに対して予測できなければ意味がありません。

このような状態を 過学習(Overfitting) と呼びます。過学習は、モデルが訓練データを「暗記」してしまい、一般的なパターンを学習できていない状態です。

過学習が起きていないかを確かめ、モデルの真の性能を評価するために、データを複数のセットに分割します。

訓練データとテストデータ

最も基本的なデータ分割は、データを 訓練データ(Training Data) と テストデータ(Test Data) の 2 つに分ける方法です。

  • 訓練データ: モデルの学習に使用するデータ
  • テストデータ: モデルの性能を評価するために使用するデータ(学習には使わない)
graph TB
    A("全データ<br/>100%") --> B("訓練データ<br/>70-80%")
    A --> C("テストデータ<br/>20-30%")

    B --> D("モデルの学習に使用")
    C --> E("モデルの評価に使用")

    classDef data fill:#D9EAF3,stroke:#0072B2,stroke-width:2px,color:#000
    classDef proc fill:#D9F0EA,stroke:#009E73,stroke-width:2px,color:#000
    classDef neu fill:#F2F2F2,stroke:#8C8C8C,stroke-width:2px,color:#000
    class A neu
    class B,D data
    class C,E proc

データ分割の比率

訓練データとテストデータの分割比率は、一般的に 7:3 や 8:2 が使われます。データ量が少ない場合は訓練データの割合を増やし、データ量が十分にある場合はテストデータの割合を増やすこともあります。

検証データ

より洗練された機械学習プロジェクトでは、データを 3 つに分割することがあります。

  • 訓練データ(Training Data): モデルの学習に使用
  • 検証データ(Validation Data): モデルの調整・選択に使用
  • テストデータ(Test Data): 最終的な性能評価に使用
graph TB
    A("全データ<br/>100%") --> B("訓練データ<br/>60-70%")
    A --> C("検証データ<br/>10-20%")
    A --> D("テストデータ<br/>10-20%")

    B --> E("モデルの学習")
    C --> F("ハイパーパラメータの調整")
    D --> G("最終評価")

    classDef data fill:#D9EAF3,stroke:#0072B2,stroke-width:2px,color:#000
    classDef proc fill:#D9F0EA,stroke:#009E73,stroke-width:2px,color:#000
    classDef model fill:#F7EBF2,stroke:#CC79A7,stroke-width:2px,color:#000
    classDef neu fill:#F2F2F2,stroke:#8C8C8C,stroke-width:2px,color:#000
    class A neu
    class B,E data
    class C,F proc
    class D,G model

検証データは、モデルのハイパーパラメータ(学習の設定値)を調整する際に使用します。検証データで性能を確認しながらモデルを改善し、最後にテストデータで最終的な性能を評価します。

データ分割の重要性

データを適切に分割しないと、モデルの真の性能を正しく評価できません。特に、テストデータは一度も学習に使用してはいけません。「試験問題を見ながら勉強する」ようなものになってしまい、正しい評価ができなくなります。

4.3 教師なし学習

教師なし学習は、正解ラベルが存在しないデータからパターンや構造を発見する手法です。ここでは、代表的な手法であるクラスタリングと次元削減を紹介します。

詳細は第 9 章で

本節では教師なし学習の概観のみを扱います。クラスタリングのアルゴリズムやクラスタ数の選び方、次元削減の具体的な実装は、第 9 章で詳しく学びます。

4.3.1 クラスタリング

クラスタリング(Clustering) は、データを類似度に基づいてグループ(クラスタ)に分割する手法です。正解ラベルがなくても、データの中に自然に存在するグループ構造を発見できます。

最も代表的なクラスタリング手法が k-means 法 です。ここでは scikit-learn を使って、Iris データセットのラベルを使わずに 3 つのクラスタに分割できることを確認します。本来クラスタリングではクラスタ数を事前に知ることはできませんが、ここでは Iris が 3 品種であるとわかっているため、クラスタ数を \(k=3\) として実行します。

from sklearn.cluster import KMeans
import seaborn as sns
import numpy as np

# データの読み込み(seaborn 版 iris。ラベルは使わない)
df = sns.load_dataset('iris')
X = df[['sepal_length', 'sepal_width',
        'petal_length', 'petal_width']].values

# k-means法によるクラスタリング(3クラスタ)
kmeans = KMeans(n_clusters=3, random_state=42, n_init=10)
kmeans.fit(X)

# クラスタのラベルを取得
labels = kmeans.labels_
print(f"各クラスタのデータ数: {np.bincount(labels)}")
各クラスタのデータ数: [62 50 38]

ラベルを与えなくても、特徴の似たデータどうしがグループ化される点が、教師なし学習の特徴です(ただし、クラスタ数 \(k=3\) は指定した値です)。k-means 法のアルゴリズムの詳細やクラスタ数 \(k\) の選び方は、第 9 章で詳しく学びます。

4.3.2 次元削減

次元削減(Dimensionality Reduction) は、データの特徴量の数を減らす手法です。高次元のデータを低次元に圧縮することで、可視化やノイズの除去、計算コストの削減に役立ちます。

最も代表的な次元削減手法が PCA(Principal Component Analysis、主成分分析) です。データの分散が最大となる方向(主成分)を見つけ、その方向にデータを射影します。具体的な実装(Iris データセットの 4 次元から 2 次元への削減、寄与率の確認、可視化)は、第 9 章の「次元削減」の節で詳しく扱います。

4.4 学習と予測の流れ

4.4.1 機械学習の典型的なワークフロー

機械学習プロジェクトは、一般的に以下のような流れで進みます。

graph TB
    A("1. データの収集") --> B("2. データの理解・可視化")
    B --> C("3. データの分割")
    C --> D("4. データの前処理")
    D --> E("5. モデルの選択")
    E --> F("6. モデルの学習<br/>訓練データを使用")
    F --> G("7. モデルの評価<br/>検証データ・交差検証を使用")
    G --> H{性能は<br/>十分か?}
    H -->|No| D
    H -->|Yes| T("最終テストで評価")
    T --> I("9. モデルのデプロイ<br/>実運用")

    classDef data fill:#D9EAF3,stroke:#0072B2,stroke-width:2px,color:#000
    classDef proc fill:#D9F0EA,stroke:#009E73,stroke-width:2px,color:#000
    classDef model fill:#F7EBF2,stroke:#CC79A7,stroke-width:2px,color:#000
    classDef out fill:#F5ECE2,stroke:#BF8040,stroke-width:2px,color:#000
    class A data
    class B,C,D proc
    class E,F model
    class G,H,T,I out

各ステップについて、簡単に説明します。

1. データの収集

機械学習の第一歩は、問題を解決するためのデータを収集することです。データは CSV ファイル、データベース、API、Web スクレイピングなど、さまざまな方法で取得できます。

2. データの理解・可視化

収集したデータの構造や特性を理解するために、統計量の計算やグラフの作成を行います(前章までに学んだ可視化技術が活躍します)。

3. データの分割

最終評価用のテストデータを先に取り分けます。残りのデータで訓練・検証を行います(交差検証を使う方法もあります)。

4. データの前処理

欠損値補完や標準化など、データから値を決める処理は訓練データだけで fit() メソッドで学習し、検証・テストデータには transform() メソッドのみを適用します。交差検証でも各分割の訓練部分で前処理を学習します。詳しくは第5章のパイプラインで扱います。

5. モデルの選択

解決したい問題に適した機械学習アルゴリズムを選択します(線形回帰、決定木、ニューラルネットワークなど)。

6. モデルの学習

訓練データを使ってモデルを学習させます。

7. モデルの評価

検証データまたは交差検証を使ってモデルの性能を評価します。精度、再現率、平均二乗誤差などの評価指標を用います。

8. モデルの改善

検証結果を見て前処理やモデルの設定を調整します。設定を決めたら、取り分けておいたテストデータで最後に一度だけ評価します。

9. モデルのデプロイ

満足のいく性能が得られたら、モデルを実際のサービスやアプリケーションに組み込んで運用します。

4.4.2 Python による実装の基本パターン

Python の機械学習ライブラリ scikit-learn を使った基本的な実装パターンは以下のようになります(詳細は次章以降で学びます)。

# ライブラリのインポート
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error

# 1. データの準備(X: 特徴量, y: ラベル)
X = [[面積1, 築年数1], [面積2, 築年数2], ...]
y = [価格1, 価格2, ...]

# 2. データの分割
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)

# 3. モデルの作成
model = LinearRegression()

# 4. モデルの学習
model.fit(X_train, y_train)

# 5. モデルの予測
y_pred = model.predict(X_test)

# 6. モデルの評価
score = mean_squared_error(y_test, y_pred)
print(f"誤差: {score}")

このパターンは、ほとんどの教師あり学習で共通しています。線形回帰をはじめとする回帰アルゴリズムの詳細は、第 6 章で詳しく学びます。

4.5 scikit-learn の基本

scikit-learn(サイキット・ラーン)は、Python で最も広く使われている機械学習ライブラリです。

scikit-learn 公式サイト

scikit-learn の公式ドキュメントには、豊富なチュートリアルやAPIリファレンスが用意されています。

4.5.1 NumPy の基礎知識

機械学習では、NumPy(Numerical Python)ライブラリを頻繁に使用します。NumPy は数値計算を高速に行うための配列操作ライブラリです。scikit-learn を使う準備として、まず NumPy の基本を押さえておきましょう。

NumPy 配列の作成

NumPy の中心となるデータ構造は、ndarray(N-dimensional array) と呼ばれる多次元配列です。

import numpy as np

# 1次元配列(ベクトル)の作成
x = np.array([1, 2, 3, 4, 5])
print(x)  # [1 2 3 4 5]
print(f"形状: {x.shape}")  # (5,)
print(f"次元数: {x.ndim}")  # 1

# 2次元配列(行列)の作成
X = np.array([[1, 2, 3],
              [4, 5, 6],
              [7, 8, 9]])
print(X)
print(f"形状: {X.shape}")  # (3, 3)
print(f"次元数: {X.ndim}")  # 2

配列の形状変換

機械学習では、データの形状を適切に変換する必要があります。

import numpy as np

# 1次元配列を2次元配列に変換
x = np.array([1, 2, 3, 4, 5])
X = x.reshape(-1, 1)  # (-1, 1) は「行数は自動、列数は1」
print(X)
# [[1]
#  [2]
#  [3]
#  [4]
#  [5]]
print(f"形状: {X.shape}")  # (5, 1)

# reshape(-1, 1) の意味
# -1: その次元のサイズを自動計算
# 1: 列数を1に固定

なぜ reshape が必要か

scikit-learn の多くのモデルは、特徴量として2次元配列を期待します。

  • 1次元配列: [1, 2, 3, 4, 5] → shape が (5,) → エラーになる
  • 2次元配列: [[1], [2], [3], [4], [5]] → shape が (5, 1) → 正しく動作

つまり、reshape(-1, 1) で「1つの特徴量を持つデータ」として正しく認識されます。

便利な配列生成関数

import numpy as np

# 連続した値を生成
arr1 = np.arange(0, 10, 2)  # 0から10未満まで、2刻み
print(arr1)  # [0 2 4 6 8]

# 等間隔の値を生成
arr2 = np.linspace(0, 1, 5)  # 0から1まで、5等分
print(arr2)  # [0.   0.25 0.5  0.75 1.  ]

# ゼロ配列
zeros = np.zeros((3, 4))  # 3行4列のゼロ配列
print(zeros)

# 乱数配列
np.random.seed(42)  # 再現性のため
random_data = np.random.rand(5, 3)  # 5行3列の乱数(0〜1)
print(random_data)

配列の演算

NumPy 配列は、要素ごとの演算が簡単に行えます。

import numpy as np

x = np.array([1, 2, 3, 4, 5])

# スカラーとの演算
print(x + 10)  # [11 12 13 14 15]
print(x * 2)   # [ 2  4  6  8 10]

# 配列同士の演算(要素ごと)
y = np.array([10, 20, 30, 40, 50])
print(x + y)   # [11 22 33 44 55]
print(x * y)   # [ 10  40  90 160 250]

# 統計関数
print(f"平均: {x.mean()}")     # 3.0
print(f"合計: {x.sum()}")      # 15
print(f"最大値: {x.max()}")    # 5
print(f"最小値: {x.min()}")    # 1
print(f"標準偏差: {x.std()}")  # 1.41...

NumPy の速度

NumPyの配列演算は、Pythonのループより効率よく実行できる場合が多く、数値データの形状や計算を統一して扱えます。以降の機械学習コードでもNumPy配列を使用します。

4.5.2 scikit-learn の設計思想

scikit-learn は、一貫した API 設計が特徴です。データから学習するオブジェクトを 推定器(Estimator) と呼び、多くの教師あり学習モデルは以下のパターンで使えます。

from sklearn.モジュール名 import モデル名

# 1. モデルの作成
model = モデル名()

# 2. モデルの学習
model.fit(X_train, y_train)

# 3. モデルの予測
y_pred = model.predict(X_test)

# 4. モデルの評価
score = model.score(X_test, y_test)

このパターンは、線形回帰や決定木など、多くの教師あり学習モデルに共通しています。一方、前処理では transform() メソッド、クラスタリングでは fit_predict() メソッドを使う場合があるなど、推定器の種類によって利用するメソッドは異なります。

4.5.3 fit / predict / transform

scikit-learn の API は、3 つの基本メソッドで構成されています。

  • fit(X, y): モデルの学習を行う。教師あり学習では特徴量 X とラベル y を与え、教師なし学習では X のみを与える
  • predict(X): 学習済みモデルを使って予測を行う。分類ではクラスラベル、回帰では数値を返す
  • transform(X): データの変換を行う。前処理(標準化など)や次元削減(PCA など)で使用する

fit_transform(X) は fit(X) と transform(X) を連続して実行するメソッドで、前処理の場面でよく使われます。

from sklearn.preprocessing import StandardScaler
import numpy as np

X = np.array([[1, 100], [2, 200],
              [3, 300], [4, 400]])

# StandardScaler: 平均0、分散1に標準化する
scaler = StandardScaler()

# fit_transform で学習と変換を同時に行う
X_scaled = scaler.fit_transform(X)
print(X_scaled)
[[-1.34164079 -1.34164079]
 [-0.4472136  -0.4472136 ]
 [ 0.4472136   0.4472136 ]
 [ 1.34164079  1.34164079]]

4.5.4 主要なモジュール

scikit-learn は機能ごとにモジュールが分かれています。

graph LR
    A("scikit-learn") --> B("linear_model<br/>線形モデル")
    A --> C("tree<br/>決定木")
    A --> D("ensemble<br/>アンサンブル学習")
    A --> E("model_selection<br/>モデル選択・評価")
    A --> F("preprocessing<br/>前処理")
    A --> G("metrics<br/>評価指標")

    B --> B1("LinearRegression<br/>線形回帰")
    B --> B2("LogisticRegression<br/>ロジスティック回帰")

    E --> E1("train_test_split<br/>データ分割")
    E --> E2("cross_val_score<br/>交差検証")

    F --> F1("StandardScaler<br/>標準化")
    F --> F2("MinMaxScaler<br/>正規化")

    G --> G1("accuracy_score<br/>精度")
    G --> G2("mean_squared_error<br/>MSE")

    classDef data fill:#D9EAF3,stroke:#0072B2,stroke-width:2px,color:#000
    classDef proc fill:#D9F0EA,stroke:#009E73,stroke-width:2px,color:#000
    classDef model fill:#F7EBF2,stroke:#CC79A7,stroke-width:2px,color:#000
    classDef out fill:#F5ECE2,stroke:#BF8040,stroke-width:2px,color:#000
    classDef hl fill:#F9E7D9,stroke:#D55E00,stroke-width:2px,color:#000
    classDef neu fill:#F2F2F2,stroke:#8C8C8C,stroke-width:2px,color:#000
    class A neu
    class B,B1,B2,G,G1,G2 data
    class C proc
    class D model
    class E,E1,E2 out
    class F,F1,F2 hl

4.5.5 LinearRegression の詳細

線形回帰モデル LinearRegression クラスの主要な属性とメソッドを理解しましょう(線形回帰アルゴリズム自体の詳細は、第 6 章で詳しく学びます)。

from sklearn.linear_model import LinearRegression
import numpy as np

# データの準備
X = np.array([[1], [2], [3], [4], [5]])
y = np.array([2, 4, 6, 8, 10])

# モデルの作成と学習
model = LinearRegression()
model.fit(X, y)

# 学習したパラメータの確認
print(f"係数(傾き): {model.coef_}")         # [2.]
print(f"切片: {model.intercept_}")           # 0.0

# 予測
X_new = np.array([[6], [7]])
y_pred = model.predict(X_new)
print(f"予測値: {y_pred}")                   # [12. 14.]

# スコア(R²)の計算
score = model.score(X, y)
print(f"R²スコア: {score}")                  # 1.0(完璧なフィット)

重要な属性とメソッド

属性(学習後に利用可能)

メソッド

4.5.6 train_test_split の詳細

データ分割を行う train_test_split() 関数の使い方を詳しく見てみましょう。

from sklearn.model_selection import train_test_split
import numpy as np

# サンプルデータ
X = np.array([[1], [2], [3], [4], [5], [6], [7], [8], [9], [10]])
y = np.array([2, 4, 6, 8, 10, 12, 14, 16, 18, 20])

# 基本的な使い方
X_train, X_test, y_train, y_test = train_test_split(
    X, y,
    test_size=0.2,      # テストデータの割合(20%)
    random_state=42     # 乱数シード(再現性のため)
)

print(f"訓練データ数: {len(X_train)}")  # 8
print(f"テストデータ数: {len(X_test)}")  # 2

# test_size のいろいろな指定方法
# test_size=0.2    → 20% をテストデータに
# test_size=0.3    → 30% をテストデータに
# test_size=2      → 2サンプルをテストデータに(整数指定も可能)

# シャッフルの制御
X_train, X_test, y_train, y_test = train_test_split(
    X, y,
    test_size=0.2,
    shuffle=True,       # シャッフルする(デフォルト)
    random_state=42
)

# シャッフルしない場合(時系列データなど)
X_train, X_test, y_train, y_test = train_test_split(
    X, y,
    test_size=0.2,
    shuffle=False       # シャッフルしない
)

random_state の重要性

random_state を指定しないと、実行するたびに異なるデータ分割になります。

  • 指定する場合: 再現性が保たれる(デバッグや比較に便利)
  • 指定しない場合: 毎回異なる分割(実験の頑健性を確認する場合に有用)

講義や演習では random_state=42 を指定することが多いです。

4.5.7 よく使う評価指標

from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score
import numpy as np

# 実際の値と予測値
y_true = np.array([3, -0.5, 2, 7])
y_pred = np.array([2.5, 0.0, 2, 8])

# MSE(平均二乗誤差)
mse = mean_squared_error(y_true, y_pred)
print(f"MSE: {mse:.4f}")  # 0.375

# RMSE(平均二乗平方根誤差)
rmse = np.sqrt(mse)
print(f"RMSE: {rmse:.4f}")  # 0.6124

# MAE(平均絶対誤差)
mae = mean_absolute_error(y_true, y_pred)
print(f"MAE: {mae:.4f}")  # 0.5

# R²スコア(決定係数)
r2 = r2_score(y_true, y_pred)
print(f"R²: {r2:.4f}")  # 0.9486

4.6 演習問題

演習 4-1: NumPy 配列の作成と統計量

演習 4-1

以下のテンプレートコードを完成させて、次の処理を行ってください。

  1. np.arange() 関数を使って、10 から 100 まで(100 を含まない)10 刻みの 1 次元配列 x を作成する
  2. x の 形状(shape) を表示する
  3. x の 平均値、最大値、標準偏差 をそれぞれ表示する
  4. x を scikit-learn に渡せるよう、形状 (9, 1) の 2 次元配列 X に変換し、X の形状を表示する
テンプレートコード
import numpy as np

# 1. 10 から 100 まで(100 を含まない)10 刻みの配列を作成
x = ___

# 2. 形状を表示
print(f"x の形状: ___")

# 3. 平均・最大・標準偏差
print(f"平均: ___")
print(f"最大値: ___")
print(f"標準偏差: ___")

# 4. 2 次元配列に変換
X = ___
print(f"X の形状: ___")
解答例
import numpy as np

# 1. 10 から 100 まで(100 を含まない)10 刻みの配列を作成
x = np.arange(10, 100, 10)

# 2. 形状を表示
print(f"x の形状: {x.shape}")

# 3. 平均・最大・標準偏差
print(f"平均: {x.mean()}")
print(f"最大値: {x.max()}")
print(f"標準偏差: {x.std():.2f}")

# 4. 2 次元配列に変換
X = x.reshape(-1, 1)
print(f"X の形状: {X.shape}")
x の形状: (9,)
平均: 50.0
最大値: 90
標準偏差: 25.82
X の形状: (9, 1)

考察:np.arange(start, stop, step) は stop を含まないので、10 から 90 までの 9 要素になります。平均や標準偏差は x.mean() のように配列のメソッドで求められます。reshape(-1, 1) の -1 は「要素数から自動で決める」という意味です。これで scikit-learn が特徴量に求める(サンプル数, 特徴量数)の 2 次元配列になります。

演習 4-2: 単回帰モデルで売上を予測する

演習 4-2

あるアイスクリーム店の「最高気温」と「1 日の売上個数」のデータが以下のように得られました。線形回帰モデルを学習させ、「気温が 32℃ のときの売上個数」を予測してください。

また、学習されたモデルの「傾き」と「切片」を表示し、訓練データと回帰直線を散布図でプロットしてください。

気温(℃) 売上(個)
22 45
24 52
26 61
28 70
30 78
テンプレートコード
import numpy as np
import matplotlib.pyplot as plt
from sklearn.linear_model import LinearRegression

# データ
X = np.array([22, 24, 26, 28, 30]).reshape(-1, 1)
y = np.array([45, 52, 61, 70, 78])

# 1. モデルの作成と学習

# 2. 傾きと切片の表示

# 3. 気温 32 度のときの売上を予測

# 4. 散布図と回帰直線の可視化
解答例
import numpy as np
import matplotlib.pyplot as plt
from sklearn.linear_model import LinearRegression

# データ
X = np.array([22, 24, 26, 28, 30]).reshape(-1, 1)
y = np.array([45, 52, 61, 70, 78])

# 1. モデルの作成と学習
model = LinearRegression()
model.fit(X, y)

# 2. 傾きと切片の表示
print(f"傾き: {model.coef_[0]:.2f}")
print(f"切片: {model.intercept_:.2f}")

# 3. 気温 32 度のときの売上を予測
pred = model.predict([[32]])
print(f"気温 32℃ のときの予測売上: {pred[0]:.1f} 個")

# 4. 散布図と回帰直線の可視化
plt.scatter(X, y, label="訓練データ")
plt.plot(X, model.predict(X), color="red", label="回帰直線")
plt.xlabel("気温(℃)")
plt.ylabel("売上(個)")
plt.legend()
plt.show()
傾き: 4.20
切片: -48.00
気温 32℃ のときの予測売上: 86.4 個

実行すると、ほぼ一直線に並んだ 5 つの訓練データの散布図と、その傾向をとらえた回帰直線が表示されます。

考察:傾き 4.20 は、気温が 1℃ 上がると売上が約 4.2 個増えることを表します。切片 −48.00 は、データのない 0℃ まで直線を延ばしたときの値で、実際の売上としての意味はありません。予測は訓練データに近い 20〜30℃ 台で使います。model.coef_ 属性は配列なので [0] で取り出します。予測したいデータも [[32]] のように 2 次元配列で渡します。

演習 4-3: データ分割と性能評価

演習 4-3

ある商品について、12 週分の週ごとの「広告費(万円)」と「売上(万円)」を記録したところ、以下のデータが得られました。

このデータを「訓練データ 75%、テストデータ 25%」に分割し、訓練データで線形回帰モデルを学習させた後、テストデータに対する予測を行い、RMSE(入力 4.4 と同じく mean_squared_error() 関数の平方根)を計算して表示してください。random_state は 42 を指定すること。特徴量は reshape(-1, 1) で 1 列の 2 次元配列にします。

さらに、test_size を 0.2、0.3、0.5 と変えて同じ評価を行い、テストデータの割合を大きくすると、訓練に使えるデータ数と評価の安定性がどう変わるかも考察してください。発展として、random_state を変えて複数回試し、RMSE がどの程度ばらつくかも調べてみましょう。

ad_cost = [2, 3, 5, 6, 7, 8, 10, 12, 14, 15, 18, 20]     # 広告費(万円)
sales   = [40, 50, 55, 62, 65, 68, 72, 78, 82, 85, 90, 95]  # 売上(万円)
テンプレートコード
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error

ad_cost = [2, 3, 5, 6, 7, 8, 10, 12, 14, 15, 18, 20]
sales   = [40, 50, 55, 62, 65, 68, 72, 78, 82, 85, 90, 95]

# 1. NumPy 配列に変換し、X は reshape(-1, 1) で 2 次元に整形

# 2. 訓練データとテストデータに分割(テスト 25%, random_state=42)

# 3. モデルの作成と学習

# 4. テストデータで予測

# 5. RMSE を計算して表示
解答例
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error

ad_cost = [2, 3, 5, 6, 7, 8, 10, 12, 14, 15, 18, 20]
sales   = [40, 50, 55, 62, 65, 68, 72, 78, 82, 85, 90, 95]

# 1. NumPy 配列に変換し、X は reshape(-1, 1) で 2 次元に整形
X = np.array(ad_cost).reshape(-1, 1)
y = np.array(sales)

# 2. 訓練データとテストデータに分割(テスト 25%, random_state=42)
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.25, random_state=42
)

# 3. モデルの作成と学習
model = LinearRegression()
model.fit(X_train, y_train)

# 4. テストデータで予測
y_pred = model.predict(X_test)

# 5. RMSE を計算して表示
rmse = np.sqrt(mean_squared_error(y_test, y_pred))
print(f"RMSE: {rmse:.2f}")
RMSE: 5.98

続いて、test_size を変えながら同じ評価を繰り返します。

for ts in [0.2, 0.3, 0.5]:
    X_train, X_test, y_train, y_test = train_test_split(
        X, y, test_size=ts, random_state=42
    )
    model = LinearRegression()
    model.fit(X_train, y_train)
    y_pred = model.predict(X_test)
    rmse = np.sqrt(mean_squared_error(y_test, y_pred))
    print(f"test_size={ts}: 訓練 {len(X_train)} 件, "
          f"テスト {len(X_test)} 件, RMSE {rmse:.2f}")
test_size=0.2: 訓練 9 件, テスト 3 件, RMSE 5.98
test_size=0.3: 訓練 8 件, テスト 4 件, RMSE 5.19
test_size=0.5: 訓練 6 件, テスト 6 件, RMSE 4.73

発展として、random_state を変えて評価のばらつきを見ます。

for rs in [0, 1, 2, 3, 4]:
    X_train, X_test, y_train, y_test = train_test_split(
        X, y, test_size=0.25, random_state=rs
    )
    model = LinearRegression()
    model.fit(X_train, y_train)
    y_pred = model.predict(X_test)
    rmse = np.sqrt(mean_squared_error(y_test, y_pred))
    print(f"random_state={rs}: RMSE {rmse:.2f}")
random_state=0: RMSE 3.66
random_state=1: RMSE 3.34
random_state=2: RMSE 3.59
random_state=3: RMSE 3.54
random_state=4: RMSE 3.95

考察:学習は訓練データだけで行い、評価はテストデータで行います。RMSE 5.98 は売上と同じ単位(万円)なので、予測がおよそ 6 万円ずれると読めます。test_size を大きくするとテストの件数が増えて評価は安定しますが、訓練に使えるデータは減ります。今回は全体が 12 件しかないので、test_size=0.2 でもテストは 0.25 と同じ 3 件です。random_state を変えるだけでも、RMSE は 3.34〜5.98 の範囲で動きます。データが少ないときは、第 5 章で学ぶ交差検証で評価を安定させます。

演習 4-4: fit・predict・transform の役割

演習 4-4

次の 3 つのメソッドについて、それぞれの役割と使う場面を自分の言葉で説明してください。

  1. fit() メソッド
  2. predict() メソッド
  3. transform() メソッド

また、テストデータに対して fit_transform() メソッドを使ってはいけない理由を説明してください。

解答例
  1. fit():モデルの「学習」を行うメソッドです。教師あり学習では特徴量 X とラベル y を与えてモデルのパラメータ(回帰係数など)を求め、前処理では標準化に使う平均や標準偏差といった統計量をデータから計算します。「データから何かを覚える」段階です。

  2. predict():学習済みモデルを使って「予測」を行うメソッドです。分類ではクラスラベル、回帰では数値を返します。fit() メソッドで覚えた内容を新しいデータに適用する段階です。

  3. transform():データの「変換」を行うメソッドです。標準化(StandardScaler クラス)や次元削減(PCA)などで、fit() メソッドで計算した統計量を使ってデータを変換します。

テストデータに fit_transform() メソッドを使ってはいけない理由:fit_transform() メソッドはそのデータから統計量を計算し直してから変換します。テストデータに対して使うと、テストデータの平均や標準偏差で変換されてしまい、(1) 訓練データと異なる基準で変換されるため予測が正しく機能しなくなり、(2) 本来「未知」であるはずのテストデータの情報がモデル構築の過程に漏れ込む(データリーケージ)ことになります。テストデータには、訓練データで fit() メソッドで学習した変換器の transform() メソッドのみを適用します。

演習 4-5: 共通 API の体験

演習 4-5

scikit-learn のモデルは共通の API(Estimator インタフェース)を持つため、モデルの差し替えが容易です。以下の線形回帰のコード(面積・築年数から住宅価格を予測する例)で、LinearRegression クラスを Ridge クラス(from sklearn.linear_model import Ridge)に差し替えても、fit() メソッドと predict() メソッドがそのまま動作することを確認してください。

テンプレートコード
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error

# データの準備(X: 特徴量 [面積, 築年数], y: ラベル [価格])
X = [[80, 5], [60, 15], [100, 2], [75, 8],
     [90, 3], [50, 20], [110, 1], [65, 12]]
y = [4500, 3200, 5800, 4200, 5100, 2800, 6200, 3500]

X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42
)

model = LinearRegression()
model.fit(X_train, y_train)
y_pred = model.predict(X_test)

rmse = np.sqrt(mean_squared_error(y_test, y_pred))
print(f"誤差(RMSE): {rmse:.1f}")
解答例
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.linear_model import Ridge
from sklearn.metrics import mean_squared_error

# データの準備(入力4.4の住宅価格予測と同じ)
X = [[80, 5], [60, 15], [100, 2], [75, 8],
     [90, 3], [50, 20], [110, 1], [65, 12]]
y = [4500, 3200, 5800, 4200, 5100, 2800, 6200, 3500]

X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42
)

# LinearRegression を Ridge に差し替えるだけで、そのまま動く
model = Ridge()
model.fit(X_train, y_train)
y_pred = model.predict(X_test)

rmse = np.sqrt(mean_squared_error(y_test, y_pred))
print(f"誤差(RMSE): {rmse:.1f}")
誤差(RMSE): 236.3

考察:書き換えたのは import 文とモデルを作る行の2か所だけで、学習・予測・評価のコードはそのまま動きます。scikit-learn のモデルが共通のインタフェース(Estimator インタフェース)を持っているためです。RMSE は LinearRegression クラスのときの約245.7から236.3に変わりました。Ridge クラスは、係数が大きくなりすぎないように制約(正則化)を加えた線形回帰だからです。正則化は第6章で扱います。

発展課題 1: クラスタ数を変えた k-means 法

発展課題 1

本文 4.3.1 節の Iris データセットのクラスタリング例で、n_clusters を 2、3、4 に変えて実行し、np.bincount() 関数で各クラスタのデータ数を確認してください。クラスタ数によって分かれ方がどう変わるか観察してください。

テンプレートコード
from sklearn.cluster import KMeans
import seaborn as sns
import numpy as np

# データの読み込み(ラベルは使わない)
df = sns.load_dataset("iris")
X = df[["sepal_length", "sepal_width",
        "petal_length", "petal_width"]].values

# n_clusters を 2, 3, 4 と変えてクラスタリングし、
# np.bincount() で各クラスタのデータ数を表示する
解答例
from sklearn.cluster import KMeans
import seaborn as sns
import numpy as np

# データの読み込み(ラベルは使わない)
df = sns.load_dataset("iris")
X = df[["sepal_length", "sepal_width",
        "petal_length", "petal_width"]].values

# n_clusters を変えてクラスタリング
for k in [2, 3, 4]:
    kmeans = KMeans(n_clusters=k, random_state=42, n_init=10)
    kmeans.fit(X)
    counts = np.bincount(kmeans.labels_)
    print(f"n_clusters={k}: 各クラスタのデータ数 {counts}")
n_clusters=2: 各クラスタのデータ数 [97 53]
n_clusters=3: 各クラスタのデータ数 [62 50 38]
n_clusters=4: 各クラスタのデータ数 [40 50 28 32]

考察:n_clusters=2 では、ほかと離れている setosa を中心とする53件と、versicolor と virginica をまとめた97件に分かれます。n_clusters=3 では、3品種におおよそ対応します。n_clusters=4 では、境界のあいまいな versicolor と virginica のあたりがさらに分けられます。k-means法は指定した数のクラスタを必ず作るので、クラスタ数は自分で決める必要があります。決め方は第9章のエルボー法とシルエット分析で学びます。

発展課題 2: 人工データで回帰モデルを評価する

発展課題 2

以下の手順で人工データを生成し、線形回帰の挙動を確認してください。

  1. np.random.seed(0) で乱数シードを固定する
  2. np.linspace(0, 10, 50) で 0 から 10 までの等間隔な値 50 個を生成し、特徴量 X(形状 (50, 1))を作る
  3. 真の関係を \(y = 3x + 5\) とし、これに np.random.normal(0, 2, 50) で生成したノイズを加えてラベル y を作る
  4. データを「訓練 80%、テスト 20%」(random_state=0)に分割する
  5. 線形回帰モデルを学習させ、学習された「傾き」と「切片」を表示する(真の値 3, 5 にどの程度近いか確認)
  6. テストデータでの「R² スコア」を表示する
  7. 訓練データ(青)、テストデータ(緑)、学習した回帰直線(赤)を 1 つの散布図で可視化する
テンプレートコード
import numpy as np
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn.metrics import r2_score

# 1. 乱数シードを固定

# 2. X を生成(形状 (50, 1))

# 3. y を生成(真の関係 y = 3x + 5 にノイズを加える)

# 4. 訓練・テストに分割

# 5. モデルの学習と傾き・切片の表示

# 6. R² スコアを表示

# 7. 可視化
解答例
import numpy as np
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn.metrics import r2_score

# 1. 乱数シードを固定
np.random.seed(0)

# 2. X を生成(形状 (50, 1))
X = np.linspace(0, 10, 50).reshape(-1, 1)

# 3. y を生成(真の関係 y = 3x + 5 にノイズを加える)
noise = np.random.normal(0, 2, 50)
y = 3 * X.flatten() + 5 + noise

# 4. 訓練・テストに分割
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=0
)

# 5. モデルの学習と傾き・切片の表示
model = LinearRegression()
model.fit(X_train, y_train)
print(f"傾き: {model.coef_[0]:.3f}(真の値 3)")
print(f"切片: {model.intercept_:.3f}(真の値 5)")

# 6. R² スコアを表示
y_pred = model.predict(X_test)
print(f"R² スコア: {r2_score(y_test, y_pred):.4f}")

# 7. 可視化
plt.scatter(X_train, y_train, color="blue", label="訓練データ")
plt.scatter(X_test, y_test, color="green", label="テストデータ")
x_line = np.linspace(0, 10, 100).reshape(-1, 1)
plt.plot(x_line, model.predict(x_line), color="red", label="回帰直線")
plt.xlabel("x")
plt.ylabel("y")
plt.legend()
plt.show()
傾き: 2.775(真の値 3)
切片: 6.248(真の値 5)
R² スコア: 0.9354

実行すると、青い訓練データと緑のテストデータが、赤い回帰直線の周りに散らばるグラフが表示されます。

考察:np.random.normal(0, 2, 50) は、平均 0、標準偏差 2 の正規分布からノイズを 50 個作ります。ノイズがあっても、傾き 2.775 と切片 6.248 は真の値(3 と 5)に近くなりました。テストの R² も 0.9354 と高い値です。y を作るときは X.flatten() メソッドで 1 次元に戻します。戻さないと y は (50, 50) の 2 次元配列になってしまいます。

4.7 まとめ

第 4 章のまとめ

機械学習の基本概念

  • 機械学習は、データからパターンを自動的に学習する技術
  • 教師あり学習、教師なし学習、強化学習の 3 種類がある

教師あり学習

  • 正解ラベル付きのデータから学習する手法
  • 分類問題と回帰問題の 2 つに大別される
  • 特徴量(入力)からラベル(出力)を予測する

データ分割の重要性

  • 訓練データでモデルを学習し、テストデータで評価する
  • データを適切に分割しないと、モデルの真の性能を評価できない
  • 過学習を見抜くために、未知のデータで評価することが重要

教師なし学習

  • 正解ラベルのないデータからパターンや構造を発見する手法
  • クラスタリング(k-means 法)や次元削減(PCA)が代表的
  • アルゴリズムの詳細は第 9 章で学ぶ

機械学習のワークフロー

  • データ収集 → 理解・可視化 → 分割 → 訓練側で前処理を学習 → モデル学習 → 検証・調整 → 最終テスト
  • scikit-learn を使った実装パターンは共通している

NumPy の基礎

  • NumPy は数値計算を高速に行うための配列操作ライブラリ
  • reshape(-1, 1) で1次元配列を2次元配列に変換できる
  • 要素ごとの演算が簡単に行える

scikit-learn の基礎

  • 一貫したAPI設計(fit, predict, transform, score)
  • LinearRegression クラスで線形回帰モデルを作成
  • train_test_split() 関数でデータを分割
  • 各種評価指標(MSE, RMSE, MAE, R²)を計算できる