「数字のデータセット」について学ぶ(scikit-learn /トイデータセット)

2023年5月13日

この記事では、統計学を初めて学ぶ筆者が、「scikit-learn」の「トイデータセット」における「数字のデータセット」について学んだ内容について記載しています。

学習には、scikit-learnのガイド「7.1. Toy datasets」を参考にし、Pythonのプログラミングにも触れ、理解を深めました。

プログラミングには、機械学習ライブラリのscikit-learnを使用しました。

この記事は、他の人が参考にできるよう、わかりやすく書くことを心がけました。

scikit-learn トイデータセット

機械学習ライブラリscikit-learnに用意されている「トイデータセット」は、機械学習の問題を解くためのサンプルデータセットのことで、いくつかの種類が用意されています。例えば、Iris(アヤメ)の花の特徴から、その種類を分類する問題を解くための「irisデータセット」や、ボストン市の住宅価格に関するデータを用いて、住宅価格を予測する問題を解くための「bostonデータセット」などがあります。

scikit-learnにはいくつかの小さな標準データセットが付属しており、外部のウェブサイトからファイルをダウンロードする必要はありません。

これらは以下の関数を使って読み込むことができます。

load_boston() : load_boston は 1.0 で非推奨となり、1.2 で削除される予定である。

load_iris() : アヤメのデータセット(分類)をロードして返す。

load_diabetes() : 糖尿病のデータセット(回帰)をロードして返す。

load_linnerud() : 身体運動のデータセットをロードして返す。

load_digits() : 数字のデータセット(分類)をロードして返す。

load_wine() : ワインのデータセット(分類)をロードして返す。

load_breast_cancer() : ウィスコンシン州の乳がんのデータセット(分類)をロードして返す。7.1. Toy datasetsts

数字のデータセット

数字のデータセットは、機械学習のアルゴリズムを学習するために用いられる小規模のデータセットの1つで、手書き数字の画像とそれに対応する正解ラベルから構成されています。このデータセットは、1797枚の8×8ピクセルの画像から構成されており、各ピクセルは0から16のグレースケール値で表されます。各画像は、0から9までの数字のいずれかに対応しており、それに対応する正解ラベルが用意されています。このデータセットは、機械学習の教師あり学習の分類問題に適しています。

Pythonプログラミング

「のデータセット」をイメージしやすいようPythonでのプログラミングについても学びます。

プログラム

数字のデータセットを読み込み、データセットの詳細を出力します。

from sklearn.datasets import load_digits

# 数字のデータセットを読み込む
digits = load_digits()

# データセットの詳細を出力する
print("数字のデータセットの定義:")
print("----------------------------")
print("データセット名:", digits['DESCR'])
print("----------------------------")
print("特徴量の数:", digits['data'].shape[1])
print("----------------------------")
print("クラスの数:", len(digits['target_names']))
print("----------------------------")
print("データ数:", len(digits['data']))
print("----------------------------")
print("データの先頭5行:")
print(digits['data'][:5])
print("----------------------------")
print("クラスの先頭5行:")
print(digits['target'][:5])

実行結果

数字のデータセットの定義:
----------------------------
データセット名: .. _digits_dataset:

Optical recognition of handwritten digits dataset
--------------------------------------------------

**Data Set Characteristics:**

    :Number of Instances: 1797
    :Number of Attributes: 64
    :Attribute Information: 8x8 image of integer pixels in the range 0..16.
    :Missing Attribute Values: None
    :Creator: E. Alpaydin (alpaydin '@' boun.edu.tr)
    :Date: July; 1998

This is a copy of the test set of the UCI ML hand-written digits datasets
https://archive.ics.uci.edu/ml/datasets/Optical+Recognition+of+Handwritten+Digits

The data set contains images of hand-written digits: 10 classes where
each class refers to a digit.

Preprocessing programs made available by NIST were used to extract
normalized bitmaps of handwritten digits from a preprinted form. From a
total of 43 people, 30 contributed to the training set and different 13
to the test set. 32x32 bitmaps are divided into nonoverlapping blocks of
4x4 and the number of on pixels are counted in each block. This generates
an input matrix of 8x8 where each element is an integer in the range
0..16. This reduces dimensionality and gives invariance to small
distortions.

For info on NIST preprocessing routines, see M. D. Garris, J. L. Blue, G.
T. Candela, D. L. Dimmick, J. Geist, P. J. Grother, S. A. Janet, and C.
L. Wilson, NIST Form-Based Handprint Recognition System, NISTIR 5469,
1994.

.. topic:: References

  - C. Kaynak (1995) Methods of Combining Multiple Classifiers and Their
    Applications to Handwritten Digit Recognition, MSc Thesis, Institute of
    Graduate Studies in Science and Engineering, Bogazici University.
  - E. Alpaydin, C. Kaynak (1998) Cascading Classifiers, Kybernetika.
  - Ken Tang and Ponnuthurai N. Suganthan and Xi Yao and A. Kai Qin.
    Linear dimensionalityreduction using relevance weighted LDA. School of
    Electrical and Electronic Engineering Nanyang Technological University.
    2005.
  - Claudio Gentile. A New Approximate Maximal Margin Classification
    Algorithm. NIPS. 2000.

----------------------------
特徴量の数: 64
----------------------------
クラスの数: 10
----------------------------
データ数: 1797
----------------------------
データの先頭5行:
[[ 0.  0.  5. 13.  9.  1.  0.  0.  0.  0. 13. 15. 10. 15.  5.  0.  0.  3.
  15.  2.  0. 11.  8.  0.  0.  4. 12.  0.  0.  8.  8.  0.  0.  5.  8.  0.
   0.  9.  8.  0.  0.  4. 11.  0.  1. 12.  7.  0.  0.  2. 14.  5. 10. 12.
   0.  0.  0.  0.  6. 13. 10.  0.  0.  0.]
 [ 0.  0.  0. 12. 13.  5.  0.  0.  0.  0.  0. 11. 16.  9.  0.  0.  0.  0.
   3. 15. 16.  6.  0.  0.  0.  7. 15. 16. 16.  2.  0.  0.  0.  0.  1. 16.
  16.  3.  0.  0.  0.  0.  1. 16. 16.  6.  0.  0.  0.  0.  1. 16. 16.  6.
   0.  0.  0.  0.  0. 11. 16. 10.  0.  0.]
 [ 0.  0.  0.  4. 15. 12.  0.  0.  0.  0.  3. 16. 15. 14.  0.  0.  0.  0.
   8. 13.  8. 16.  0.  0.  0.  0.  1.  6. 15. 11.  0.  0.  0.  1.  8. 13.
  15.  1.  0.  0.  0.  9. 16. 16.  5.  0.  0.  0.  0.  3. 13. 16. 16. 11.
   5.  0.  0.  0.  0.  3. 11. 16.  9.  0.]
 [ 0.  0.  7. 15. 13.  1.  0.  0.  0.  8. 13.  6. 15.  4.  0.  0.  0.  2.
   1. 13. 13.  0.  0.  0.  0.  0.  2. 15. 11.  1.  0.  0.  0.  0.  0.  1.
  12. 12.  1.  0.  0.  0.  0.  0.  1. 10.  8.  0.  0.  0.  8.  4.  5. 14.
   9.  0.  0.  0.  7. 13. 13.  9.  0.  0.]
 [ 0.  0.  0.  1. 11.  0.  0.  0.  0.  0.  0.  7.  8.  0.  0.  0.  0.  0.
   1. 13.  6.  2.  2.  0.  0.  0.  7. 15.  0.  9.  8.  0.  0.  5. 16. 10.
   0. 16.  6.  0.  0.  4. 15. 16. 13. 16.  1.  0.  0.  0.  0.  3. 15. 10.
   0.  0.  0.  0.  0.  2. 16.  4.  0.  0.]]
----------------------------
クラスの先頭5行:
[0 1 2 3 4]

和訳します。(.. topic:: Referencesを除きます。)

数字のデータセットの定義:
----------------------------
データセット名: .. _digits_dataset:

手書き数字の光学的認識データセット

データセットの特徴:

:データの数: 1797
:属性の数: 64
:属性情報: 0から16までの整数ピクセルを持つ8x8の画像。
:欠損値: なし
:作成者: E. Alpaydin (alpaydin '@' boun.edu.tr)
:日付: 1998年7月

これはUCI ML手書き数字データセットのテストセットのコピーです。
https://archive.ics.uci.edu/ml/datasets/Optical+Recognition+of+Handwritten+Digits

このデータセットには、手書き数字の画像が含まれています。各クラスは1つの数字を表します。

NISTが提供する前処理プログラムを使用して、手書き数字の標準化されたビットマップが、事前に印刷されたフォームから抽出されました。43人中30人がトレーニングセットに貢献し、異なる13人がテストセットに貢献しました。32x32ビットマップは、4x4の重ならないブロックに分割され、各ブロックでオンになっているピクセルの数が数えられます。これにより、0から16までの整数が各要素の8x8の入力行列が生成されます。これにより、次元が減少し、小さな歪みに対して不変性が得られます。

NIST前処理ルーチンの情報については、M. D. Garris、J. L. Blue、G.
T. Candela、D. L. Dimmick、J. Geist、P. J. Grother、S. A. Janet、およびC。
L. Wilsonによる「NISTフォームベースの手書き文字認識システム」、NISTIR 5469、1994年を参照してください。

----------------------------
特徴量の数: 64
----------------------------
クラスの数: 10
----------------------------
データ数: 1797
----------------------------
データの先頭5行:
[[ 0.  0.  5. 13.  9.  1.  0.  0.  0.  0. 13. 15. 10. 15.  5.  0.  0.  3.
  15.  2.  0. 11.  8.  0.  0.  4. 12.  0.  0.  8.  8.  0.  0.  5.  8.  0.
   0.  9.  8.  0.  0.  4. 11.  0.  1. 12.  7.  0.  0.  2. 14.  5. 10. 12.
   0.  0.  0.  0.  6. 13. 10.  0.  0.  0.]
 [ 0.  0.  0. 12. 13.  5.  0.  0.  0.  0.  0. 11. 16.  9.  0.  0.  0.  0.
   3. 15. 16.  6.  0.  0.  0.  7. 15. 16. 16.  2.  0.  0.  0.  0.  1. 16.
  16.  3.  0.  0.  0.  0.  1. 16. 16.  6.  0.  0.  0.  0.  1. 16. 16.  6.
   0.  0.  0.  0.  0. 11. 16. 10.  0.  0.]
 [ 0.  0.  0.  4. 15. 12.  0.  0.  0.  0.  3. 16. 15. 14.  0.  0.  0.  0.
   8. 13.  8. 16.  0.  0.  0.  0.  1.  6. 15. 11.  0.  0.  0.  1.  8. 13.
  15.  1.  0.  0.  0.  9. 16. 16.  5.  0.  0.  0.  0.  3. 13. 16. 16. 11.
   5.  0.  0.  0.  0.  3. 11. 16.  9.  0.]
 [ 0.  0.  7. 15. 13.  1.  0.  0.  0.  8. 13.  6. 15.  4.  0.  0.  0.  2.
   1. 13. 13.  0.  0.  0.  0.  0.  2. 15. 11.  1.  0.  0.  0.  0.  0.  1.
  12. 12.  1.  0.  0.  0.  0.  0.  1. 10.  8.  0.  0.  0.  8.  4.  5. 14.
   9.  0.  0.  0.  7. 13. 13.  9.  0.  0.]
 [ 0.  0.  0.  1. 11.  0.  0.  0.  0.  0.  0.  7.  8.  0.  0.  0.  0.  0.
   1. 13.  6.  2.  2.  0.  0.  0.  7. 15.  0.  9.  8.  0.  0.  5. 16. 10.
   0. 16.  6.  0.  0.  4. 15. 16. 13. 16.  1.  0.  0.  0.  0.  3. 15. 10.
   0.  0.  0.  0.  0.  2. 16.  4.  0.  0.]]
----------------------------
クラスの先頭5行:
[0 1 2 3 4]

プログラムの説明

from sklearn.datasets import load_digits

scikit-learnのdatasetsモジュールから、load_digits関数をインポートします。これにより、数字データセットを読み込むことができます。

# 数字のデータセットを読み込む
digits = load_digits()

load_digits()関数を使って、数字データセットを読み込み、digitsという名前で保存します。

# データセットの詳細を出力する
print("数字のデータセットの定義:")
print("----------------------------")
print("データセット名:", digits['DESCR'])
print("----------------------------")
print("特徴量の数:", digits['data'].shape[1])
print("----------------------------")
print("クラスの数:", len(digits['target_names']))
print("----------------------------")
print("データ数:", len(digits['data']))
print("----------------------------")

print(“データセット名:", digits['DESCR’])は、数字のデータセットの詳細情報を出力します。

print(“特徴量の数:", digits['data’].shape[1])は、数字のデータセットの特徴量の数を出力します。

shapeはNumPy配列の属性の一つで、その配列の各次元の大きさをタプル形式で返します。タプルは、複数の要素をまとめて一つの値として扱うデータ型です。一方、[1]はPythonのリストやタプルに対するインデックス指定の方法です。
つまり、digits['data’].shape[1]は、digits['data’]配列の2次元目の大きさ(列の数)を返すことになります。この部分が実行されることで、digitsデータセットの特徴量の数が表示されます。

print(“クラスの数:", len(digits['target_names’]))は、数字のデータセットのクラスの数を出力します。

print(“データ数:", len(digits['data’]))は、数字のデータセットのクラスの数を出力します。

print(digits['data'][:5])
print("----------------------------")
print("クラスの先頭5行:")
print(digits['target'][:5])

print(digits['data’][:5])は、アヤメのデータセットの最初の5行を出力します。

digits['data’]は、アヤメのデータセットから取得したデータの行列を表します。各行が1つのデータポイントであり、各列が4つの特徴量の値を表します。digits['data’][:5]は、最初の5つの行を取得するためのPythonのスライスです。したがって、print(digits['data’][:5])は、最初の5つのデータポイントの特徴量の値を表示します。

print(digits['target’][:5])は、アヤメのデータセットのクラスの最初の5行を出力します。

digits['target’]は、アヤメのデータセットから取得したクラスラベルを表します。各クラスラベルは、各データポイントに対応しています。digits['target’][:5]は、最初の5つのクラスラベルを取得するためのPythonのスライスです。したがって、print(digits['target’][:5])は、最初の5つのデータポイントのクラスラベルを表示します。

データセットのサンプル

Pythonプログラミング

「数字のデータセットのサンプル」をイメージしやすいようPythonでのプログラミングについても学びます。

プログラム

数字のデータセットを読み込み、最初の10個のサンプルを表示するプログラムです。

import matplotlib.pyplot as plt
from sklearn.datasets import load_digits

# データセットを読み込む
digits = load_digits()

# 最初の10個のサンプルを表示する
fig, axes = plt.subplots(2, 5, figsize=(8, 4))
for ax, image, label in zip(axes.flat, digits.images, digits.target):
    ax.imshow(image, cmap='gray_r', interpolation='nearest')
    ax.set_title(f"Label: {label}")
    ax.set_xticks([])
    ax.set_yticks([])
plt.show()

実行結果

プログラムの説明

import matplotlib.pyplot as plt
from sklearn.datasets import load_digits

必要なライブラリであるmatplotlibとscikit-learnのデータセット読み込みモジュールをそれぞれimportしています。

# データセットを読み込む
digits = load_digits()

digitsデータセットをload_digits()関数を用いて読み込んでいます。digitsデータセットは、0から9までの手書き数字の画像が8×8ピクセルのグレースケール画像として保存されたもので、特徴量として64個のピクセル値が含まれています。また、target属性には、各画像が表す数字が含まれています。

# 最初の10個のサンプルを表示する
fig, axes = plt.subplots(2, 5, figsize=(8, 4))

10個の画像を表示するために、2×5のサブプロットを作成しています。引数figsizeは、作成される図のサイズをインチ単位で指定しています。

for ax, image, label in zip(axes.flat, digits.images, digits.target):

zip()関数を用いて、axesのフラットなリスト、digits.images、digits.targetをそれぞれimage, labelとしてforループで回しています。

この部分は、3つの異なる配列 axes.flat, digits.images, digits.target のそれぞれの要素を結合し、各ループの繰り返しで1つずつ要素を返します。 zip() 関数は、複数の配列をまとめ、各配列の同じインデックスの要素をタプルとして返します。タプルは、複数の要素をまとめて一つの値として扱うデータ型です。このループでは、各タプルを3つの変数 ax, image, label に分割しています。

axes.flat は、2次元の配列 axes (2×5のサブプロット)を1次元のフラットな配列に変換するために使用されます。これは、axes 配列の要素を左上から右下まで順番に並べたものです。digits.images は、画像のピクセル値(8×8の各ピクセルの0から16のグレースケール値)を含む2次元配列のリストであり、 digits.target は、画像に対するラベル(0〜9)の配列です。

したがって、このループは axes.flat, digits.images, digits.target の各要素を1つずつ取り、ax, image, label の3つの変数にそれぞれ代入しています。ループの本体で、各変数を使用して、 ax に image のグレースケール画像を表示し、 label を画像のタイトルに設定しています。

    ax.imshow(image, cmap='gray_r', interpolation='nearest')
    ax.set_title(f"Label: {label}")
    ax.set_xticks([])
    ax.set_yticks([])

matplotlibを使ってデジタル画像を表示します。numpy配列で表された画像をmatplotlibのimshow関数を使ってグレースケール画像として表示します。imshow関数の第一引数には、表示する画像のデータが入った配列を指定し、cmap引数にはグレースケールのカラーマップを指定します。ここでは 'gray_r’ を指定しています。’gray_r’は、反転したグレースケールのカラーマップを表します。

interpolation引数には、画像の拡大縮小時に使われる補間法を指定することができます。’nearest’を指定すると、最も近い画素の値を使って補間されます。最も近い画素の値を使うため、画素数が変わっても画素の位置は変わらないという特徴があります。これを近傍補間法(最近傍補間法)といいます。

axに画像のタイトルを設定しています。f文字列を用いて、表示される数字のラベル(0〜9)を表示しています。

axに表示されるx軸とy軸の目盛りを削除しています。


plt.show()

plt.show()関数を用いて、グラフを表示しています。

データセットの分布

Pythonプログラミング

「数字のデータセットの分布」をイメージしやすいようPythonでのプログラミングについても学びます。

プログラム

数字のデータセットの各特徴量(8×8ピクセルの画像の各ピクセルにおける0から16のグレースケール値)について、0から9までの数字の分布をそれぞれヒストグラムで表示します。

from sklearn.datasets import load_digits
import matplotlib.pyplot as plt

# 数字のデータセットをロードする
digits = load_digits()

# 各特徴量ごとにヒストグラムを描画する
for i in range(digits.data.shape[1]):
    plt.hist(digits.data[digits.target==0, i], alpha=0.5, label="0", bins=17, range=(0,16))
    plt.hist(digits.data[digits.target==1, i], alpha=0.5, label="1", bins=17, range=(0,16))
    plt.hist(digits.data[digits.target==2, i], alpha=0.5, label="2", bins=17, range=(0,16))
    plt.hist(digits.data[digits.target==3, i], alpha=0.5, label="3", bins=17, range=(0,16))
    plt.hist(digits.data[digits.target==4, i], alpha=0.5, label="4", bins=17, range=(0,16))
    plt.hist(digits.data[digits.target==5, i], alpha=0.5, label="5", bins=17, range=(0,16))
    plt.hist(digits.data[digits.target==6, i], alpha=0.5, label="6", bins=17, range=(0,16))
    plt.hist(digits.data[digits.target==7, i], alpha=0.5, label="7", bins=17, range=(0,16))
    plt.hist(digits.data[digits.target==8, i], alpha=0.5, label="8", bins=17, range=(0,16))
    plt.hist(digits.data[digits.target==9, i], alpha=0.5, label="9", bins=17, range=(0,16))
    plt.xlabel(f"Feature {i}")
    plt.ylabel("Number of samples")
    plt.legend(loc="best")
    plt.show()

実行結果

Feature 3〜60までは省略します。

プログラムの説明

from sklearn.datasets import load_digits
import matplotlib.pyplot as plt

scikit-learnライブラリからload_digits関数をインポートします。

Matplotlibのpyplotモジュールをインポートし、pltという名前で呼び出します。

# 数字のデータセットをロードする
digits = load_digits()

scikit-learnのdatasetsモジュールから、load_digits関数をインポートします。これにより、digitsデータセットを読み込むことができます。

# 各特徴量ごとにヒストグラムを描画する
for i in range(digits.data.shape[1]):

digitsデータセットの特徴量の数だけループを回します。

    plt.hist(digits.data[digits.target==0, i], alpha=0.5, label="0", bins=17, range=(0,16))

target(0から9までの数字)が0のデータから特徴量i(8×8ピクセルの画像の各ピクセル)の値(0から16のグレースケール値)を抽出し、ヒストグラムを描画します。alpha引数は透明度、label引数は凡例、bins引数はビンの数、range引数は描画範囲を指定する。

    plt.hist(digits.data[digits.target==1, i], alpha=0.5, label="1", bins=17, range=(0,16))
    plt.hist(digits.data[digits.target==2, i], alpha=0.5, label="2", bins=17, range=(0,16))
    plt.hist(digits.data[digits.target==3, i], alpha=0.5, label="3", bins=17, range=(0,16))
    plt.hist(digits.data[digits.target==4, i], alpha=0.5, label="4", bins=17, range=(0,16))
    plt.hist(digits.data[digits.target==5, i], alpha=0.5, label="5", bins=17, range=(0,16))
    plt.hist(digits.data[digits.target==6, i], alpha=0.5, label="6", bins=17, range=(0,16))
    plt.hist(digits.data[digits.target==7, i], alpha=0.5, label="7", bins=17, range=(0,16))
    plt.hist(digits.data[digits.target==8, i], alpha=0.5, label="8", bins=17, range=(0,16))
    plt.hist(digits.data[digits.target==9, i], alpha=0.5, label="9", bins=17, range=(0,16))

target(0から9までの数字)が1〜16のデータについて同様にヒストグラムを描画します。

    plt.xlabel(f"Feature {i}")
    plt.ylabel("Number of samples")
    plt.legend(loc="best")
    plt.show()

plt.xlabel(f"Feature {i}") はx軸ラベルを"Feature i"に設定します。iは特徴量の番号を表します。
plt.ylabel(“Number of samples") はy軸ラベルを"Number of samples"に設定します。
plt.legend(loc="best") は凡例をグラフの最適な位置に表示します。
plt.show() は描画したヒストグラムを表示します。ループを回しているため、特徴量ごとに複数のヒストグラムが表示されます。