scikit-learn

【scikit-learn】k近傍法(k-NN)を用いたデータ分類方法

【scikit-learn】k近傍法(k-NN)を用いたデータ分類方法
naoki-hn

Python の機械学習ライブラリである scikit-learn の KNeighborsClassifier を使って k 近傍法 (k-NN) によるデータ分類を行う方法を解説します。

k 近傍法(k-NN)

k 近傍法 (k-NN) とは、分類の手法の 1 つです。分類の中では非常に単純なアルゴリズムにであり、他のアルゴリズムのように識別関数、識別モデル、生成モデルのようなものを学習するわけではないため、機械学習の中でも怠惰学習と呼ばれたりします。

k 近傍法の概要を見てみましょう。k-NN は、k-Nearest Neighbors という名の通り、分類したい対象データから k 個の近傍のデータ点を見つけて多数決によって分類するクラスを決めます。近傍を求める際の距離尺度としては、一般的には距離はユークリッド距離が使用されます。距離尺度には他にもマンハッタン距離やマハラノビス距離といったものがあります。

k 近傍法の例を少し見てみましょう。以下のようなデータで黄色のデータ点が青なのか緑なのかを分類したいとしましょう。k=3 とすると、青 : 1、緑 : 2 となるので分類結果は緑となります。しかし、k=8 とすると青 : 5、緑 : 3 となるため青に分類されます。このようにいくつの近傍数を見るかによって分類結果は変わってきます。

k 近傍法 (k-NN) k=3
k 近傍法 (k-NN) k=8

k 近傍法は、Python の機械学習ライブラリである scikit-learn にて KNeighborsClassifier で実装がされています。この記事では、scikit-learn の KNeighborsClassifier を使って k 近傍法によるデータ分類する方法を紹介します。

KNeighborsClassifier を使って
k 近傍法によるデータ分類をする方法

以降では、scikit-learn を使用します。インストールがされていない場合は pip でインストールしておいてください。

pip install scikit-learn

k 近傍法の使い方(sklearn.neighbors.KNeighborsClassifier

実装例

scikit-learn の make_classification で生成したデータを使って、k 近傍法を実現する KNeighborsClassifier の使い方を紹介します。k 近傍法は、近傍数をいくつにするかで結果が変わるのでそれも比較してみようと思います。

import matplotlib.pyplot as plt
import numpy as np
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier


def main():
    """メイン関数"""
    np.random.seed(1)

    # ===== データの用意
    data, label = make_classification(
        n_samples=1000,
        n_classes=2,
        n_features=4,
        n_informative=4,
        n_redundant=0,
    )
    # データセットを訓練用、テスト用に分割する
    train_data, test_data, train_label, test_label = train_test_split(data, label)

    # ===== 複数のkで性能が分類性能がどのように変わるか確認
    k_list = [k for k in range(1, 11)]
    acc_list = []

    # ===== kを変えながらモデルを順番に学習
    for k in k_list:
        # モデルの構築
        model = KNeighborsClassifier(n_neighbors=k)
        # モデルの学習
        model.fit(train_data, train_label)
        # 正解率の評価
        acc_list.append(model.score(test_data, test_label))

    # ===== 正解率をプロットする
    plt.plot(k_list, acc_list)
    plt.title("accuracy list")
    plt.xlabel("n_neighbors")
    plt.ylabel("accuracy")
    plt.show()


if __name__ == "__main__":
    main()
k近傍法 (k-NN) 正解率

実装内容の解説

上記で紹介した実装例の各部分ごとに内容を紹介していきます。

必要モジュールのインポート

import matplotlib.pyplot as plt
import numpy as np
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier

必要なモジュール類をインポートします。今回は scikit-learn の KNeighborsClassifier を使用するので、sklearn.neighbors からインポートします。またデータ生成用に make_classification、データ分割のために train_test_split をインポートしています。NumPy と Matplotlib はデータの操作や可視化用です。

データセットの準備

    np.random.seed(1)

    # ===== データの用意
    data, label = make_classification(
        n_samples=1000,
        n_classes=2,
        n_features=4,
        n_informative=4,
        n_redundant=0,
    )
    # データセットを訓練用、テスト用に分割する
    train_data, test_data, train_label, test_label = train_test_split(data, label)

データは make_classification を使って生成します。指定しているパラメータとしては以下のような項目です。

  • n_samples:データ点数
  • n_classes:データのクラス数
  • n_features:各データの次元数
  • n_infomative:各データで情報を持ってる特徴数
  • n_redundant:各データで冗長な特徴数

今回は 4 次元の特徴を持つ 1,000 点のデータで、2 つのクラスに分かれているデータを生成します。

n_infomative は 4 次元のうち意味のある特徴数で、n_redundant は冗長な特徴数という意味ですが、公式ドキュメントの記載を見ると「infomative な特徴のランダムな線形結合で生成される特徴の数」ということです。他の特徴で表現できるということは情報はもっていないような特徴ということですね。

乱数シードは、np.random.seed で設定していますが make_classificationrandam_state 引数で乱数シードを指定することも可能です。train_test_split を使ってデータを訓練用とテスト用に分割しています。

make_classification の公式ドキュメントはこちらを参照してください。

モデルの生成と正解率

    # ===== 複数のkで性能が分類性能がどのように変わるか確認
    k_list = [k for k in range(1, 11)]
    acc_list = []

    # ===== kを変えながらモデルを順番に学習
    for k in k_list:
        # モデルの構築
        model = KNeighborsClassifier(n_neighbors=k)
        # モデルの学習
        model.fit(train_data, train_label)
        # 正解率の評価
        acc_list.append(model.score(test_data, test_label))

上記部分が k 近傍法を実行している部分です。まずは、KNeighborsClassifier をインスタンス化します。その際の引数としては近傍数の n_neighbors を指定します。

モデルの学習については、fit を使用して train_datatrain_label を使用します。また、正解率は、訓練データとは異なる test_datatest_label を用いて score により計算します。

今回は k=1 ~ 10 までの数を順番に変えながら for 文で実行し、正解率をリストに追加していきます。

正解率のプロット

    # ===== 正解率をプロットする
    plt.plot(k_list, acc_list)
    plt.title("accuracy list")
    plt.xlabel("n_neighbors")
    plt.ylabel("accuracy")
    plt.show()
k近傍法 (k-NN) 正解率

こちらの部分は、計算した正解率のリストをプロットしている部分です。正解率は、どうやら n_neighbors=3 の時が最も高いようです。

今回のデータではという意味ですので、3 が常に適切ということはありません。対象とする問題によりハイパーパラメータとして調整する必要があります。近傍数が多すぎると分類範囲の狭いようなカテゴリーではうまく分類されない場合もあります。

以上が、scikit-learn の KNeighborsClassifier を使った k 近傍法 (k-NN) によるデータ分類方法の紹介でした。

まとめ

Python の機械学習ライブラリである scikit-learn の KNeighborsClassifier を使って k 近傍法 (k-NN) によるデータ分類を行う方法を解説しました。

k 近傍法は、分類アルゴリズムの中ではかなりシンプルな考え方の方法で簡単に適用できます。まずデータ分類するときに使ってみるのもよいでしょう。必ずしも複雑な分類モデルが常に適切ということはなく、k 近傍法で十分な例もあるかもしれません。

今回紹介したように簡単に使用できますので、試しに使ってみてください。

sklearn.neighbors.KNeighborsClassifier の公式ドキュメントはこちらを参照してください。

ソースコード

上記で紹介しているソースコードについては GitHub にて公開しています。参考にしていただければと思います。

あわせて読みたい
【Python Tech】プログラミングガイド
【Python Tech】プログラミングガイド
ABOUT ME
ホッシー
ホッシー
システムエンジニア
はじめまして。当サイトをご覧いただきありがとうございます。 私は製造業のメーカーで、DX推進や業務システムの設計・開発・導入を担当しているシステムエンジニアです。これまでに転職も経験しており、以前は大手電機メーカーでシステム開発に携わっていました。

プログラミング言語はこれまでC、C++、JAVA等を扱ってきましたが、最近では特に機械学習等の分析でも注目されているPythonについてとても興味をもって取り組んでいます。これまでの経験をもとに、Pythonに興味を持つ方のお役に立てるような情報を発信していきたいと思います。どうぞよろしくお願いいたします。

※キャラクターデザイン:ゼイルン様
記事URLをコピーしました