Chain min-max scaling and 1-nearest-neighbor classification by hand. Scale training features using train min/max; scale the query identically; find the nearest scaled training point and return its label. Library: sklearn Pipeline with MinMaxScaler and KNeighborsClassifier(n_neighbors=1). RESULT: predicted label.

By hand

x_train=[0,2,4,8], y_train=['A','A','B','B'], query=5. Scale (range=8): x_scaled=[0.0,0.25,0.5,1.0], q_scaled=0.625. Sq-dists: [0.390625,0.140625,0.015625,0.140625] → nearest=x=4 (index 2, label='B').

naive.py
Replay: real traced execution (multi-file project)
x_train = [0, 2, 4, 8]
y_train = ['A', 'A', 'B', 'B']
query = 5
x_min = min(x_train)
x_max = max(x_train)
x_range = x_max - x_min
x_scaled = []
for x in x_train:
    x_scaled.append((x - x_min) / x_range)
q_scaled = (query - x_min) / x_range
best_i = 0
best_d = (q_scaled - x_scaled[0]) ** 2
for i in range(1, len(x_scaled)):
    d = (q_scaled - x_scaled[i]) ** 2
    if d < best_d:
        best_d = d
        best_i = i
pred = y_train[best_i]
print('RESULT:', repr(pred))
  1. x_train ← [0, 2, 4, 8]

    1x_train = [0, 2, 4, 8]2y_train = ['A', 'A', 'B', 'B']
    values this step[0, 2, 4, 8]x_train
  2. y_train ← ['A', 'A', 'B', 'B']

    1x_train = [0, 2, 4, 8]2y_train = ['A', 'A', 'B', 'B']3query = 5
    values this step['A', 'A', 'B', 'B']y_train
  3. query ← 5

    2y_train = ['A', 'A', 'B', 'B']3query = 54x_min = min(x_train)
    values this step5query
  4. x_min ← 0

    3query = 54x_min = min(x_train)5x_max = max(x_train)
    values this step0x_min
  5. x_max ← 8

    4x_min = min(x_train)5x_max = max(x_train)6x_range = x_max - x_min
    values this step8x_max
  6. x_range ← 8

    5x_max = max(x_train)6x_range = x_max - x_min7x_scaled = []
    values this step8x_range
  7. x_scaled ← []

    6x_range = x_max - x_min7x_scaled = []8for x in x_train:
    values this step[]x_scaled
  8. x ← 0, x_scaled ← [0.0]

    pass 1 of 4
    7x_scaled = []8for x in x_train:9    x_scaled.append((x - x_min) / x_range)10q_scaled = (query - x_min) / x_range
    values this step0x[] [0.0]x_scaled
    All 4 passes — pass 1 is the card above
    passxx_scaled
    10[] [0.0]
    20 2[0.0] [0.0, 0.25]
    32 4[0.0, 0.25] [0.0, 0.25, 0.5]
    44 8[0.0, 0.25, 0.5] [0.0, 0.25, 0.5, 1.0]
  9. for x in x_train:

    7x_scaled = []8for x in x_train:9    x_scaled.append((x - x_min) / x_range)
  10. q_scaled ← 0.625

    9    x_scaled.append((x - x_min) / x_range)10q_scaled = (query - x_min) / x_range11best_i = 0
    values this step0.625q_scaled
  11. best_i ← 0

    10q_scaled = (query - x_min) / x_range11best_i = 012best_d = (q_scaled - x_scaled[0]) ** 2
    values this step0best_i
  12. best_d ← 0.390625

    11best_i = 012best_d = (q_scaled - x_scaled[0]) ** 213for i in range(1, len(x_scaled)):
    values this step0.390625best_d
  13. i ← 1, d ← 0.140625, best_d ← 0.140625, best_i ← 1

    pass 1 of 2
    12best_d = (q_scaled - x_scaled[0]) ** 213for i in range(1, len(x_scaled)):14    d = (q_scaled - x_scaled[i]) ** 215    if d < best_d:16        best_d = d17        best_i = i18pred = y_train[best_i]
    values this step1i0.140625d0.390625 0.140625best_d0 1best_i
  14. i ← 2, d ← 0.015625, best_d ← 0.015625, best_i ← 2

    pass 2 of 2
    12best_d = (q_scaled - x_scaled[0]) ** 213for i in range(1, len(x_scaled)):14    d = (q_scaled - x_scaled[i]) ** 215    if d < best_d:16        best_d = d17        best_i = i18pred = y_train[best_i]
    values this step1 2i0.140625 0.015625d0.140625 0.015625best_d1 2best_i
  15. i ← 3

    12best_d = (q_scaled - x_scaled[0]) ** 213for i in range(1, len(x_scaled)):14    d = (q_scaled - x_scaled[i]) ** 2
    values this step2 3i
  16. d ← 0.140625

    13for i in range(1, len(x_scaled)):14    d = (q_scaled - x_scaled[i]) ** 215    if d < best_d:
    values this step0.015625 0.140625d
  17. if d < best_d:

    14d = (q_scaled - x_scaled[i]) ** 215if d < best_d:16    best_d = d
  18. for i in range(1, len(x_scaled)):

    12best_d = (q_scaled - x_scaled[0]) ** 213for i in range(1, len(x_scaled)):14    d = (q_scaled - x_scaled[i]) ** 2
  19. pred ← 'B'

    17        best_i = i18pred = y_train[best_i]19print('RESULT:', repr(pred))
    values this step'B'pred
  20. stdout ← RESULT: 'B'

    18pred = y_train[best_i]19print('RESULT:', repr(pred))
    values this stepRESULT: 'B'stdout

With scikit-learn

make_pipeline(MinMaxScaler(), KNeighborsClassifier(n_neighbors=1)) chains scaling and classification. fit applies scaling to training data and trains the classifier on scaled features; predict scales new data with the same parameters before classifying.

library.py
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import MinMaxScaler
from sklearn.neighbors import KNeighborsClassifier
from dalib.display import set_display
set_display()

X_train = [[0], [2], [4], [8]]
y_train = ['A', 'A', 'B', 'B']
pipe = make_pipeline(MinMaxScaler(), KNeighborsClassifier(n_neighbors=1))
pipe.fit(X_train, y_train)
scaler = pipe.named_steps['minmaxscaler']
x_sc = [round(float(v), 4) for v in scaler.transform(X_train).flatten()]
q_sc = round(float(scaler.transform([[5]])[0][0]), 4)
print('x_scaled:', x_sc)
print('q_scaled:', q_sc)
print('RESULT:', repr(str(pipe.predict([[5]])[0])))
x_scaled: [0.0, 0.25, 0.5, 1.0]
q_scaled: 0.625
RESULT: 'B'

Implementation notes

  • Scaling at fit time uses train min/max only; those same parameters apply to new data at predict time. Fitting the scaler on train+query together would leak query information into training (data leakage). The pipeline enforces this automatically.
  • (q_scaled - x_scaled[i])**2 is squared distance; for 1-NN with a single feature it is equivalent to abs(q_scaled - x_scaled[i]). Cross-reference: euclidean-distance (ch02) for the multi-feature form.
  • Capstone ties together: min-max-scale (ch01) for the preprocessing step, knn-classify-majority (ch02) for the classification step, and cross-val-fold-manual / compare-two-model-scores (this chapter) for how a fitted pipeline fits into a validation workflow.
  • Same links as pages: min-max scale, KNN classify majority, manual cross-validation fold, and compare two model scores. This page consumes those sibling mechanics instead of re-teaching each one.