ROC Curves
K-NN
Scikit Learn
Python
Machine Learning

Implementing ROC Curves for K-NN machine learning algorithm using python and Scikit Learn

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

A ROC curve shows how a classifier behaves across many decision thresholds instead of only one final predicted label. For k-nearest neighbors in scikit-learn, the important detail is that ROC curves need a continuous score such as class probability or decision strength, not just hard class predictions.

Why ROC Needs Scores, Not Labels

The ROC curve plots:

  • true positive rate
  • false positive rate

at many thresholds. If you only use predicted labels such as 0 or 1, you get at most one operating point, not a useful curve.

With KNeighborsClassifier, the usual score source is predict_proba(), which returns estimated class probabilities based on the neighbor votes.

A Complete Binary Classification Example

python
1from sklearn.datasets import load_breast_cancer
2from sklearn.model_selection import train_test_split
3from sklearn.neighbors import KNeighborsClassifier
4from sklearn.metrics import roc_curve, roc_auc_score
5import matplotlib.pyplot as plt
6
7X, y = load_breast_cancer(return_X_y=True)
8
9X_train, X_test, y_train, y_test = train_test_split(
10    X, y, test_size=0.3, random_state=42, stratify=y
11)
12
13model = KNeighborsClassifier(n_neighbors=7)
14model.fit(X_train, y_train)
15
16y_score = model.predict_proba(X_test)[:, 1]
17
18fpr, tpr, thresholds = roc_curve(y_test, y_score)
19auc = roc_auc_score(y_test, y_score)
20
21plt.plot(fpr, tpr, label=f"KNN ROC AUC = {auc:.3f}")
22plt.plot([0, 1], [0, 1], linestyle="--", color="gray")
23plt.xlabel("False Positive Rate")
24plt.ylabel("True Positive Rate")
25plt.title("ROC Curve for KNN")
26plt.legend()
27plt.show()

The critical line is:

python
y_score = model.predict_proba(X_test)[:, 1]

That selects the probability of the positive class, which ROC functions need for a binary problem.

Interpreting the Curve

The ROC curve describes the tradeoff between sensitivity and false alarms as the threshold changes.

Some practical interpretations:

  • a curve near the diagonal indicates weak discrimination
  • a curve closer to the upper-left corner indicates stronger discrimination
  • AUC near 1.0 is better than AUC near 0.5

For k-NN, the shape depends on:

  • the value of k
  • feature scaling
  • class overlap
  • data dimensionality

Because k-NN is distance-based, preprocessing often matters as much as the ROC calculation itself.

Feature Scaling Matters for K-NN

ROC is an evaluation method, but k-NN model quality depends heavily on distance computations. If one feature has a much larger numeric range than others, it can dominate neighbor selection.

A more realistic pipeline uses scaling:

python
1from sklearn.pipeline import make_pipeline
2from sklearn.preprocessing import StandardScaler
3from sklearn.neighbors import KNeighborsClassifier
4
5model = make_pipeline(
6    StandardScaler(),
7    KNeighborsClassifier(n_neighbors=7)
8)
9
10model.fit(X_train, y_train)
11y_score = model.predict_proba(X_test)[:, 1]

Without scaling, you may be measuring a weakly configured model rather than the real capability of k-NN on the dataset.

Multi-Class Note

ROC is simplest in binary classification. For multi-class k-NN, scikit-learn typically uses one-vs-rest evaluation and computes one ROC curve per class, or macro and micro averages. The core idea stays the same, but the setup is more involved because there is no single universal positive class.

If your problem is binary, keep it binary for the first implementation.

Common Pitfalls

The biggest mistake is passing model.predict(X_test) into roc_curve(). Predicted labels do not provide the threshold sweep ROC needs.

Another mistake is using the wrong probability column. In binary classification, predict_proba() returns one column per class, and you usually want the probability for the positive class.

People also forget scaling with k-NN, which can make the ROC curve look worse for reasons unrelated to ROC itself.

Finally, ROC can look optimistic on imbalanced datasets. In those cases, precision-recall curves may also be worth inspecting.

Summary

  • ROC curves for k-NN require probabilities or scores, not hard class labels.
  • In scikit-learn, use predict_proba()[:, 1] for the positive class in binary problems.
  • 'roc_curve() gives the threshold sweep and roc_auc_score() summarizes it.'
  • Feature scaling usually matters a lot for k-NN performance.
  • For imbalanced data, ROC is useful, but precision-recall analysis can add context.

Course illustration
Course illustration

All Rights Reserved.