Model Workflow
Fit-Predict Pipeline
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').
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))
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_trainy_train ← ['A', 'A', 'B', 'B']
1x_train = [0, 2, 4, 8]2y_train = ['A', 'A', 'B', 'B']3query = 5values this step['A', 'A', 'B', 'B']y_trainquery ← 5
2y_train = ['A', 'A', 'B', 'B']3query = 54x_min = min(x_train)values this step5queryx_min ← 0
3query = 54x_min = min(x_train)5x_max = max(x_train)values this step0x_minx_max ← 8
4x_min = min(x_train)5x_max = max(x_train)6x_range = x_max - x_minvalues this step8x_maxx_range ← 8
5x_max = max(x_train)6x_range = x_max - x_min7x_scaled = []values this step8x_rangex_scaled ← []
6x_range = x_max - x_min7x_scaled = []8for x in x_train:values this step[]x_scaledx ← 0, x_scaled ← [0.0]
pass 1 of 47x_scaled = []8for x in x_train:9 x_scaled.append((x - x_min) / x_range)10q_scaled = (query - x_min) / x_rangevalues this step0x[] → [0.0]x_scaledAll 4 passes — pass 1 is the card above pass xx_scaled1 0 [] → [0.0] 2 0 → 2 [0.0] → [0.0, 0.25] 3 2 → 4 [0.0, 0.25] → [0.0, 0.25, 0.5] 4 4 → 8 [0.0, 0.25, 0.5] → [0.0, 0.25, 0.5, 1.0] for x in x_train:
7x_scaled = []8for x in x_train:9 x_scaled.append((x - x_min) / x_range)q_scaled ← 0.625
9 x_scaled.append((x - x_min) / x_range)10q_scaled = (query - x_min) / x_range11best_i = 0values this step0.625q_scaledbest_i ← 0
10q_scaled = (query - x_min) / x_range11best_i = 012best_d = (q_scaled - x_scaled[0]) ** 2values this step0best_ibest_d ← 0.390625
11best_i = 012best_d = (q_scaled - x_scaled[0]) ** 213for i in range(1, len(x_scaled)):values this step0.390625best_di ← 1, d ← 0.140625, best_d ← 0.140625, best_i ← 1
pass 1 of 212best_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_ii ← 2, d ← 0.015625, best_d ← 0.015625, best_i ← 2
pass 2 of 212best_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_ii ← 3
12best_d = (q_scaled - x_scaled[0]) ** 213for i in range(1, len(x_scaled)):14 d = (q_scaled - x_scaled[i]) ** 2values this step2 → 3id ← 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.140625dif d < best_d:
14d = (q_scaled - x_scaled[i]) ** 215if d < best_d:16 best_d = dfor 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]) ** 2pred ← 'B'
17 best_i = i18pred = y_train[best_i]19print('RESULT:', repr(pred))values this step'B'predstdout ← 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.
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])**2is squared distance; for 1-NN with a single feature it is equivalent toabs(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, andcross-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.