kNN на пальцах
Реализуем kNN с нуля на чистом Python — и поймём его насквозь.
kNN настолько прост, что его легко написать самому без библиотек. Сделаем это пошагово — код запускается, можно экспериментировать.
Шаг 1. Данные с метками
У нас есть точки на плоскости, каждая принадлежит классу A или B. Это обучающая выборка.
Шаг 2. Расстояние
«Ближайший» — значит с наименьшим расстоянием. Берём обычное евклидово расстояние: √((x1−x2)² + (y1−y2)²) — теорема Пифагора, длина отрезка между точками.
Шаг 3. Соседи и голосование
Считаем расстояния от новой точки до всех, сортируем, берём k ближайших и смотрим, какой класс среди них чаще.
# Обучающие точки: (x, y, класс)
points = [
(1.0, 1.0, "A"),
(1.5, 2.0, "A"),
(1.2, 0.8, "A"),
(5.0, 5.0, "B"),
(6.0, 5.5, "B"),
]
# Новая точка, класс которой надо предсказать
new = (5.5, 5.0)
def dist(p, q):
return ((p[0]-q[0])**2 + (p[1]-q[1])**2) ** 0.5
# Расстояние от новой точки до каждой обучающей
scored = []
for x, y, label in points:
d = dist((x, y), new)
scored.append((d, label))
scored.sort() # ближайшие — первыми
k = 3
nearest = scored[:k]
print(f"{k} ближайших соседа:")
for d, label in nearest:
print(f" расстояние={round(d, 2)}, класс={label}")
# Голосование: какой класс встречается чаще
votes = {}
for d, label in nearest:
votes[label] = votes.get(label, 0) + 1
winner = max(votes, key=votes.get)
print("Голоса:", votes)
print("Предсказанный класс:", winner)
Вывод:
3 ближайших соседа:
расстояние=0.5, класс=B
расстояние=0.71, класс=B
расстояние=5.0, класс=A
Голоса: {'B': 2, 'A': 1}
Предсказанный класс: B
Новая точка (5.5, 5.0) попала в скопление класса B — туда её и отнесли двумя голосами против одного.
Почему важен выбор k
Число k — это сколько соседей учитывать.
- Маленькое k (например, 1) — модель чувствительна к шуму: один случайный сосед может всё решить.
- Большое k — модель усредняет, граница сглаживается, но детали теряются.
- Чётное
kв бинарной задаче может дать ничью голосов, поэтому часто берут нечётное.
Хорошее k подбирают экспериментом — проверяя качество на отдельных данных.
Зачем нормализовать признаки
kNN считает расстояния, поэтому признаки с большим размахом давят на результат. Если один признак — возраст (0–100), а другой — зарплата (0–200000), то зарплата перевесит всё расстояние, и возраст почти не учтётся. Решение — привести признаки к одному масштабу (нормализация). Этой подготовке данных посвящён отдельный урок в разделе про данные.
Сильные и слабые стороны kNN
Обратите внимание на любопытную деталь: у kNN нет «обучения» в привычном смысле. Он не подбирает веса и не строит формулу заранее — просто хранит все обучающие точки и считает расстояния в момент предсказания. Такие методы называют «ленивыми»: вся работа откладывается до запроса.
Отсюда плюсы и минусы. Плюс — простота и отсутствие долгого обучения. Минус — на больших данных каждое предсказание медленное, ведь нужно сравниться со всеми точками, и приходится держать в памяти весь датасет. Поэтому kNN хорош для небольших и средних задач с понятной геометрией, но редко применяется там, где объектов миллионы.
Итог
- kNN: посчитать расстояния до всех точек, взять k ближайших, проголосовать за класс.
- Расстояние — обычно евклидово (теорема Пифагора).
- Малое k чувствительно к шуму, большое — сглаживает; нечётное k избегает ничьих.
- Признаки разного масштаба надо нормализовать, иначе расстояние перекосит.