---
title: K-Nearest Neighbors (KNN)
date: 2025-04-12T09:08:16Z
modified: 2026-07-10T07:49:07Z
permalink: "https://www.micheledpierri.com/machine-learning/k-nearest-neighbors-knn/"
type: page
status: publish
excerpt: ""
wpid: 1283
featured_image: "https://www.micheledpierri.com/wp-content/uploads/2026/07/ml_knn_.png"
featured_image_alt: Young woman in period dress painting celestial diagrams in an ornate historic library, surrounded by antique books and floating luminous spheres.
timestamp: 2026-07-10T07:49:07Z
tags: []
---

## Introduction

K-nearest Neighbors (KNN) is one of the most powerful and widely used algorithms in Machine Learning. While it can handle classification and regression tasks, it’s primarily used for classification. This focus on classification arises from the availability of more efficient algorithms for regression problems.

## Definition

K-Nearest Neighbors is a non-parametric model that works by finding similarities. It follows a simple principle: in an ideal feature space, similar objects naturally group together. We can identify an object’s category by examining how close it is to other objects.

This is why measuring distances, as covered in the previous chapter, is essential.

The decision boundary marks the line of separation between classes in the feature space.

## Medical Applications

KNN has several important applications in medicine:

Patient diagnosis through comparison of characteristics to identify conditions like diabetes

Classification of skin lesions through image comparison with labeled samples

Analysis of CT scans by comparing them with labeled images to detect cancer

The following medical publications demonstrate the use of this algorithm:

Saini I, Singh D, Khosla A. K-nearest neighbour-based algorithm for P- and T-waves detection and delineation. J Med Eng Technol. 2014 Apr;38(3):115-24. doi: 10.3109/03091902.2014.882424. Epub 2014 Feb 10. PMID: 24506210.

Siddalingappa R, Kanagaraj S. K-nearest-neighbor algorithm to predict the survival time and classification of various stages of oral cancer: a machine learning approach. F1000Res. 2023 Nov 16;11:70. doi: 10.12688/f1000research.75469.2. PMID: 38046542; PMCID: PMC10690040.

Uddin S, Haque I, Lu H, Moni MA, Gide E. Comparative performance analysis of K-nearest neighbour (KNN) algorithm and its different variants for disease prediction. Sci Rep. 2022 Apr 15;12(1):6256. doi: 10.1038/s41598-022-10358-x. PMID: 35428863; PMCID: PMC9012855.

B2

## Indications for Using KNN

KNN doesn’t assume any specific data distribution pattern, making it suitable for non-linear relationships between variables. For example, it works well for tumor classification using radiographic or histological images.

KNN performs best with small datasets, as it becomes less efficient with larger ones.

The algorithm requires numerical and scaled data. If your data uses different scales, you must normalize or standardize it first.

KNN offers intuitive and easily interpretable results, making it accessible even to non-experts in data analysis.

The algorithm works best when classes are clearly separated. For overlapping classes, other classification methods are more appropriate.

## Limitations of Using KNN

With large datasets (n > 100,000), KNN becomes inefficient since it must calculate distances between all observation pairs.

If there are many features, Euclidean distance loses meaning (see curse of dimensionality)

Outliers and anomalous data can significantly affect predictions

The algorithm is slow during prediction because it must compare all data points, making it unsuitable when speed is crucial.

## KNN Application in Python

Like all Machine Learning algorithms, proper dataset preparation is essential:

Features must be numerical, and data must be clean—free of errors, outliers, and missing values

Select only the most relevant features for your prediction task

Split data into training and test sets, typically using an 80:20 or 70:30 ratio

Scale and normalize the data since KNN relies on distance calculations

Using StandardScaler to scale the data

from sklearn.preprocessing import StandardScaler scaler = StandardScaler() X\_train\_scaled = scaler.fit\_transform(X\_train) X\_test\_scaled = scaler.transform(X\_test)```
<span class="line"><span style="color: #FF79C6">from</span><span style="color: #F8F8F2"> sklearn.preprocessing </span><span style="color: #FF79C6">import</span><span style="color: #F8F8F2"> StandardScaler</span></span>
<span class="line"><span style="color: #F8F8F2">scaler </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> StandardScaler()</span></span>
<span class="line"><span style="color: #F8F8F2">X_train_scaled </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> scaler.fit_transform(X_train)</span></span>
<span class="line"><span style="color: #F8F8F2">X_test_scaled </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> scaler.transform(X_test)</span></span>
```

## Choosing the value of K

Selecting an appropriate K value is crucial.

K determines the number of nearest neighbor points used to assign a label to a new data point.

Consider this example: you have existing labeled points (red and blue) and a new green point that needs labeling. With k = 5, if the five closest points include three red and two blue points, the new point will be labeled red, as the majority rule applies. However, if k=2, the two closest points are blue, so the new point would be labeled blue.

![KNN Classification prediction with k=5 or k=2](https://www.micheledpierri.com/wp-content/uploads/2025/04/k_selection-1024x512.png)

A K that’s too small can cause overfitting, making the model oversensitive to noise. Conversely, a K that’s too large leads to underfitting and loss of important details.

To find the best k value, use the elbow method: plot error rates (or accuracy) against increasing k values. You’ll see that as k increases, the error initially decreases but eventually plateaus. The optimal k value occurs at this “elbow” point—where further increases in k yield minimal improvement in error reduction.

![Illustration of elbow method to find the best k value](https://www.micheledpierri.com/wp-content/uploads/2025/04/elbow-1024x512.png)

You can also find the optimal K value using grid search or cross-validation techniques.

## Model’s performance

The model’s performance is evaluated using these metrics:

- Accuracy: The percentage of correct classifications

from sklearn.metrics import accuracy\_score accuracy = accuracy\_score(y\_test, y\_pred) print(f’Accuracy: {accuracy:.2f}’)```
<span class="line"><span style="color: #FF79C6">from</span><span style="color: #F8F8F2"> sklearn.metrics </span><span style="color: #FF79C6">import</span><span style="color: #F8F8F2"> accuracy_score</span></span>
<span class="line"><span style="color: #F8F8F2">accuracy </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> accuracy_score(y_test, y_pred)</span></span>
<span class="line"><span style="color: #8BE9FD">print</span><span style="color: #F8F8F2">(</span><span style="color: #FF79C6">f</span><span style="color: #F1FA8C">'Accuracy: </span><span style="color: #BD93F9">{</span><span style="color: #F8F8F2">accuracy</span><span style="color: #FF79C6">:.2f</span><span style="color: #BD93F9">}</span><span style="color: #F1FA8C">'</span><span style="color: #F8F8F2">)</span></span>
```

- Confusion matrix: A comparison of predicted versus actual classes

from sklearn.metrics import confusion\_matrix import seaborn as sns import matplotlib.pyplot as plt conf\_matrix = confusion\_matrix(y\_test, y\_pred) sns.heatmap(conf\_matrix, annot=True, fmt=’d’, cmap=’Blues’, xticklabels=\[‘No Disease’, ‘Disease’\], yticklabels=\[‘No Disease’, ‘Disease’\]) plt.xlabel(‘Predicted’) plt.ylabel(‘Actual’) plt.title(‘Confusion Matrix’) plt.show()```
<span class="line"><span style="color: #FF79C6">from</span><span style="color: #F8F8F2"> sklearn.metrics </span><span style="color: #FF79C6">import</span><span style="color: #F8F8F2"> confusion_matrix</span></span>
<span class="line"><span style="color: #FF79C6">import</span><span style="color: #F8F8F2"> seaborn </span><span style="color: #FF79C6">as</span><span style="color: #F8F8F2"> sns</span></span>
<span class="line"><span style="color: #FF79C6">import</span><span style="color: #F8F8F2"> matplotlib.pyplot </span><span style="color: #FF79C6">as</span><span style="color: #F8F8F2"> plt</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F8F8F2">conf_matrix </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> confusion_matrix(y_test, y_pred)</span></span>
<span class="line"><span style="color: #F8F8F2">sns.heatmap(conf_matrix, </span><span style="color: #FFB86C; font-style: italic">annot</span><span style="color: #FF79C6">=</span><span style="color: #BD93F9">True</span><span style="color: #F8F8F2">, </span><span style="color: #FFB86C; font-style: italic">fmt</span><span style="color: #FF79C6">=</span><span style="color: #E9F284">'</span><span style="color: #F1FA8C">d</span><span style="color: #E9F284">'</span><span style="color: #F8F8F2">, </span><span style="color: #FFB86C; font-style: italic">cmap</span><span style="color: #FF79C6">=</span><span style="color: #E9F284">'</span><span style="color: #F1FA8C">Blues</span><span style="color: #E9F284">'</span><span style="color: #F8F8F2">, </span><span style="color: #FFB86C; font-style: italic">xticklabels</span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2">[</span><span style="color: #E9F284">'</span><span style="color: #F1FA8C">No Disease</span><span style="color: #E9F284">'</span><span style="color: #F8F8F2">, </span><span style="color: #E9F284">'</span><span style="color: #F1FA8C">Disease</span><span style="color: #E9F284">'</span><span style="color: #F8F8F2">], </span><span style="color: #FFB86C; font-style: italic">yticklabels</span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2">[</span><span style="color: #E9F284">'</span><span style="color: #F1FA8C">No Disease</span><span style="color: #E9F284">'</span><span style="color: #F8F8F2">, </span><span style="color: #E9F284">'</span><span style="color: #F1FA8C">Disease</span><span style="color: #E9F284">'</span><span style="color: #F8F8F2">])</span></span>
<span class="line"><span style="color: #F8F8F2">plt.xlabel(</span><span style="color: #E9F284">'</span><span style="color: #F1FA8C">Predicted</span><span style="color: #E9F284">'</span><span style="color: #F8F8F2">)</span></span>
<span class="line"><span style="color: #F8F8F2">plt.ylabel(</span><span style="color: #E9F284">'</span><span style="color: #F1FA8C">Actual</span><span style="color: #E9F284">'</span><span style="color: #F8F8F2">)</span></span>
<span class="line"><span style="color: #F8F8F2">plt.title(</span><span style="color: #E9F284">'</span><span style="color: #F1FA8C">Confusion Matrix</span><span style="color: #E9F284">'</span><span style="color: #F8F8F2">)</span></span>
<span class="line"><span style="color: #F8F8F2">plt.show()</span></span>
```

- Classification report: Displays precision, recall, and F1 score metrics

from sklearn.metrics import classification\_report print(classification\_report(y\_test, y\_pred)) ```
<span class="line"><span style="color: #FF79C6">from</span><span style="color: #F8F8F2"> sklearn.metrics </span><span style="color: #FF79C6">import</span><span style="color: #F8F8F2"> classification_report</span></span>
<span class="line"><span style="color: #8BE9FD">print</span><span style="color: #F8F8F2">(classification_report(y_test, y_pred))</span></span>
<span class="line"></span>
```

## Complete Python Program

In this program, we implement all the guidelines discussed above.

We begin by creating a sample patient dataset containing three features: age, systolic blood pressure, and cholesterol values.

Each patient record includes a binary label indicating their health status.

We then divide our dataset into training and test portions.

After standardizing the data values,

we train our model using the prepared dataset.

Next, we assess the model’s effectiveness.

Finally, we create a visualization showing the decision boundary between two selected features.

import numpy as np import pandas as pd import matplotlib.pyplot as plt import seaborn as sns from sklearn.model\_selection import train\_test\_split from sklearn.preprocessing import StandardScaler from sklearn.neighbors import KNeighborsClassifier from sklearn.metrics import accuracy\_score, confusion\_matrix, classification\_report from matplotlib.colors import ListedColormap # Generate synthetic medical dataset np.random.seed(42) n\_samples = 300 # Features: Age, Blood Pressure, Cholesterol age = np.random.randint(20, 80, n\_samples) bp = np.random.randint(80, 180, n\_samples) cholesterol = np.random.randint(150, 300, n\_samples) # Target: Disease (0 = No Disease, 1 = Disease) disease = ((age > 50) & (bp > 130) & (cholesterol > 220)).astype(int) # Create DataFrame data = pd.DataFrame({‘Age’: age, ‘Blood Pressure’: bp, ‘Cholesterol’: cholesterol, ‘Disease’: disease}) # Split dataset X = data\[\[‘Age’, ‘Blood Pressure’, ‘Cholesterol’\]\] y = data\[‘Disease’\] X\_train, X\_test, y\_train, y\_test = train\_test\_split(X, y, test\_size=0.2, random\_state=42) # Standardize features scaler = StandardScaler() X\_train\_scaled = scaler.fit\_transform(X\_train) X\_test\_scaled = scaler.transform(X\_test) # Train KNN model knn = KNeighborsClassifier(n\_neighbors=5) knn.fit(X\_train\_scaled, y\_train) # Predictions y\_pred = knn.predict(X\_test\_scaled) # Evaluate performance accuracy = accuracy\_score(y\_test, y\_pred) conf\_matrix = confusion\_matrix(y\_test, y\_pred) # Print classification report print(f’Accuracy: {accuracy:.2f}’) print(classification\_report(y\_test, y\_pred)) # Plot confusion matrix plt.figure(figsize=(6,4)) sns.heatmap(conf\_matrix, annot=True, fmt=’d’, cmap=’Blues’, xticklabels=\[‘No Disease’, ‘Disease’\], yticklabels=\[‘No Disease’, ‘Disease’\]) plt.xlabel(‘Predicted’) plt.ylabel(‘Actual’) plt.title(‘Confusion Matrix’) plt.show() # Decision boundary visualization (2D projection of 3D space) def plot\_decision\_boundary(model, X, y): X = X\[:, \[0, 1\]\] # Use first two features for visualization x\_min, x\_max = X\[:, 0\].min() – 1, X\[:, 0\].max() + 1 y\_min, y\_max = X\[:, 1\].min() – 1, X\[:, 1\].max() + 1 xx, yy = np.meshgrid(np.linspace(x\_min, x\_max, 100), np.linspace(y\_min, y\_max, 100)) Z = model.predict(np.c\_\[xx.ravel(), yy.ravel(), np.zeros(xx.ravel().shape)\]) # Adding a zero column to match dimensions Z = Z.reshape(xx.shape) plt.contourf(xx, yy, Z, alpha=0.3, cmap=ListedColormap(\[‘lightblue’, ‘lightcoral’\])) scatter = plt.scatter(X\[:, 0\], X\[:, 1\], c=y, cmap=ListedColormap(\[‘blue’, ‘red’\]), edgecolors=’k’) plt.xlabel(‘Age’) plt.ylabel(‘Blood Pressure’) plt.title(‘Decision Boundary’) plt.legend(handles=scatter.legend\_elements()\[0\], labels=\[‘No Disease’, ‘Disease’\]) plt.show() plot\_decision\_boundary(knn, X\_train\_scaled, y\_train) ```
<span class="line"><span style="color: #FF79C6">import</span><span style="color: #F8F8F2"> numpy </span><span style="color: #FF79C6">as</span><span style="color: #F8F8F2"> np</span></span>
<span class="line"><span style="color: #FF79C6">import</span><span style="color: #F8F8F2"> pandas </span><span style="color: #FF79C6">as</span><span style="color: #F8F8F2"> pd</span></span>
<span class="line"><span style="color: #FF79C6">import</span><span style="color: #F8F8F2"> matplotlib.pyplot </span><span style="color: #FF79C6">as</span><span style="color: #F8F8F2"> plt</span></span>
<span class="line"><span style="color: #FF79C6">import</span><span style="color: #F8F8F2"> seaborn </span><span style="color: #FF79C6">as</span><span style="color: #F8F8F2"> sns</span></span>
<span class="line"><span style="color: #FF79C6">from</span><span style="color: #F8F8F2"> sklearn.model_selection </span><span style="color: #FF79C6">import</span><span style="color: #F8F8F2"> train_test_split</span></span>
<span class="line"><span style="color: #FF79C6">from</span><span style="color: #F8F8F2"> sklearn.preprocessing </span><span style="color: #FF79C6">import</span><span style="color: #F8F8F2"> StandardScaler</span></span>
<span class="line"><span style="color: #FF79C6">from</span><span style="color: #F8F8F2"> sklearn.neighbors </span><span style="color: #FF79C6">import</span><span style="color: #F8F8F2"> KNeighborsClassifier</span></span>
<span class="line"><span style="color: #FF79C6">from</span><span style="color: #F8F8F2"> sklearn.metrics </span><span style="color: #FF79C6">import</span><span style="color: #F8F8F2"> accuracy_score, confusion_matrix, classification_report</span></span>
<span class="line"><span style="color: #FF79C6">from</span><span style="color: #F8F8F2"> matplotlib.colors </span><span style="color: #FF79C6">import</span><span style="color: #F8F8F2"> ListedColormap</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6272A4"># Generate synthetic medical dataset</span></span>
<span class="line"><span style="color: #F8F8F2">np.random.seed(</span><span style="color: #BD93F9">42</span><span style="color: #F8F8F2">)</span></span>
<span class="line"><span style="color: #F8F8F2">n_samples </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> </span><span style="color: #BD93F9">300</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6272A4"># Features: Age, Blood Pressure, Cholesterol</span></span>
<span class="line"><span style="color: #F8F8F2">age </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> np.random.randint(</span><span style="color: #BD93F9">20</span><span style="color: #F8F8F2">, </span><span style="color: #BD93F9">80</span><span style="color: #F8F8F2">, n_samples)</span></span>
<span class="line"><span style="color: #F8F8F2">bp </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> np.random.randint(</span><span style="color: #BD93F9">80</span><span style="color: #F8F8F2">, </span><span style="color: #BD93F9">180</span><span style="color: #F8F8F2">, n_samples)</span></span>
<span class="line"><span style="color: #F8F8F2">cholesterol </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> np.random.randint(</span><span style="color: #BD93F9">150</span><span style="color: #F8F8F2">, </span><span style="color: #BD93F9">300</span><span style="color: #F8F8F2">, n_samples)</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6272A4"># Target: Disease (0 = No Disease, 1 = Disease)</span></span>
<span class="line"><span style="color: #F8F8F2">disease </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> ((age </span><span style="color: #FF79C6">></span><span style="color: #F8F8F2"> </span><span style="color: #BD93F9">50</span><span style="color: #F8F8F2">) </span><span style="color: #FF79C6">&</span><span style="color: #F8F8F2"> (bp </span><span style="color: #FF79C6">></span><span style="color: #F8F8F2"> </span><span style="color: #BD93F9">130</span><span style="color: #F8F8F2">) </span><span style="color: #FF79C6">&</span><span style="color: #F8F8F2"> (cholesterol </span><span style="color: #FF79C6">></span><span style="color: #F8F8F2"> </span><span style="color: #BD93F9">220</span><span style="color: #F8F8F2">)).astype(</span><span style="color: #8BE9FD; font-style: italic">int</span><span style="color: #F8F8F2">)</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6272A4"># Create DataFrame</span></span>
<span class="line"><span style="color: #F8F8F2">data </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> pd.DataFrame({</span><span style="color: #E9F284">'</span><span style="color: #F1FA8C">Age</span><span style="color: #E9F284">'</span><span style="color: #F8F8F2">: age, </span><span style="color: #E9F284">'</span><span style="color: #F1FA8C">Blood Pressure</span><span style="color: #E9F284">'</span><span style="color: #F8F8F2">: bp, </span><span style="color: #E9F284">'</span><span style="color: #F1FA8C">Cholesterol</span><span style="color: #E9F284">'</span><span style="color: #F8F8F2">: cholesterol, </span><span style="color: #E9F284">'</span><span style="color: #F1FA8C">Disease</span><span style="color: #E9F284">'</span><span style="color: #F8F8F2">: disease})</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6272A4"># Split dataset</span></span>
<span class="line"><span style="color: #F8F8F2">X </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> data[[</span><span style="color: #E9F284">'</span><span style="color: #F1FA8C">Age</span><span style="color: #E9F284">'</span><span style="color: #F8F8F2">, </span><span style="color: #E9F284">'</span><span style="color: #F1FA8C">Blood Pressure</span><span style="color: #E9F284">'</span><span style="color: #F8F8F2">, </span><span style="color: #E9F284">'</span><span style="color: #F1FA8C">Cholesterol</span><span style="color: #E9F284">'</span><span style="color: #F8F8F2">]]</span></span>
<span class="line"><span style="color: #F8F8F2">y </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> data[</span><span style="color: #E9F284">'</span><span style="color: #F1FA8C">Disease</span><span style="color: #E9F284">'</span><span style="color: #F8F8F2">]</span></span>
<span class="line"><span style="color: #F8F8F2">X_train, X_test, y_train, y_test </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> train_test_split(X, y, </span><span style="color: #FFB86C; font-style: italic">test_size</span><span style="color: #FF79C6">=</span><span style="color: #BD93F9">0.2</span><span style="color: #F8F8F2">, </span><span style="color: #FFB86C; font-style: italic">random_state</span><span style="color: #FF79C6">=</span><span style="color: #BD93F9">42</span><span style="color: #F8F8F2">)</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6272A4"># Standardize features</span></span>
<span class="line"><span style="color: #F8F8F2">scaler </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> StandardScaler()</span></span>
<span class="line"><span style="color: #F8F8F2">X_train_scaled </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> scaler.fit_transform(X_train)</span></span>
<span class="line"><span style="color: #F8F8F2">X_test_scaled </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> scaler.transform(X_test)</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6272A4"># Train KNN model</span></span>
<span class="line"><span style="color: #F8F8F2">knn </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> KNeighborsClassifier(</span><span style="color: #FFB86C; font-style: italic">n_neighbors</span><span style="color: #FF79C6">=</span><span style="color: #BD93F9">5</span><span style="color: #F8F8F2">)</span></span>
<span class="line"><span style="color: #F8F8F2">knn.fit(X_train_scaled, y_train)</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6272A4"># Predictions</span></span>
<span class="line"><span style="color: #F8F8F2">y_pred </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> knn.predict(X_test_scaled)</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6272A4"># Evaluate performance</span></span>
<span class="line"><span style="color: #F8F8F2">accuracy </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> accuracy_score(y_test, y_pred)</span></span>
<span class="line"><span style="color: #F8F8F2">conf_matrix </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> confusion_matrix(y_test, y_pred)</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6272A4"># Print classification report</span></span>
<span class="line"><span style="color: #8BE9FD">print</span><span style="color: #F8F8F2">(</span><span style="color: #FF79C6">f</span><span style="color: #F1FA8C">'Accuracy: </span><span style="color: #BD93F9">{</span><span style="color: #F8F8F2">accuracy</span><span style="color: #FF79C6">:.2f</span><span style="color: #BD93F9">}</span><span style="color: #F1FA8C">'</span><span style="color: #F8F8F2">)</span></span>
<span class="line"><span style="color: #8BE9FD">print</span><span style="color: #F8F8F2">(classification_report(y_test, y_pred))</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6272A4"># Plot confusion matrix</span></span>
<span class="line"><span style="color: #F8F8F2">plt.figure(</span><span style="color: #FFB86C; font-style: italic">figsize</span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2">(</span><span style="color: #BD93F9">6</span><span style="color: #F8F8F2">,</span><span style="color: #BD93F9">4</span><span style="color: #F8F8F2">))</span></span>
<span class="line"><span style="color: #F8F8F2">sns.heatmap(conf_matrix, </span><span style="color: #FFB86C; font-style: italic">annot</span><span style="color: #FF79C6">=</span><span style="color: #BD93F9">True</span><span style="color: #F8F8F2">, </span><span style="color: #FFB86C; font-style: italic">fmt</span><span style="color: #FF79C6">=</span><span style="color: #E9F284">'</span><span style="color: #F1FA8C">d</span><span style="color: #E9F284">'</span><span style="color: #F8F8F2">, </span><span style="color: #FFB86C; font-style: italic">cmap</span><span style="color: #FF79C6">=</span><span style="color: #E9F284">'</span><span style="color: #F1FA8C">Blues</span><span style="color: #E9F284">'</span><span style="color: #F8F8F2">, </span><span style="color: #FFB86C; font-style: italic">xticklabels</span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2">[</span><span style="color: #E9F284">'</span><span style="color: #F1FA8C">No Disease</span><span style="color: #E9F284">'</span><span style="color: #F8F8F2">, </span><span style="color: #E9F284">'</span><span style="color: #F1FA8C">Disease</span><span style="color: #E9F284">'</span><span style="color: #F8F8F2">], </span><span style="color: #FFB86C; font-style: italic">yticklabels</span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2">[</span><span style="color: #E9F284">'</span><span style="color: #F1FA8C">No Disease</span><span style="color: #E9F284">'</span><span style="color: #F8F8F2">, </span><span style="color: #E9F284">'</span><span style="color: #F1FA8C">Disease</span><span style="color: #E9F284">'</span><span style="color: #F8F8F2">])</span></span>
<span class="line"><span style="color: #F8F8F2">plt.xlabel(</span><span style="color: #E9F284">'</span><span style="color: #F1FA8C">Predicted</span><span style="color: #E9F284">'</span><span style="color: #F8F8F2">)</span></span>
<span class="line"><span style="color: #F8F8F2">plt.ylabel(</span><span style="color: #E9F284">'</span><span style="color: #F1FA8C">Actual</span><span style="color: #E9F284">'</span><span style="color: #F8F8F2">)</span></span>
<span class="line"><span style="color: #F8F8F2">plt.title(</span><span style="color: #E9F284">'</span><span style="color: #F1FA8C">Confusion Matrix</span><span style="color: #E9F284">'</span><span style="color: #F8F8F2">)</span></span>
<span class="line"><span style="color: #F8F8F2">plt.show()</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6272A4"># Decision boundary visualization (2D projection of 3D space)</span></span>
<span class="line"><span style="color: #FF79C6">def</span><span style="color: #F8F8F2"> </span><span style="color: #50FA7B">plot_decision_boundary</span><span style="color: #F8F8F2">(</span><span style="color: #FFB86C; font-style: italic">model</span><span style="color: #F8F8F2">, </span><span style="color: #FFB86C; font-style: italic">X</span><span style="color: #F8F8F2">, </span><span style="color: #FFB86C; font-style: italic">y</span><span style="color: #F8F8F2">):</span></span>
<span class="line"><span style="color: #F8F8F2">    X </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> X[</span><span style="color: #FF79C6">:</span><span style="color: #F8F8F2">, [</span><span style="color: #BD93F9">0</span><span style="color: #F8F8F2">, </span><span style="color: #BD93F9">1</span><span style="color: #F8F8F2">]]  </span><span style="color: #6272A4"># Use first two features for visualization</span></span>
<span class="line"><span style="color: #F8F8F2">    x_min, x_max </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> X[</span><span style="color: #FF79C6">:</span><span style="color: #F8F8F2">, </span><span style="color: #BD93F9">0</span><span style="color: #F8F8F2">].min() </span><span style="color: #FF79C6">-</span><span style="color: #F8F8F2"> </span><span style="color: #BD93F9">1</span><span style="color: #F8F8F2">, X[</span><span style="color: #FF79C6">:</span><span style="color: #F8F8F2">, </span><span style="color: #BD93F9">0</span><span style="color: #F8F8F2">].max() </span><span style="color: #FF79C6">+</span><span style="color: #F8F8F2"> </span><span style="color: #BD93F9">1</span></span>
<span class="line"><span style="color: #F8F8F2">    y_min, y_max </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> X[</span><span style="color: #FF79C6">:</span><span style="color: #F8F8F2">, </span><span style="color: #BD93F9">1</span><span style="color: #F8F8F2">].min() </span><span style="color: #FF79C6">-</span><span style="color: #F8F8F2"> </span><span style="color: #BD93F9">1</span><span style="color: #F8F8F2">, X[</span><span style="color: #FF79C6">:</span><span style="color: #F8F8F2">, </span><span style="color: #BD93F9">1</span><span style="color: #F8F8F2">].max() </span><span style="color: #FF79C6">+</span><span style="color: #F8F8F2"> </span><span style="color: #BD93F9">1</span></span>
<span class="line"><span style="color: #F8F8F2">    xx, yy </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> np.meshgrid(np.linspace(x_min, x_max, </span><span style="color: #BD93F9">100</span><span style="color: #F8F8F2">), np.linspace(y_min, y_max, </span><span style="color: #BD93F9">100</span><span style="color: #F8F8F2">))</span></span>
<span class="line"><span style="color: #F8F8F2">    Z </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> model.predict(np.c_[xx.ravel(), yy.ravel(), np.zeros(xx.ravel().shape)])  </span><span style="color: #6272A4"># Adding a zero column to match dimensions</span></span>
<span class="line"><span style="color: #F8F8F2">    Z </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> Z.reshape(xx.shape)</span></span>
<span class="line"><span style="color: #F8F8F2">    </span></span>
<span class="line"><span style="color: #F8F8F2">    plt.contourf(xx, yy, Z, </span><span style="color: #FFB86C; font-style: italic">alpha</span><span style="color: #FF79C6">=</span><span style="color: #BD93F9">0.3</span><span style="color: #F8F8F2">, </span><span style="color: #FFB86C; font-style: italic">cmap</span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2">ListedColormap([</span><span style="color: #E9F284">'</span><span style="color: #F1FA8C">lightblue</span><span style="color: #E9F284">'</span><span style="color: #F8F8F2">, </span><span style="color: #E9F284">'</span><span style="color: #F1FA8C">lightcoral</span><span style="color: #E9F284">'</span><span style="color: #F8F8F2">]))</span></span>
<span class="line"><span style="color: #F8F8F2">    scatter </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> plt.scatter(X[</span><span style="color: #FF79C6">:</span><span style="color: #F8F8F2">, </span><span style="color: #BD93F9">0</span><span style="color: #F8F8F2">], X[</span><span style="color: #FF79C6">:</span><span style="color: #F8F8F2">, </span><span style="color: #BD93F9">1</span><span style="color: #F8F8F2">], </span><span style="color: #FFB86C; font-style: italic">c</span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2">y, </span><span style="color: #FFB86C; font-style: italic">cmap</span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2">ListedColormap([</span><span style="color: #E9F284">'</span><span style="color: #F1FA8C">blue</span><span style="color: #E9F284">'</span><span style="color: #F8F8F2">, </span><span style="color: #E9F284">'</span><span style="color: #F1FA8C">red</span><span style="color: #E9F284">'</span><span style="color: #F8F8F2">]), </span><span style="color: #FFB86C; font-style: italic">edgecolors</span><span style="color: #FF79C6">=</span><span style="color: #E9F284">'</span><span style="color: #F1FA8C">k</span><span style="color: #E9F284">'</span><span style="color: #F8F8F2">)</span></span>
<span class="line"><span style="color: #F8F8F2">    plt.xlabel(</span><span style="color: #E9F284">'</span><span style="color: #F1FA8C">Age</span><span style="color: #E9F284">'</span><span style="color: #F8F8F2">)</span></span>
<span class="line"><span style="color: #F8F8F2">    plt.ylabel(</span><span style="color: #E9F284">'</span><span style="color: #F1FA8C">Blood Pressure</span><span style="color: #E9F284">'</span><span style="color: #F8F8F2">)</span></span>
<span class="line"><span style="color: #F8F8F2">    plt.title(</span><span style="color: #E9F284">'</span><span style="color: #F1FA8C">Decision Boundary</span><span style="color: #E9F284">'</span><span style="color: #F8F8F2">)</span></span>
<span class="line"><span style="color: #F8F8F2">    plt.legend(</span><span style="color: #FFB86C; font-style: italic">handles</span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2">scatter.legend_elements()[</span><span style="color: #BD93F9">0</span><span style="color: #F8F8F2">], </span><span style="color: #FFB86C; font-style: italic">labels</span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2">[</span><span style="color: #E9F284">'</span><span style="color: #F1FA8C">No Disease</span><span style="color: #E9F284">'</span><span style="color: #F8F8F2">, </span><span style="color: #E9F284">'</span><span style="color: #F1FA8C">Disease</span><span style="color: #E9F284">'</span><span style="color: #F8F8F2">])</span></span>
<span class="line"><span style="color: #F8F8F2">    plt.show()</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F8F8F2">plot_decision_boundary(knn, X_train_scaled, y_train)</span></span>
<span class="line"></span>
```

![Decision boundary](https://www.micheledpierri.com/wp-content/uploads/2025/04/decision_boundary-1024x768.png)

### Additional Resources

[Wikipedia — k-nearest neighbors algorithm – Wikipedia](https://en.wikipedia.org/wiki/K-nearest_neighbors_algorithm)

[Python Machine Learning – K-nearest neighbors (KNN)](https://www.w3schools.com/python/python_ml_knn.asp)

[KNeighborsClassifier — scikit-learn 1.6.1 documentation](https://scikit-learn.org/stable/modules/generated/sklearn.neighbors.KNeighborsClassifier.html)

### Conclusions

KNN is a powerful algorithm for classification tasks, though less effective for regression. Its strengths lie in its simplicity, non-parametric nature (no assumptions about data distribution), and strong performance with small datasets.

However, the algorithm has limitations—it struggles with large datasets containing many features and shows sensitivity to both scale differences and outliers.