ゼロから始める Python 機械学習ガイド (3) - 教師あり学習の kNN 分類

導入

このブログでは、例を組み合わせて、监督学习/Supervised Learning/SL別の大きなブランチを紹介します分类/Classification正確に言うと、使用する分類アルゴリズムは です邻近算法/k-nearest neighbors/kNN

始める前の準備

開始する前に、Python 環境に次のパッケージがあることを確認してください:
pandasnumpysklearnseaborn

この記事のコードはすべて で実行できAnacondaますJupyter Lab

文章

分类/Classification問題の性質は何ですか?
前回のブログで説明した問題を確認してみましょう回归/Regression回帰問題の本質は、未知のデータ ポイントを最も正確に予測できる回帰直線を見つけることです。たとえば、入力として連続変数を指定すると、その連続変数を出力として取得できます。

分類問題も同様で、特徴セットとラベル セットの間の関係を最も正確に記述できるモデルを見つける必要があります。ただし、違いは、分類問題のラベル セットがすべて非連続変数であることです。たとえば、人の年齢を考慮すると、その人は成人か未成年かのどちらかにしか分類できませんが、動物が写っている写真があれば、その動物の種類を正確に識別して区別する必要があります。言い換えれば、分類問題は、未知のマッピングffに対して次のように理解できます。f
f : R n ↦ L f:\mathbb{R}^n\mapsto \mathbb{L}f:RnL
、それはあります定义域/Domain(R n \mathbb{R}^nRnは特徴セット) および对应域/Codomain(L \mathbb{L}Lはラベル セットの配列です)。既存のデータを使用して、データに最適なモデルを見つけたいと考えています。ラベル集合L \mathbb{L}Lは有限集合です。したがって、回帰関数と異なるのは、分類関数が であることができること非参数模型/nonparametric function、つまりパラメータ (線形回帰 \bf w の重みセット ww ) データの分類を実現できます。最も単純な例は、この記事で紹介する KNN アルゴリズムです。

KNNとは何ですか?どのようにして分類が行われるのでしょうか?
その名前から答えを見つけることができますk-nearest neighbors。新しいデータ ポイントについて、アルゴリズムは、「赤に近いものは赤、インクに近いものは黒」と同様に、どのラベル データに最も近いかを決定します。 」これまで見たことのないものを見ると、私たち人間はそれを、これまでに見た最も類似したものと比較します。

新しいデータ特徴の場合、x = [ x 1 x 2 … xn ] x=[x_1\ x_2\ \dots \ x_n]バツ=[ ×1 バツ2  バツ]、kNN アルゴリズムはkkデータ特性に最も近いk 個の近傍を抽出し、これらの近傍のラベルを使用して新しいデータのラベルを決定します。言い換えれば、入力された未知のデータをボールの中心として N 次元のボールを描画し、ボール内のデータ点が正確にkkk 、次にボールの内側のkkk点は、アルゴリズムが考慮する必要がある入力データの最近傍点です。通常、判断には次の 2 つの方法があります。

  1. 多数决规则/Majority Rule隣接するラベルの中で最も多くのラベルを持つラベルが選択されます。同数のラベルがある場合は、ラベルがランダムに選択されます。以下の例では、クエスチョンマークデータは、k=3 の場合は B、k=7 の場合は A に分類されます。
    多数決
  2. 基于距离的规则/Distance-based Rule互いに近い隣接するものほど重みが高くなります。近ければ近いほど、重みも高くなります。最後に、最も高い加重平均を持つラベルが選択されます。右下のプロットでは、緑色のデータが疑問符データに近いため、疑問符データ ラベルを決定する際の重みが高くなります。
    距離ベースのルール

2 番目のルールを実装して最近傍を決定するには、距離の尺度も定義する必要があります。2 つのデータ特徴の場合xxxyyy 、 2 つの間のdddには次の定義があります。
3.L 1 L_1L1曼哈顿距离/Manhattan Distanced ( x , y ) = ∑ i = 1 n ∣ xi − yi ∣ d(x,y)=\sum_{i=1}^{n} |{x_i-y_i}|d ( x ,y )=i = 1x私はy私は平面上の 2 点の場合、この式は 2 点xxxyyy座標の差の合計 (下図の直角三角形の直角辺の長さの合計)。
4.L2L_2_L2欧几里得距离/Euclidian Distanced ( x , y ) = ∑ i = 1 n ∣ xi − yi ∣ 2 d(x,y)=\sqrt{\sum_{i=1}^{n} |{x_i-y_i}|^2}d ( x ,y )=i = 1x私はy私は2 この式は、平面上の 2 点について、2 点間の直線距離 (下図の直角三角形の斜辺の長さ) を計算します。
5.L ∞ L_\infinL切比雪夫距离/Chebyshev Distanced ( x , y ) = max ⁡ 1 ≤ i ≤ n ∣ xi − yi ∣ d(x,y)=\max_{1\le i\le n}|x_i-y_i|d ( x ,y )=最大1 i nx私はy私は .. 平面上の 2 点の場合、この式は 2 点xxxyyy座標の差の最大値 (下図の直角三角形の最も長い直角辺)。上記のことから、モデルの決定は最適な重みではなくすべての入力データに依存するため、
距離の公式
KNN がモデルであることもわかります非参数模型/nonparametric functionしたがって、データの信頼性と包括性を維持するために、通常、kNN モデルのサイズは大きくなります。

モデルに超参/Hyperparametersは近傍数kkのみが含まれます。k、どのラベル決定ルールと距離計算方法を使用するかを決定する必要があるため、多くの場合、さまざまな組み合わせを試して最適なモデルを見つけることができます。

最後に 1 つポイント: すべてのデータが KNN 分類に適しているわけではありません。データが十分に分離されていない場合 (つまり、異なるラベルを持つデータが多く重複している場合)、kNN のパフォーマンスは低下します。このとき、モデルを変更する数据工程/Data Engineeringか。

コード

原理を理解した後、Python を使用して上記の kNN 分類アルゴリズムを実装できます。

まず必要なライブラリをインポートします。

import pandas as pd
import matplotlib
import matplotlib.pyplot as plt
import numpy as np

今回使用したデータセットはsklearnパッケージに同梱されており、アヤメの花を分類するために使用されます。データは合計 150 行 4 列で構成されます。特徴セットには花の花びらとがく片の長さと幅が含まれます。ラベル セットにはアヤメが属する種 (Setosa/Mountain Iris、Versicolour/variegated Iris) が含まれます。 、バージニカ/バージニア アイリス)。

from sklearn.datasets import load_iris 
iris = load_iris() # 从sklearn中引入数据集

iris_df = pd.DataFrame(iris.data, columns=iris.feature_names) # 创建DataFrame

iris_df['Iris species'] = iris.target # 在DataFrame里加入标签集
print(iris_df) # 看看长什么样

以下の図は、上記のコードの出力を示しています。特徴セットには 4 つの特徴 (つまり、DataFrame の最初の 4 列) があり、ラベル セットは番号で表されるアヤメの種であることがわかります。
データフレーム
簡単な視覚化を行うことができます。seabornこれは、変数のさまざまな順列や組み合わせを描画する時間を節約できる、非常に便利な描画ライブラリです。コードは以下のように表示されます。

import seaborn as sb

sb.set(style="ticks", color_codes=True) # 设置视觉效果

g = sb.pairplot(iris_df, hue="Iris species", diag_kind='hist')

下の図は seaborn によって描画された結果であることがわかります。この図から、さまざまな変数間の関係を観察できます。上で述べたように、kNN には分離可能なラベル クラスが必要です。全体的に、クラス 0 は他のクラスから十分に分離されていますが、クラス 1 とクラス 2 の間にはいくつかの重複があるように見えます。この単純な観察から、モデルのクラス 0 の分類精度は高く、クラス 1 とクラス 2 の間の精度は低くなることが推測できます。
sb
次にモデルをトレーニングします。モデルのトレーニングも次のように非常に簡単です。

from sklearn.neighbors import KNeighborsClassifier
neighbors_num = 10 # 考虑的邻居数量
weights = 'uniform' # 多数决规则

classifier = KNeighborsClassifier(n_neighbors=neighbors_num, weights=weights)

classifier.fit(iris.data, iris.target) # 学习数据

モデルのトレーニングが完了したので、そのパフォーマンスを評価する方法を考えてみましょう。sklearn使用されるメソッドは と呼ばれます0-1损失函数/Zero-one Loss簡単に言うと、正しい分類を 0、誤った分類を 1 として記録し、すべての分類のスコアを合計し、データの総数で割ります。定義は次のようになります: E ˉ = 1 m ∑ t
∈すべてのデータ 1 clf ( t ) ≠ t \bar{E} = \frac{1}{m}\sum_{t \in all\ data} {\bf 1}_{clf(t) \net}Eˉ=メートル1t すべてデータ_ _ _ 1c l f ( t )= t
つまり、精度は1 − E ˉ 1-\bar{E}です。1Eˉこれを直接sklearn.metrics使用して

from sklearn import metrics 

Y_pred = classifier.predict(iris.data) # 模型预测的标签集

accuracy = metrics.accuracy_score(iris.target, Y_pred)

print('Training accuracy of kNN: {:.3f}'.format(accuracy))
# Training accuracy of kNN: 0.980

依然として精度が非常に高いことがわかります。しかし、どのデータが誤って分類されているかをどうやって知ることができるでしょうか? 混淆矩阵/Confusion Matrix直感的な判断を下すことができます。

from sklearn.metrics import confusion_matrix

def show_confusion_matrix(true_labels, learned_labels, class_names):
	# 用sklearn创建混淆矩阵对象
    cmat = confusion_matrix(true_labels, learned_labels) 
    
	# 设置图像大小
    plt.figure(figsize=(14, 5))
    plt.tick_params(labelsize=8)
    
    # 画出热度图
    hm = sb.heatmap(cmat.T, square=True, annot=True, fmt='d', cbar=True,
                     xticklabels=class_names,
                     yticklabels=class_names, 
                     cmap="seismic", 
                     annot_kws={
    
    "size":12}, cbar_kws={
    
    'label': 'Counts'})

    # 添加图例
    hm.figure.axes[-1].yaxis.label.set_size(10)
    hm.figure.axes[-1].tick_params(labelsize=8)

	# 增加坐标轴标题
    plt.xlabel('True label', fontsize=9)
    plt.ylabel('Predicted label', fontsize=9)
    
    plt.show()

Y_test = iris.target # 真实标签
show_confusion_matrix(Y_test, Y_pred, iris.target_names)

次の混同行列が得られます。私たちの推測どおり、モデルはタイプ 1 (versicolor) とタイプ 2 (virginica) を区別するときにいくつかのエラーを生成したことがわかります。私たちのモデルの精度はすでに非常に高いですが、精度が低い場合は、モデルがエラーを起こしやすいカテゴリにさらに多くのデータ サンプルを追加するか、データにより便利な機能 (ブレードの厚さなど) を提供することを検討する必要があります。 )。
混同行列
もちろん、上記で選択した番号はk=10私たちが任意に選択した番号です。より良い隣人の数はありますか? 次のように、さまざまな k 値を試し、交叉验证/Cross-validationさまざまなモデルのパフォーマンスを評価できます。

from sklearn.model_selection import cross_validate

features = iris.data # 特征集
labels = iris.target # 标签集

k_fold = 10

for k in [1,2,3,4,5,6,7,8,9,10,20,50]:
    classifier = KNeighborsClassifier(n_neighbors=k, weights='uniform')
    classifier.fit(features, labels)

    cv_results = cross_validate(classifier, features, labels, 
                                cv=k_fold, return_train_score=True)

    print('[{}-NN] Mean test score: {:.3f} (std: {:.3f})'
          '\nMean train score: {:.3f} (std: {:.3f})\n'.format(k,
                                                  np.mean(cv_results['test_score']),
                                                  np.std(cv_results['test_score']),
                                                  np.mean(cv_results['train_score']),
                                                  np.std(cv_results['train_score'])))
'''
[1-NN] Mean test score: 0.960 (std: 0.053)
Mean train score: 1.000 (std: 0.000)

[2-NN] Mean test score: 0.953 (std: 0.052)
Mean train score: 0.979 (std: 0.005)

[3-NN] Mean test score: 0.967 (std: 0.045)
Mean train score: 0.961 (std: 0.007)

[4-NN] Mean test score: 0.967 (std: 0.045)
Mean train score: 0.964 (std: 0.007)

[5-NN] Mean test score: 0.967 (std: 0.045)
Mean train score: 0.969 (std: 0.007)

[6-NN] Mean test score: 0.967 (std: 0.045)
Mean train score: 0.973 (std: 0.008)

[7-NN] Mean test score: 0.967 (std: 0.045)
Mean train score: 0.973 (std: 0.006)

[8-NN] Mean test score: 0.967 (std: 0.045)
Mean train score: 0.980 (std: 0.006)

[9-NN] Mean test score: 0.973 (std: 0.033)
Mean train score: 0.979 (std: 0.006)

[20-NN] Mean test score: 0.980 (std: 0.031)
Mean train score: 0.974 (std: 0.013)

[50-NN] Mean test score: 0.927 (std: 0.036)
Mean train score: 0.933 (std: 0.017)
'''

上記からわかるように、k=1これは最もよくトレーニングされたものであるように見えますが、この場合、モデルのトレーニング精度が検証精度よりもはるかに高いため、モデルが過学習していることは明らかです。k=50十分なサンプルがなく (わずか 150 個)、近傍を考慮しすぎたため、精度が大幅に低くなり、モデルの意思決定がより誤解を招く原因となりました。トレーニング精度と検証精度が高く、差が小さいものを選択するように最善を尽くしたほうが良いでしょうk=9

結論

次回のブログでは、ブロガーが教師なし学習のK-均值聚类/K-means Clusteringアルゴリズムを使用して実装する方法を紹介します分类/Classificationご質問やご提案がございましたら、お気軽にコメントまたはプライベートメッセージを送信してください。コーディングは簡単ではありませんが、ブロガーのコンテンツが気に入ったら、「いいね!」とサポートをお願いします。

おすすめ

転載: blog.csdn.net/EricFrenzy/article/details/131468505