Machine Learning & AI · Chapter 4.9 · Pro level

ML From Scratch in Pure Python (Distance, Nearest Neighbour, Cleaning & Scaling)

Pure Python में ML ख़ुद बनाओ (दूरी, Nearest Neighbour, Cleaning और Scaling)

Libraries like scikit-learn are great, but a pro knows what happens inside. Let's build the famous nearest-neighbour classifier ourselves, in pure Python. Step 1 — clean the data: real data has holes (None = a missing value), so we keep only complete rows with a list comprehension. Step 2 — distance: how far apart are two players [height, weight]? Use the Pythagoras formula from school, √((x1 − x2)² + (y1 − y2)²), which in Python is math.sqrt((a[0] - b[0]) ** 2 + (a[1] - b[1]) ** 2). Step 3 — predict: the closest known example decides the answer (this is KNN with k = 1). Step 4 — feature scaling: if one feature is in grams (thousands) and another goes from 1 to 10, the big numbers dominate the distance. Min-max scaling (v - min) / (max - min) squeezes every feature into 0 to 1, so all features count fairly.

scikit-learn जैसी libraries बढ़िया हैं, पर एक pro जानता है कि अंदर क्या होता है। चलो मशहूर nearest-neighbour classifier ख़ुद pure Python में बनाते हैं। स्टेप 1 — data साफ़ करो: असली data में छेद होते हैं (None = गायब वैल्यू), इसलिए list comprehension से सिर्फ़ पूरी rows रखते हैं। स्टेप 2 — दूरी: दो खिलाड़ी [height, weight] एक-दूसरे से कितनी दूर हैं? स्कूल वाला पाइथागोरस फ़ॉर्मूला √((x1 − x2)² + (y1 − y2)²) लगाओ, जो Python में math.sqrt((a[0] - b[0]) ** 2 + (a[1] - b[1]) ** 2) है। स्टेप 3 — prediction: सबसे पास वाला जाना-पहचाना उदाहरण जवाब तय करता है (यही k = 1 वाला KNN है)। स्टेप 4 — feature scaling: अगर एक feature ग्राम में है (हज़ारों) और दूसरा 1 से 10 तक, तो बड़े नंबर दूरी पर हावी हो जाते हैं। Min-max scaling (v - min) / (max - min) हर feature को 0 से 1 के बीच ले आता है, ताकि सब features बराबर गिने जाएँ।

In the classroom you can run and edit this code in your browser, get hints and mark the chapter as done. क्लास में यह code ब्राउज़र में चलाकर बदल सकते हो।

Words and symbols in this chapter

[p for p in players if None not in p]
Data cleaning: keep only rows without a missing value.
Data cleaning: सिर्फ़ वे rows रखो जिनमें कोई वैल्यू गायब नहीं।
import math / math.sqrt(...)
The math module gives the square root.
math module से square root मिलता है।
(a[0] - b[0]) ** 2
The difference of one feature, squared (** = power).
एक feature का अंतर, उसका वर्ग (** = घात)।
min(clean, key=lambda p: distance(new, p))
Picks the row with the smallest distance.
सबसे कम दूरी वाली row चुनता है।
(v - low) / (high - low)
Min-max scaling: the smallest value becomes 0, the biggest 1.
Min-max scaling: सबसे छोटी वैल्यू 0, सबसे बड़ी 1 बन जाती है।

Ready example

import math

# Each row: [height_cm, weight_kg, role]   (None = missing value)
players = [
    [170, 65, "Batsman"],
    [185, 90, "Bowler"],
    [None, 70, "Batsman"],
    [175, 68, "Batsman"],
    [190, 95, "Bowler"],
    [182, None, "Bowler"],
]

# STEP 1 - Data cleaning: drop rows that have a missing value
clean = [p for p in players if None not in p]
print("Rows kept:", len(clean), "of", len(players))

# STEP 2 - Distance formula (Pythagoras)
def distance(a, b):
    return math.sqrt((a[0] - b[0]) ** 2 + (a[1] - b[1]) ** 2)

# STEP 3 - Nearest neighbour: copy the label of the closest row
def predict(new):
    closest = min(clean, key=lambda p: distance(new, p))
    return closest[2]

print("New player [178, 72] is a", predict([178, 72]))

# STEP 4 - Min-max scaling: squeeze a feature into 0..1
def min_max(values):
    low, high = min(values), max(values)
    return [(v - low) / (high - low) for v in values]

print("Weights scaled:", min_max([p[1] for p in clean]))

What you will see: Memory boxes show the raw data and the cleaned list; the terminal shows the prediction and the scaled weights.

मेमोरी डिब्बों में कच्चा data और साफ़ list दिखेगी; terminal में prediction और scale किए हुए वज़न छपेंगे।

Line by line

clean = [p for p in players if None not in p]
The 2 incomplete rows are dropped: 4 of 6 remain.
2 अधूरी rows हट गईं: 6 में से 4 बचीं।
def distance(a, b): ...
Straight-line distance between two players.
दो खिलाड़ियों के बीच सीधी दूरी।
closest = min(clean, key=lambda p: distance(new, p))
The nearest player is [175, 68] → Batsman.
सबसे पास वाला खिलाड़ी [175, 68] है → Batsman।
min_max([p[1] for p in clean])
Weights 65–95 become 0.0–1.0.
65–95 वाले वज़न 0.0–1.0 बन जाते हैं।

Common mistake

✗ Wrong

math.sqrt(a[0] - b[0] ** 2 + a[1] - b[1] ** 2)

✓ Right

math.sqrt((a[0] - b[0]) ** 2 + (a[1] - b[1]) ** 2)

** runs before -, so put each difference in brackets before squaring it.

** पहले चलता है और - बाद में, इसलिए वर्ग करने से पहले हर अंतर को ब्रैकेट में रखो।

Your task

Make the from-scratch classifier work: drop the rows with None, write the real distance formula and predict the result for [5, 7] — it should be Pass using 4 clean rows.

ख़ुद बनाया classifier चालू करो: None वाली rows हटाओ, असली दूरी का फ़ॉर्मूला लिखो और [5, 7] का नतीजा निकालो — 4 साफ़ rows से Pass आना चाहिए।

  1. Replace clean = students with clean = [s for s in students if None not in s].
    clean = students की जगह clean = [s for s in students if None not in s] लिखो।
  2. In distance() replace return 0 with return math.sqrt((a[0] - b[0]) ** 2 + (a[1] - b[1]) ** 2).
    distance() में return 0 की जगह return math.sqrt((a[0] - b[0]) ** 2 + (a[1] - b[1]) ** 2) लिखो।
  3. Run — you should see Rows used: 4 and Prediction: Pass.
    Run करो — Rows used: 4 और Prediction: Pass दिखना चाहिए।
Starter code for the task
import math

# [study_hours, sleep_hours, result]   (None = data missing)
students = [
    [1, 4, "Fail"],
    [2, 5, "Fail"],
    [None, 6, "Fail"],
    [6, 7, "Pass"],
    [7, 8, "Pass"],
    [5, None, "Pass"],
]

# TODO 1: neeche ki line badlo: clean = [s for s in students if None not in s]
clean = students

def distance(a, b):
    # TODO 2: Pythagoras lagao: return math.sqrt((a[0] - b[0]) ** 2 + (a[1] - b[1]) ** 2)
    return 0

new_student = [5, 7]
closest = min(clean, key=lambda s: distance(new_student, s))
print("Rows used:", len(clean))
print("Closest row:", closest)
print("Prediction:", closest[2])

Do this task in the classroom: your code is checked automatically and you get hints if something is missing.

Recap

Quick quiz

Why do we use min-max scaling before measuring distance?

दूरी नापने से पहले min-max scaling क्यों करते हैं?

  1. To delete missing values
  2. So a feature with big numbers (like grams) does not dominate features with small numbers
  3. To make the list longer
  4. To turn text into numbers
Show the answer

Answer: B (So a feature with big numbers (like grams) does not dominate features with small numbers)

After scaling, every feature goes from 0 to 1, so each one counts fairly in the distance.

Scaling के बाद हर feature 0 से 1 तक होता है, इसलिए दूरी में हर feature बराबर गिना जाता है।

Practice problems for this chapter

Solve them in the Practice Zone, where each answer is checked automatically and two hints are available.