Python および Scikit-Learn PlatoBlockchain Data Intelligence の K 最近傍アルゴリズムのガイド。垂直検索。あい。

Python と Scikit-Learn の K 最近傍アルゴリズムのガイド

概要

  K 最近傍 (KNN) アルゴリズムは、分類、回帰、外れ値検出に使用される教師あり機械学習アルゴリズムの一種です。 最も基本的な形式で実装するのは非常に簡単ですが、かなり複雑なタスクを実行できます。 特別なトレーニング フェーズがないため、遅延学習アルゴリズムです。 むしろ、新しいデータ ポイントまたはインスタンスを分類 (または回帰) しながら、すべてのデータをトレーニングに使用します。

KNNは ノンパラメトリック学習アルゴリズム、つまり、基になるデータについて何も想定していません。 これは非常に便利な機能です。実際のデータのほとんどは、線形分離可能性、一様分布などの理論的仮定に実際には従っていないからです。

このガイドでは、Python の Scikit-Learn ライブラリを使用して KNN を実装する方法について説明します。 その前に、まず KNN をどのように使用できるかを探り、その背後にある理論を説明します。 その後、 カリフォルニア州住宅データセット KNN アルゴリズムとそのバリエーションのいくつかを説明するために使用します。 まず、回帰用の KNN アルゴリズムを実装する方法を見ていき、次に KNN 分類と外れ値検出の実装を見ていきます。 最後に、アルゴリズムの長所と短所をいくつか紹介します。

いつ KNN を使用する必要がありますか?

アパートを借りたいと思っていて、最近、友人の隣人が 2 週間以内にアパートを借りる可能性があることを知ったとします。 このアパートはまだ賃貸ウェブサイトに掲載されていないので、その賃貸価格をどのように見積もることができますか?

あなたの友人が 1,200 ドルの家賃を払っているとしましょう。 あなたの家賃の値はその程度かもしれませんが、アパートはまったく同じではない (向き、面積、家具の品質など) ため、他のアパートのデータをもっと持っておくとよいでしょう。

他の隣人に尋ねて、賃貸ウェブサイトに掲載されていた同じ建物のアパートを見ると、最も近い 1,200 つの近隣アパートの家賃は 1,210 ドル、1,210 ドル、1,215 ドル、XNUMX ドルです。 それらのアパートは、あなたの友人のアパートと同じブロックとフロアにあります.

同じフロアにあるが別のブロックにある、さらに離れた他のアパートの家賃は、$ 1,400、$ 1,430、$ 1,500、および$ 1,470です。 夕方は日差しが強いため、お値段が高めのようです。

アパートが近くにあることを考えると、あなたの推定家賃は約 $1,210 になるようです。 それが、 K最近傍法(KNN) アルゴリズムが行います! 既存のデータとの近接性に基づいて、新しいデータを分類または回帰します。

例を理論に変換する

家賃の値など、推定値が連続する数値の場合は、KNN を使用します。 回帰. ただし、たとえば、最低家賃と最高家賃に基づいてアパートをカテゴリに分類することもできます。 値が離散的でカテゴリになる場合、KNN が使用されます。 分類.

また、どの隣人が他の人と非常に異なっているため、おそらく家賃の支払いをやめる可能性があるかを推定する可能性もあります。 これは、どの値やカテゴリにも当てはまらないほど離れているデータ ポイントを検出するのと同じです。その場合、KNN が使用されます。 外れ値の検出.

この例では、各アパートの家賃も既にわかっているため、データにラベルが付けられています。 KNN は、以前にラベル付けされたデータを使用します。 教師あり学習アルゴリズム.

KNN は、最も基本的な形式で非常に簡単に実装できますが、非常に複雑な分類、回帰、または外れ値検出タスクを実行します。

データに新しい点が追加されるたびに、KNN はデータの一部のみを使用して、その追加された点の値 (回帰) またはクラス (分類) を決定します。 すべてのポイントをもう一度見る必要がないため、 遅延学習アルゴリズム.

また、KNN は、基礎となるデータの特性については何も想定しておらず、データが均一などの何らかのタイプの分布に適合することや、線形分離可能であることを期待していません。 これは、 ノンパラメトリック学習アルゴリズム. 実世界のデータのほとんどは実際には理論上の仮定に従っていないため、これは非常に便利な機能です。

KNN のさまざまな用途の視覚化

示されているように、KNN アルゴリズムの背後にある直感は、すべての教師あり機械学習アルゴリズムの中で最も直接的なアルゴリズムの XNUMX つです。 アルゴリズムは最初に 距離 他のすべてのトレーニング データ ポイントへの新しいデータ ポイントの。

注: 距離はさまざまな方法で測定できます。 ミンコフスキーを使用できます。 ユークリッド、マンハッタン、マハラノビス、またはハミングの式など、いくつかの指標を挙げることができます。 高次元データでは、ユークリッド距離はしばしば失敗し始め (高次元は… 奇妙です)、代わりにマンハッタン距離が使用されます。

距離を計算した後、KNN はいくつかの最も近いデータ ポイント (2、3、10、または実際には任意の整数) を選択します。 このポイント数 (2、3、10 など) は、 K K最近傍で!

最後のステップで、回帰タスクの場合、KNN は予測のために K 最近傍点の平均加重和を計算します。 分類タスクの場合、新しいデータ ポイントは、選択された K 最近傍ポイントの大部分が属するクラスに割り当てられます。

簡単な例を使って、実際のアルゴリズムを視覚化してみましょう。 3 つの変数と XNUMX の K を持つデータセットを考えてみましょう。

回帰を実行するときのタスクは、最も近い 3 つのポイントの平均加重合計に基づいて、新しいデータ ポイントの値を見つけることです。

とのKNN K = 3、時 回帰に使用:

Python および Scikit-Learn PlatoBlockchain Data Intelligence の K 最近傍アルゴリズムのガイド。垂直検索。あい。

KNN アルゴリズムは、すべてのポイントから新しいポイントまでの距離を計算することから始めます。 次に、新しいポイントまでの距離が最小の 3 つのポイントを見つけます。 これは上の XNUMX 番目の図に示されています。 47, 58, 79 取り囲まれています。 その後、加重合計を計算します。 47, 58 および 79 – この場合、重みは 1 です – すべてのポイントを等しいと見なしますが、距離に基づいて異なる重みを割り当てることもできます。 加重合計を計算した後、新しいポイント値は 61,33.

分類を実行するとき、新しいデータ ポイントを分類する KNN タスクは、 "Purple" or "Red" とに提供されます。

とのKNN K = 3、時 分類に使用:

Python および Scikit-Learn PlatoBlockchain Data Intelligence の K 最近傍アルゴリズムのガイド。垂直検索。あい。
Python および Scikit-Learn PlatoBlockchain Data Intelligence の K 最近傍アルゴリズムのガイド。垂直検索。あい。

KNN アルゴリズムは、すべてのポイントから新しいポイントまでの距離を計算し、新しいポイントまでの距離が最も近い 3 つの最も近いポイントを見つけ、数値を計算する代わりに、前と同じ方法で開始します。最も近い XNUMX つのポイントの過半数が属するクラス (赤のクラス) への新しいポイント。 したがって、新しいデータ ポイントは次のように分類されます。 "Red".

外れ値検出プロセスは上記の両方とは異なります。回帰と分類の実装後に実装するときに、それについて詳しく説明します。

Note: このチュートリアルで提供されるコードは、以下で実行およびテストされています。 Jupyter Notebook.

Scikit-Learn カリフォルニア州住宅データセット

を使用します カリフォルニア州の住宅データセット KNN アルゴリズムがどのように機能するかを説明します。 このデータセットは、1990 年の米国の国勢調査から派生したものです。 データセットの XNUMX 行は、XNUMX つのブロック グループの国勢調査を表します。

このセクションでは、カリフォルニア州住宅データセットの詳細について説明します。これにより、使用するデータを直感的に理解できるようになります。 作業を開始する前に、データについて理解することは非常に重要です。

A コロナ新型ウィルス(COVID-XNUMX)やメンタルヘルスの崩壊を避ける為の グループは、米国国勢調査局がサンプル データを公開する最小の地理的単位です。 ブロックグループのほかに、世帯という別の用語が使用されます。世帯は、家の中に住む人々のグループです。

データセットは次の XNUMX つの属性で構成されます。

  • MedInc – ブロックグループの収入の中央値
  • HouseAge – ブロックグループの住宅年齢の中央値
  • AveRooms – 平均部屋数 (世帯ごとに提供)
  • AveBedrms – 寝室の平均数 (世帯ごとに提供)
  • Population – ブロックグループのポピュレーション
  • AveOccup – 世帯員の平均数
  • Latitude – ブロックグループの緯度
  • Longitude – ブロックグループの経度
  • MedHouseVal – カリフォルニア地区の住宅価格の中央値 (数十万ドル)

データセットは すでに Scikit-Learn ライブラリの一部、それをインポートしてデータフレームとしてロードするだけです。

from sklearn.datasets import fetch_california_housing

california_housing = fetch_california_housing(as_frame=True)

df = california_housing.frame

Scikit-Learn から直接データをインポートすると、列と数値だけでなく、データの説明が Bunch オブジェクト – 抽出したばかりです frame. データセットの詳細が利用可能です こちら.

Pandas をインポートして、データの最初の数行を見てみましょう。

import pandas as pd
df.head()

コードを実行すると、データセットの最初の XNUMX 行が表示されます。

	MedInc  HouseAge  AveRooms  AveBedrms  Population  AveOccup   Latitude  Longitude  MedHouseVal
0 	8.3252 	41.0 	  6.984127 	1.023810   322.0 	   2.555556   37.88 	-122.23    4.526
1 	8.3014 	21.0 	  6.238137 	0.971880   2401.0 	   2.109842   37.86 	-122.22    3.585
2 	7.2574 	52.0 	  8.288136 	1.073446   496.0 	   2.802260   37.85 	-122.24    3.521
3 	5.6431 	52.0 	  5.817352 	1.073059   558.0 	   2.547945   37.85 	-122.25    3.413
4 	3.8462 	52.0 	  6.281853 	1.081081   565.0 	   2.181467   37.85 	-122.25    3.422

このガイドでは、 MedInc, HouseAge, AveRooms, AveBedrms, Population, AveOccup, Latitude, Longitude 予測する MedHouseVal. 私たちの動機の物語に似たもの。

それでは、回帰のための KNN アルゴリズムの実装に飛び込みましょう。

Scikit-Learn を使用した K 最近傍法による回帰

ここまでで、データセットについて理解できたので、KNN アルゴリズムの他のステップに進むことができます。

KNN 回帰のためのデータの前処理

前処理は、回帰タスクと分類タスクの最初の違いが現れる場所です。 このセクションはすべて回帰に関するものなので、それに応じてデータセットを準備します。

回帰のために、別の住宅価格の中央値を予測する必要があります。 そのために、私たちは割り当てます MedHouseVal 〜へ y および他のすべての列 X 落とすだけで MedHouseVal:

y = df['MedHouseVal']
X = df.drop(['MedHouseVal'], axis = 1)

変数の説明を見ると、測定値に違いがあることがわかります。 推測を避けるために、 describe() チェックする方法:


X.describe().T

この結果:

			count 	  mean 		   std 			min 		25% 		50% 		75% 		max
MedInc 		20640.0   3.870671 	   1.899822 	0.499900 	2.563400 	3.534800 	4.743250 	15.000100
HouseAge 	20640.0   28.639486    12.585558 	1.000000 	18.000000 	29.000000 	37.000000 	52.000000
AveRooms 	20640.0   5.429000 	   2.474173 	0.846154 	4.440716 	5.229129 	6.052381 	141.909091
AveBedrms 	20640.0   1.096675 	   0.473911 	0.333333 	1.006079 	1.048780 	1.099526 	34.066667
Population 	20640.0   1425.476744  1132.462122 	3.000000 	787.000000 	1166.000000 1725.000000 35682.000000
AveOccup 	20640.0   3.070655 	   10.386050 	0.692308 	2.429741 	2.818116 	3.282261 	1243.333333
Latitude 	20640.0   35.631861    2.135952 	32.540000 	33.930000 	34.260000 	37.710000 	41.950000
Longitude 	20640.0   -119.569704  2.003532    -124.350000 -121.800000 	-118.490000 -118.010000 -114.310000

ここで、 mean の値 MedInc 約です 3.87mean の値 HouseAge についてです 28.64、それの7.4倍の大きさになります MedInc. 他の機能も平均と標準偏差に違いがあります – それを確認するには、 mean および std 値とそれらが互いにどのように離れているかを観察します。 為に MedInc std 約です 1.9、用 HouseAge, std is 12.59 同じことが他の機能にも当てはまります。

に基づいたアルゴリズムを使用しています 距離 また、距離ベースのアルゴリズムは、このデータのように同じ縮尺ではないデータに大きく影響されます。 ポイントのスケールは、値間の実際の距離を歪める可能性があります (実際には、ほとんどの場合そうなります)。

機能スケーリングを実行するには、Scikit-Learn の StandardScaler クラスは後で。 スケーリングを今すぐ (トレーニングとテストの分割前に) 適用すると、計算にはテスト データが含まれます。 漏れ パイプラインの残りの部分にデータ情報をテストします。 この種の データ漏洩 残念ながら一般的にスキップされ、再現不可能または幻想的な結果が得られます。

トレーニング セットとテスト セットへのデータの分割

漏れなくデータをスケーリングできるだけでなく、結果を評価し、過学習を回避するために、データセットをトレーニングとテストの分割に分割します。

トレーニングとテストの分割を作成する簡単な方法は、 train_test_split Scikit-Learn のメソッド。 分割はある時点で直線的に分割されませんが、X% と Y% をランダムにサンプリングします。 このプロセスを再現可能にする (メソッドが常に同じデータポイントをサンプリングするようにする) には、 random_state ある議論 SEED:

from sklearn.model_selection import train_test_split

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

このコードでは、トレーニング用にデータの 75% をサンプリングし、テスト用にデータの 25% をサンプリングします。 を変更することにより、 test_size たとえば、0.3 にすると、データの 70% でトレーニングし、30% でテストできます。

データの 75% をトレーニングに使用し、25% をテストに使用すると、20640 レコードのうち、トレーニング セットには 15480 が含まれ、テスト セットには 5160 が含まれます。完全なデータセットと分割データの長さを出力することで、これらの数値をすばやく調べることができます。 :

len(X)       
len(X_train) 
len(X_test)  

すごい! これで、データ スケーラーを X_train 両方を設定し、スケーリングします X_train および X_test からデータを漏らすことなく X_testX_train.

KNN 回帰の特徴スケーリング

輸入することで StandardScaler、それをインスタンス化し、トレーニング データに従ってフィッティングし (漏れを防ぎます)、トレーニング データセットとテスト データセットの両方を変換することで、特徴のスケーリングを実行できます。

from sklearn.preprocessing import StandardScaler

scaler = StandardScaler()

scaler.fit(X_train)


X_train = scaler.transform(X_train)
X_test = scaler.transform(X_test)

注: よく電話するから scaler.fit(X_train) 続い scaler.transform(X_train) – シングルを呼び出すことができます scaler.fit_transform(X_train) 続い scaler.transform(X_test) 通話を短くするために!

これで、データがスケーリングされました。 スケーラーは、データ ポイントに適用されると、列名ではなく、データ ポイントのみを維持します。 DataFrame. 列名を使用してデータを再度 DataFrame に整理し、使用します。 describe() の変化を観察する mean および std:

col_names=['MedInc', 'HouseAge', 'AveRooms', 'AveBedrms', 'Population', 'AveOccup', 'Latitude', 'Longitude']
scaled_df = pd.DataFrame(X_train, columns=col_names)
scaled_df.describe().T

これは私たちに与えるでしょう:

			count 		mean 			std 		min 		25% 		50% 		75% 		max
MedInc 		15480.0 	2.074711e-16 	1.000032 	-1.774632 	-0.688854 	-0.175663 	0.464450 	5.842113
HouseAge 	15480.0 	-1.232434e-16 	1.000032 	-2.188261 	-0.840224 	0.032036 	0.666407 	1.855852
AveRooms 	15480.0 	-1.620294e-16 	1.000032 	-1.877586 	-0.407008 	-0.083940 	0.257082 	56.357392
AveBedrms 	15480.0 	7.435912e-17 	1.000032 	-1.740123 	-0.205765 	-0.108332 	0.007435 	55.925392
Population 	15480.0 	-8.996536e-17 	1.000032 	-1.246395 	-0.558886 	-0.227928 	0.262056 	29.971725
AveOccup 	15480.0 	1.055716e-17 	1.000032 	-0.201946 	-0.056581 	-0.024172 	0.014501 	103.737365
Latitude 	15480.0 	7.890329e-16 	1.000032 	-1.451215 	-0.799820 	-0.645172 	0.971601 	2.953905
Longitude 	15480.0 	2.206676e-15 	1.000032 	-2.380303 	-1.106817 	0.536231 	0.785934 	2.633738

すべての標準偏差が現在どのようになっているのかを観察します 1 そして手段は小さくなりました。 これが私たちのデータを作るものです より均一! KNN ベースのリグレッサーをトレーニングして評価しましょう。

KNN 回帰のトレーニングと予測

Scikit-Learn の直感的で安定した API により、リグレッサーと分類器のトレーニングが非常に簡単になります。 インポートしましょう KNeighborsRegressor からのクラス sklearn.neighbors モジュールを作成し、インスタンス化し、トレーニング データに適合させます。

from sklearn.neighbors import KNeighborsRegressor
regressor = KNeighborsRegressor(n_neighbors=5)
regressor.fit(X_train, y_train)

上記のコードでは、 n_neighbors の値です K、またはアルゴリズムが新しい住宅の中央値を選択するために考慮する近隣の数。 5 のデフォルト値です KNeighborsRegressor(). K には理想的な値はなく、テストと評価の後に選択されますが、最初は、 5 は KNN で一般的に使用される値であるため、デフォルト値として設定されました。

最後のステップは、テスト データで予測を行うことです。 これを行うには、次のスクリプトを実行します。

y_pred = regressor.predict(X_test)

これで、モデルがラベル (グラウンド トゥルース) を持つ新しいデータ (テスト セット) にどの程度一般化されているかを評価できます。

KNN 回帰のアルゴリズムの評価

アルゴリズムを評価するために最も一般的に使用される回帰指標は、平均絶対誤差 (MAE)、平均二乗誤差 (MSE)、二乗平均平方根誤差 (RMSE)、および決定係数 (R2):

  1. 平均絶対誤差(MAE): 実際の値から予測値を差し引いて誤差を求め、それらの誤差の絶対値を合計して平均値を求めます。 このメトリックは、モデルの各予測の全体的なエラーの概念を示します。小さいほど (0 に近いほど) 優れています。

$$
mae =(frac {1} {n})sum_ {i = 1}^{n}左| 実際–予測される権利|
$$

注: あなたも遭遇するかもしれません y および ŷ (y-hat と読みます) 式の表記。 の y 実際の値を参照し、 ŷ 予測値に。

  1. 平均二乗誤差(MSE): MAE メトリックに似ていますが、誤差の絶対値を 0 乗します。 また、MAE と同様に、小さいほど、または XNUMX に近いほど良いです。 MSE 値は、大きな誤差がさらに大きくなるように XNUMX 乗されます。 細心の注意を払うべきことの XNUMX つは、その値のサイズと、データと同じスケールではないという事実のために、通常は解釈が難しいメトリックであるということです。

$$
mse = sum_ {i = 1} ^ {D}(実際–予測)^ 2
$$

  1. 二乗平均平方根誤差(RMSE):データの同じ単位にスケールバックするために、最終値の平方根を取得することにより、MSEで発生した解釈の問題を解決しようとします。 エラーのあるデータの実際の値を表示または表示する必要がある場合は、解釈が簡単で適切です。 データがどの程度変化する可能性があるかを示しているため、RMSEが4.35の場合、モデルは実際の値に4.35を追加したか、実際の値に到達するために4.35が必要だったため、エラーが発生する可能性があります。 0に近いほど、同様に優れています。

$$
rmse = sqrt {sum_ {i = 1} ^ {D}(実際–予測)^ 2}
$$

  mean_absolute_error() および mean_squared_error() の方法 sklearn.metrics 次のスニペットに示すように、これらの指標を計算するために使用できます。

from sklearn.metrics import mean_absolute_error, mean_squared_error

mae = mean_absolute_error(y_test, y_pred)
mse = mean_squared_error(y_test, y_pred)
rmse = mean_squared_error(y_test, y_pred, squared=False)

print(f'mae: {mae}')
print(f'mse: {mse}')
print(f'rmse: {rmse}')

上記のスクリプトの出力は次のようになります。

mae: 0.4460739527131783 
mse: 0.4316907430948294 
rmse: 0.6570317671884894

R2 で直接計算できます。 score() 方法:

regressor.score(X_test, y_test)

どの出力:

0.6737569252627673

結果は、KNN アルゴリズムの全体的なエラーと平均エラーが約であることを示しています。 0.44, 0.43. また、RMSE は、追加することでデータの実際の値を上回ったり下回ったりできることを示しています。 0.65 または減算 0.65. それはどれほど良いですか?

価格がどのように見えるかを確認しましょう。

y.describe()
count    20640.000000
mean         2.068558
std          1.153956
min          0.149990
25%          1.196000
50%          1.797000
75%          2.647250
max          5.000010
Name: MedHouseVal, dtype: float64

平均は 2.06 平均からの標準偏差は 1.15 〜のスコア0.44 本当に恒星ではありませんが、それほど悪くはありません。

Rで2、取得する 1 (または 100) に最も近いほど良いです。 R2 データまたはデータの変更の程度を示します 分散 理解されているか、 説明 KNNによる。

$$
R ^ 2 = 1 – frac {sum(実際–予測)^ 2} {sum(実際–実際の平均)^ 2}
$$

の値で 0.67、モデルがデータ分散の 67% を説明していることがわかります。 すでに 50% を超えています。これは問題ありませんが、あまり良くありません。 もっとうまくやれる方法はありますか?

の値を持つ所定の K を使用しました。 5、そのため、5 つの近傍を使用してターゲットを予測していますが、これは必ずしも最適な数ではありません。 K の理想的な数を理解するために、アルゴリズムのエラーを分析し、損失を最小限に抑える K を選択できます。

KNN 回帰に最適な K を見つける

理想的には、どのメトリックが自分のコンテキストにより適しているかを確認できますが、通常はすべてのメトリックをテストすることが興味深いものです。 それらすべてをテストできるときはいつでも、それを実行してください。 ここでは、平均絶対誤差のみを使用して最適な K を選択する方法を示しますが、他のメトリックに変更して結果を比較することもできます。

これを行うには、for ループを作成し、1 から X までの近傍を持つモデルを実行します。 各相互作用で、MAE を計算し、MAE の結果とともに K の数をプロットします。

error = []


for i in range(1, 40):
    knn = KNeighborsRegressor(n_neighbors=i)
    knn.fit(X_train, y_train)
    pred_i = knn.predict(X_test)
    mae = mean_absolute_error(y_test, pred_i)
    error.append(mae)

さて、プロットしてみましょう errors:

import matplotlib.pyplot as plt 

plt.figure(figsize=(12, 6))
plt.plot(range(1, 40), error, color='red', 
         linestyle='dashed', marker='o',
         markerfacecolor='blue', markersize=10)
         
plt.title('K Value MAE')
plt.xlabel('K Value')
plt.ylabel('Mean Absolute Error')

Python および Scikit-Learn PlatoBlockchain Data Intelligence の K 最近傍アルゴリズムのガイド。垂直検索。あい。

プロットを見ると、K が最小の MAE 値のようです。 12. より少ないデータをプロットして、プロットを詳しく見てみましょう。

plt.figure(figsize=(12, 6))
plt.plot(range(1, 15), error[:14], color='red', 
         linestyle='dashed', marker='o',
         markerfacecolor='blue', markersize=10)
plt.title('K Value MAE')
plt.xlabel('K Value')
plt.ylabel('Mean Absolute Error')

Python および Scikit-Learn PlatoBlockchain Data Intelligence の K 最近傍アルゴリズムのガイド。垂直検索。あい。

ベストプラクティス、業界で認められた標準、および含まれているチートシートを含む、Gitを学習するための実践的で実用的なガイドを確認してください。 グーグルGitコマンドを停止し、実際に 学ぶ それ!

組み込みを使用して、最小誤差とそのポイントのインデックスを取得することもできます min() 関数 (リストで動作) またはリストを NumPy 配列に変換して取得します argmin() (最小値を持つ要素のインデックス):

import numpy as np 

print(min(error))               
print(np.array(error).argmin()) 

隣人は 1 から数え始めましたが、配列は 0 ベースなので、11 番目のインデックスは 12 個の隣人です!

これは、MAE エラーが最も少ないポイントを予測できるようにするには、12 個の近傍が必要であることを意味します。 結果を比較するために、12 個の近傍でモデルとメトリクスを再度実行できます。

knn_reg12 = KNeighborsRegressor(n_neighbors=12)
knn_reg12.fit(X_train, y_train)
y_pred12 = knn_reg12.predict(X_test)
r2 = knn_reg12.score(X_test, y_test) 

mae12 = mean_absolute_error(y_test, y_pred12)
mse12 = mean_squared_error(y_test, y_pred12)
rmse12 = mean_squared_error(y_test, y_pred12, squared=False)
print(f'r2: {r2}, nmae: {mae12} nmse: {mse12} nrmse: {rmse12}')

次のコードの出力:

r2: 0.6887495617137436, 
mae: 0.43631325936692505 
mse: 0.4118522151025172 
rmse: 0.6417571309323467

12 個の近傍がある場合、KNN モデルはデータの分散の 69% を説明し、損失が少し少なくなりました。 0.44 〜へ 0.43, 0.43 〜へ 0.41, 0.65 〜へ 0.64 それぞれの指標で。 それほど大きな改善ではありませんが、それでも改善です。

注: この分析をさらに進めて、探索的データ分析 (EDA) と残差分析を行うと、特徴を選択してより良い結果を得るのに役立つ場合があります。

回帰に KNN を使用する方法については既に説明しましたが、ポイントの値を予測する代わりにポイントを分類したい場合はどうすればよいでしょうか? ここで、分類に KNN を使用する方法を見ていきます。

Scikit-Learn で K 最近傍点を使用した分類

このタスクでは、連続値を予測する代わりに、これらのブロック グループが属するクラスを予測します。 これを行うには、地区の住宅価格の中央値を異なる住宅価格範囲のグループに分割するか、 ビン.

分類に連続値を使用する場合は、通常、データをビン化できます。 このようにして、値ではなくグループを予測できます。

分類のためのデータの前処理

データ ビンを作成して、連続値をカテゴリに変換しましょう。


df["MedHouseValCat"] = pd.qcut(df["MedHouseVal"], 4, retbins=False, labels=[1, 2, 3, 4])

次に、データセットを属性とラベルに分割できます。

y = df['MedHouseValCat']
X = df.drop(['MedHouseVal', 'MedHouseValCat'], axis = 1)

を使用して以来、 MedHouseVal 列を作成してビンを作成するには、ドロップする必要があります MedHouseVal 列と MedHouseValCat からの列 X。 このように、 DataFrame データセットの最初の 8 列 (つまり、属性、機能) が含まれますが、 y のみが含まれます MedHouseValCat 割り当てられたラベル。

注: を使用して列を選択することもできます .iloc() それらをドロップする代わりに。 ドロップするときは、割り当てる必要があることに注意してください y 割り当てる前の値 X の削除された列を割り当てることができないため、値 DataFrame メモリ内の別のオブジェクトに。

トレーニング セットとテスト セットへのデータの分割

回帰で行われたように、データセットもトレーニングとテストの分割に分割します。 異なるデータがあるため、このプロセスを繰り返す必要があります。

from sklearn.model_selection import train_test_split

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

標準の Scikit-Learn 値である 75% のトレーニング データと 25% のテスト データを再度使用します。 これは、以前の回帰と同じ数のトレーニングとテストのレコードを持つことを意味します。

分類のための特徴スケーリング

同じ未処理のデータセットとそのさまざまな測定単位を扱っているため、回帰データに対して行ったのと同じ方法で、フィーチャのスケーリングを再度実行します。

from sklearn.preprocessing import StandardScaler

scaler = StandardScaler()
scaler.fit(X_train)

X_train = scaler.transform(X_train)
X_test = scaler.transform(X_test)

分類のためのトレーニングと予測

データのビニング、分割、およびスケーリングの後、最終的に分類子を適合させることができます。 予測のために、ベースラインとして再び 5 つのネイバーを使用します。 インスタンス化することもできます KNeighbors_ クラスを引数なしで作成すると、自動的に 5 つのネイバーが使用されます。 ここでは、インポートする代わりに KNeighborsRegressor、インポートします KNeighborsClassifier、 クラス:

from sklearn.neighbors import KNeighborsClassifier

classifier = KNeighborsClassifier()
classifier.fit(X_train, y_train)

フィッティング後 KNeighborsClassifier、テスト データのクラスを予測できます。

y_pred = classifier.predict(X_test)

予測を評価する時が来ました! この場合、値を予測するよりもクラスを予測する方が良い方法でしょうか? アルゴリズムを評価して何が起こるか見てみましょう。

分類のための KNN の評価

KNN 分類器を評価するために、 score メソッドですが、リグレッサーではなく分類子をスコアリングしているため、別のメトリックを実行します。 分類の基本的なメトリックは次のとおりです。 accuracy – 分類子がどれだけ多くの予測を正しく行ったかを示します。 精度の最低値は 0 で、最高値は 1 です。通常、その値に 100 を掛けてパーセンテージを取得します。

$$
精度 = frac{text{正しい予測の数}}{text{予測の総数}}
$$

注: 実際のデータで 100% の精度を得ることは非常に困難です。そうなった場合は、何らかの漏れや何か問題が発生している可能性があることに注意してください。理想的な精度値についてはコンセンサスがなく、状況にも依存します。 に応じて エラーのコスト (分類器を信頼していて、それが間違っていることが判明した場合、それはどれほど悪いことでしょう)、許容されるエラー率は 5%、10%、さらには 30% かもしれません。

分類子にスコアを付けましょう。

acc =  classifier.score(X_test, y_test)
print(acc) 

結果のスコアを見ると、分類器がクラスの最大 62% を正しく取得したと推測できます。 これはすでに分析に役立ちますが、分類器が何を正しくしたかを知るだけでは、それを改善することは困難です。

データセットには 4 つのクラスがあります。 クラス 90、1、および 2 の 3% が正しい、 だけ クラス30の権利の4%?

クラス間で共有されるバランスの取れた障害とは対照的に、一部のクラスの全体的な障害は、両方とも 62% の精度スコアをもたらす可能性があります。 精度は、実際の評価にはあまり適した指標ではありませんが、良い代用としては役立ちます。 多くの場合、バランスの取れたデータセットを使用すると、62% の精度が比較的均等に分散されます。 また、多くの場合、データセットはバランスが取れていないため、精度が不十分なメトリックであるという振り出しに戻ります。

それを判断できるように、他のメトリックを使用して結果をさらに詳しく調べることができます。 このステップも回帰とは異なります。ここでは以下を使用します。

  1. 混乱マトリックス: どれくらい正解したか、または間違っていたかを知るため 各クラス. 正しく、正しく予測された値が呼び出されます 真陽性 陽性と予測されたが陽性ではなかったものが呼び出されます 偽陽性. の同じ命名法 真のネガティブ および 偽陰性 負の値に使用されます。
  2. 精度: 分類子によってどの正しい予測値が正しいと見なされたかを理解するため。 精度は、これらの真陽性の値を陽性と予測されたもので除算します。

$$
精度 = frac{text{真陽性}}{text{真陽性} + text{偽陽性}}
$$

  1. リコール: 分類器によって識別された真陽性の数を理解するため。 再現率は、真の陽性を、陽性と予測されるはずだったもので割ることによって計算されます。

$$
リコール = frac{text{真陽性}}{text{真陽性} + text{偽陰性}}
$$

  1. F1スコア: バランスが取れているか、または 調和平均 精度と再現率。 最小値は 0 で、最大値は 1 です。 f1-score が 1 の場合、すべてのクラスが正しく予測されたことを意味します。これは、実際のデータで取得するのが非常に難しいスコアです (例外はほとんど常に存在します)。

$$
text{f1-score} = 2* frac{text{precision} * text{recall}}{text{precision} + text{recall}}
$$

注: 重み付けされた F1 スコアも存在します。これは、すべてのクラスに同じ重みを適用しない F1 にすぎません。 重みは通常、クラスによって決定されます サポート – F1 スコア (特定のクラスに属するラベルの割合) を「サポート」するインスタンスの数。 サポートが低い (クラスのインスタンスが少ない) ほど、信頼性が低くなるため、そのクラスの重み付けされた F1 が低くなります。

  confusion_matrix() および classification_report() の方法 sklearn.metrics モジュールを使用して、これらすべてのメトリックを計算および表示できます。 の confusion_matrix ヒートマップを使用して視覚化することをお勧めします。 分類レポートはすでに私たちに与えています accuracy, precision, recall, f1-score、しかし、これらの各指標をからインポートすることもできます sklearn.metrics.

メトリックを取得するには、次のスニペットを実行します。

from sklearn.metrics import classification_report, confusion_matrix

import seaborn as sns


classes_names = ['class 1','class 2','class 3', 'class 4']
cm = pd.DataFrame(confusion_matrix(yc_test, yc_pred), 
                  columns=classes_names, index = classes_names)
                  

sns.heatmap(cm, annot=True, fmt='d');

print(classification_report(y_test, y_pred))

上記のスクリプトの出力は次のようになります。

Python および Scikit-Learn PlatoBlockchain Data Intelligence の K 最近傍アルゴリズムのガイド。垂直検索。あい。

              precision    recall  f1-score   support

           1       0.75      0.78      0.76      1292
           2       0.49      0.56      0.53      1283
           3       0.51      0.51      0.51      1292
           4       0.76      0.62      0.69      1293

    accuracy                           0.62      5160
   macro avg       0.63      0.62      0.62      5160
weighted avg       0.63      0.62      0.62      5160

結果は、KNN がテスト セット内の 5160 レコードすべてを 62% の精度で分類できたことを示しています。これは平均を上回っています。 サポートはかなり等しい (データセット内のクラスの均等な分布) ため、重み付けされた F1 と重み付けされていない F1 はほぼ同じになります。

また、4 つのクラスそれぞれのメトリックの結果も確認できます。 そこからわかるのは、 class 2 精度が最低だった recall、および最低 f1-score. Class 3 すぐ後ろです class 2 スコアが最も低いため、次のようになります。 class 1 最高のスコアに続いて class 4.

混同行列を見ると、次のことがわかります。

  • class 1 ほとんど間違えた class 2 238件
  • class 2 for class 1 256 エントリで、 class 3 260件
  • class 3 ほとんど間違えた class 2、374 エントリ、および class 4、193件中
  • class 4 と誤って分類された class 3 339 エントリの場合、および class 2 130の場合。

また、対角線が真の正の値を示していることに注意してください。これを見ると、 class 2 および class 3 正確に予測された値が最も少なくなります。

これらの結果を使用して、分析をさらに詳しく調べて、なぜそれが起こったのかを突き止め、4 つのクラスがデータをビン化する最善の方法であるかどうかを理解することもできます。 おそらくからの値 class 2 および class 3 お互いに近すぎて、見分けるのが難しくなりました。

常に異なる数のビンでデータをテストして、何が起こるかを確認してください。

データ ビンの任意の数に加えて、選択した別の任意の数、K 近傍の数もあります。 メトリック値を最大化または最小化する K の数を決定するときに、回帰タスクに適用したのと同じ手法を分類に適用できます。

KNN 分類に最適な K を見つける

回帰に対して行ったことを繰り返し、K 値のグラフとテスト セットの対応するメトリックをプロットしてみましょう。 コンテキストに適したメトリックを選択することもできます。ここでは、選択します f1-score.

このようにして、 f1-score 1 ~ 40 のすべての K 値に対するテスト セットの予測値。

まず、インポートします f1_score から sklearn.metrics 次に、K 最近傍分類器のすべての予測の値を計算します。ここで、K の範囲は 1 から 40 です。

from sklearn.metrics import f1_score

f1s = []


for i in range(1, 40):
    knn = KNeighborsClassifier(n_neighbors=i)
    knn.fit(X_train, y_train)
    pred_i = knn.predict(X_test)
    
    f1s.append(f1_score(y_test, pred_i, average='weighted'))

次のステップは、 f1_score K 値に対する値。 回帰との違いは、誤差を最小化する K 値を選択する代わりに、今回は誤差を最大化する値を選択することです。 f1-score.

次のスクリプトを実行して、プロットを作成します。

plt.figure(figsize=(12, 6))
plt.plot(range(1, 40), f1s, color='red', linestyle='dashed', marker='o',
         markerfacecolor='blue', markersize=10)
plt.title('F1 Score K Value')
plt.xlabel('K Value')
plt.ylabel('F1 Score')

出力グラフは次のようになります。

Python および Scikit-Learn PlatoBlockchain Data Intelligence の K 最近傍アルゴリズムのガイド。垂直検索。あい。

出力から、 f1-score K の値が 15. 15 個の近傍を使用して分類子を再トレーニングし、分類レポートの結果がどうなるかを見てみましょう。

classifier15 = KNeighborsClassifier(n_neighbors=15)
classifier15.fit(X_train, y_train)
y_pred15 = classifier15.predict(X_test)
print(classification_report(y_test, y_pred15))

これは出力します:

              precision    recall  f1-score   support

           1       0.77      0.79      0.78      1292
           2       0.52      0.58      0.55      1283
           3       0.51      0.53      0.52      1292
           4       0.77      0.64      0.70      1293

    accuracy                           0.63      5160
   macro avg       0.64      0.63      0.64      5160
weighted avg       0.64      0.63      0.64      5160

メトリクスが 15 個のネイバーで改善され、63% 以上の精度が得られていることに注意してください。 precision, recall, f1-scores、しかし、ビンをさらに調べて、なぜ f1-score クラスの場合 2 および 3 まだ低いです。

回帰、ブロック値の決定、分類、ブロック クラスの決定に KNN を使用する以外に、KNN を使用して、ほとんどのブロック値と異なる平均ブロック値 (ほとんどのデータが行っていることに従わないもの) を検出することもできます。 つまり、KNN を次の目的で使用できます。 外れ値の検出.

Scikit-Learn を使用した外れ値検出のための KNN の実装

外れ値の検出 回帰と分類のために以前に行った方法とは異なる別の方法を使用します。

ここでは、各近傍がデータ ポイントからどれだけ離れているかを確認します。 デフォルトの 5 つのネイバーを使用しましょう。 データ ポイントの場合、K 最近隣点のそれぞれまでの距離を計算します。 そのために、Scikit-learn から別の KNN アルゴリズムをインポートします。これは、単純に呼び出される回帰または分類のいずれにも固有のものではありません。 NearestNeighbors.

インポート後、インスタンス化します NearestNeighbors 5 つの近傍を持つクラス – 回帰の例で外れ値を識別するために 12 の近傍でインスタンス化することも、分類の例で同じことを行うために 15 でインスタンス化することもできます。 次に、列車データを適合させ、 kneighbors() 各データポイントと近隣インデックスの計算された距離を見つける方法:

from sklearn.neighbors import NearestNeighbors

nbrs = NearestNeighbors(n_neighbors = 5)
nbrs.fit(X_train)

distances, indexes = nbrs.kneighbors(X_train)

これで、データ ポイントごとに 5 つの距離 (データ ポイントとその 5 つの隣接ポイントの間の距離、およびそれらを識別するインデックス) が得られました。 これをよりよく視覚化するために、最初の XNUMX つの結果と配列の形状を見てみましょう。

最初の XNUMX つの距離形状を見るには、次を実行します。

distances[:3], distances.shape
(array([[0.        , 0.12998939, 0.15157687, 0.16543705, 0.17750354],
        [0.        , 0.25535314, 0.37100754, 0.39090243, 0.40619693],
        [0.        , 0.27149697, 0.28024623, 0.28112326, 0.30420656]]),
 (3, 5))

それぞれ距離が 3 の行が 5 つあることに注意してください。 また、隣人のインデックスを調べることもできます。

indexes[:3], indexes[:3].shape

この結果:

(array([[    0,  8608, 12831,  8298,  2482],
        [    1,  4966,  5786,  8568,  6759],
        [    2, 13326, 13936,  3618,  9756]]),
 (3, 5))

上記の出力では、5 つの隣接ノードのそれぞれのインデックスを確認できます。 ここで、引き続き 5 つの距離の平均を計算し、X 軸に各行をカウントし、Y 軸に各平均距離を表示するグラフをプロットできます。

dist_means = distances.mean(axis=1)
plt.plot(dist_means)
plt.title('Mean of the 5 neighbors distances for each data point')
plt.xlabel('Count')
plt.ylabel('Mean Distances')

Python および Scikit-Learn PlatoBlockchain Data Intelligence の K 最近傍アルゴリズムのガイド。垂直検索。あい。

平均距離が一定の値を持つグラフの部分があることに注意してください。 平均が高すぎず低すぎない Y 軸のポイントは、外れ値を切り捨てるために特定する必要があるポイントです。

この場合、それは平均距離が 3 の場所です。それを見つけることができるように、水平の点線でグラフを再度プロットしてみましょう。

dist_means = distances.mean(axis=1)
plt.plot(dist_means)
plt.title('Mean of the 5 neighbors distances for each data point with cut-off line')
plt.xlabel('Count')
plt.ylabel('Mean Distances')
plt.axhline(y = 3, color = 'r', linestyle = '--')

Python および Scikit-Learn PlatoBlockchain Data Intelligence の K 最近傍アルゴリズムのガイド。垂直検索。あい。

この線は平均距離を示しており、それを超えるとすべての値が変化します。 これは、 mean 上の距離 3 私たちの外れ値です。 を使用して、これらのポイントのインデックスを見つけることができます np.where(). このメソッドは次のいずれかを出力します True or False に関する各インデックスの mean 3上記 調子:

import numpy as np


outlier_index = np.where(dist_means > 3)
outlier_index

上記のコード出力:

(array([  564,  2167,  2415,  2902,  6607,  8047,  8243,  9029, 11892,
        12127, 12226, 12353, 13534, 13795, 14292, 14707]),)

これで、外れ値ポイント インデックスができました。 それらをデータフレームで見つけましょう。


outlier_values = df.iloc[outlier_index]
outlier_values

この結果:

		MedInc 	HouseAge AveRooms 	AveBedrms 	Population 	AveOccup 	Latitude 	Longitude 	MedHouseVal
564 	4.8711 	27.0 	 5.082811 	0.944793 	1499.0 	    1.880803 	37.75 		-122.24 	2.86600
2167 	2.8359 	30.0 	 4.948357 	1.001565 	1660.0 	    2.597809 	36.78 		-119.83 	0.80300
2415 	2.8250 	32.0 	 4.784232 	0.979253 	761.0 	    3.157676 	36.59 		-119.44 	0.67600
2902 	1.1875 	48.0 	 5.492063 	1.460317 	129.0 	    2.047619 	35.38 		-119.02 	0.63800
6607 	3.5164 	47.0 	 5.970639 	1.074266 	1700.0 	    2.936097 	34.18 		-118.14 	2.26500
8047 	2.7260 	29.0 	 3.707547 	1.078616 	2515.0 	    1.977201 	33.84 		-118.17 	2.08700
8243 	2.0769 	17.0 	 3.941667 	1.211111 	1300.0 	    3.611111 	33.78 		-118.18 	1.00000
9029 	6.8300 	28.0 	 6.748744 	1.080402 	487.0 		2.447236 	34.05 		-118.78 	5.00001
11892 	2.6071 	45.0 	 4.225806 	0.903226 	89.0 		2.870968 	33.99 		-117.35 	1.12500
12127 	4.1482 	7.0 	 5.674957 	1.106998 	5595.0 		3.235975 	33.92 		-117.25 	1.24600
12226 	2.8125 	18.0 	 4.962500 	1.112500 	239.0 		2.987500 	33.63 		-116.92 	1.43800
12353 	3.1493 	24.0 	 7.307323 	1.460984 	1721.0 		2.066026 	33.81 		-116.54 	1.99400
13534 	3.7949 	13.0 	 5.832258 	1.072581 	2189.0 		3.530645 	34.17 		-117.33 	1.06300
13795 	1.7567 	8.0 	 4.485173 	1.120264 	3220.0 		2.652389 	34.59 		-117.42 	0.69500
14292 	2.6250 	50.0 	 4.742236 	1.049689 	728.0 		2.260870 	32.74 		-117.13 	2.03200
14707 	3.7167 	17.0 	 5.034130 	1.051195 	549.0 		1.873720 	32.80 		-117.05 	1.80400

外れ値の検出が終了しました。 これは、一般的なデータの傾向から逸脱した各データ ポイントを特定する方法です。 結果を改善するために、さらに調べたり、調査したり、場合によっては処理したり、データから削除したりする (誤って入力された場合) 必要があるトレーニング データには 16 個のポイントがあることがわかります。 これらのポイントは、入力エラー、平均ブロック値の不一致、またはその両方が原因である可能性があります。

KNN の長所と短所

このセクションでは、KNN アルゴリズムを使用することの長所と短所をいくつか紹介します。

メリット

  • 実装は簡単です
  • これは遅延学習アルゴリズムであるため、すべてのデータ ポイントでトレーニングを行う必要はありません (予測には K 最近傍のみを使用します)。 これにより、KNN アルゴリズムは、次のようなデータセット全体でトレーニングを必要とする他のアルゴリズムよりもはるかに高速になります。 サポートベクターマシン, 線形回帰, etc.
  • KNN は予測を行う前にトレーニングを必要としないため、新しいデータをシームレスに追加できます
  • KNN を使用するために必要なパラメーターは XNUMX つだけです。つまり、K の値と距離関数です。

デメリット

  • KNN アルゴリズムは高次元データではうまく機能しません。これは、次元数が多いとポイント間の距離が「奇妙」になり、使用する距離メトリックが維持されないためです。
  • 最後に、KNN アルゴリズムは、カテゴリ特徴では次元間の距離を見つけるのが難しいため、カテゴリ特徴ではうまく機能しません。

さらに進む – ハンドヘルド エンド ツー エンド プロジェクト

Python および Scikit-Learn PlatoBlockchain Data Intelligence の K 最近傍アルゴリズムのガイド。垂直検索。あい。

このガイド付きプロジェクトでは、強力な従来の機械学習モデルとディープ ラーニング モデルを構築し、Ensemble Learning を利用してメタ学習者をトレーニングし、Scikit-Learn および Keras モデルのバッグから住宅価格を予測する方法を学習します。

Tensorflow の上に構築された深層学習 API である Keras を使用して、アーキテクチャを実験し、積み重ねられたモデルのアンサンブルを構築し、 メタ学習者 家の価格を計算するためのニューラル ネットワーク (レベル 1 モデル)。

深層学習は素晴らしいですが、それに頼る前に、次のようなより単純な手法で問題を解決することもお勧めします。 浅い学び アルゴリズム。 私たちのベースラインパフォーマンスは、 ランダム フォレスト回帰 アルゴリズム。 さらに、次のような手法を使用して、Scikit-Learn を介してモデルのアンサンブルを作成することを検討します。 バギング および 投票.

これはエンド ツー エンドのプロジェクトであり、すべての機械学習プロジェクトと同様に、ここから始めます。 探索的データ分析、続いて データの前処理 そして最後に 建物の浅い および ディープラーニングモデル 以前に調査してクリーニングしたデータに合わせます。

まとめ

KNN は単純ですが強力なアルゴリズムです。 回帰、分類、外れ値検出など、多くのタスクに使用できます。

KNN は、ドキュメントの類似性とパターン認識を見つけるために広く使用されています。 また、レコメンダー システムの開発や、コンピューター ビジョンの次元削減と前処理のステップ、特に顔認識タスクにも使用されています。

このガイドでは、Scikit-Learn の K-Nearest Neighbor アルゴリズムの実装を使用して、回帰、分類、外れ値検出について説明しました。

タイムスタンプ:

より多くの スタックアバス