KNN в Python: пошаговая реализация алгоритма для классификации данных

Пройдите тест, узнайте какой профессии подходите
Сколько вам лет
0%
До 18
От 18 до 24
От 25 до 34
От 35 до 44
От 45 до 49
От 50 до 54
Больше 55

Для кого эта статья:

  • Студенты и начинающие специалисты в области анализа данных и машинного обучения
  • Практикующие аналитики и данные ученые, ищущие способы использования KNN в проектах
  • Преподаватели и исследователи, заинтересованные в объяснении и внедрении алгоритмов машинного обучения

    K-Nearest Neighbors (KNN) — один из тех редких алгоритмов машинного обучения, который сочетает в себе математическую элегантность с практической простотой. Представьте: вы можете классифицировать новые данные, просто "спросив мнения" у их ближайших соседей! 🔍 В этой статье мы не просто поговорим о KNN — мы засучим рукава и реализуем этот алгоритм в Python шаг за шагом, превратив теоретические концепции в работающий код. Готовы построить классификатор, который действительно работает на реальных данных?

Погружение в мир алгоритмов машинного обучения — путь от новичка к профессионалу. На Профессии аналитик данных от Skypro вы не только изучите KNN и другие алгоритмы, но и научитесь применять их для решения бизнес-задач. Вместо бездушной теории — практические кейсы и менторская поддержка. Превратите свой интерес к данным в востребованную профессию за 9 месяцев!

Основы алгоритма K-Nearest Neighbors для анализа данных

Алгоритм K-Nearest Neighbors (KNN) — это метод машинного обучения с учителем, который использует принцип "подобное классифицируется подобным". По своей сути, KNN — воплощение интуитивной идеи: если нечто выглядит как утка, плавает как утка и крякает как утка, то это, вероятно, утка. 🦆

Принцип работы KNN удивительно прост:

  1. Для каждого нового наблюдения алгоритм ищет K ближайших соседей в обучающем наборе данных.
  2. Для классификации: новая точка получает класс, который встречается чаще всего среди K соседей.
  3. Для регрессии: значение для новой точки вычисляется как среднее (или взвешенное среднее) значений K соседей.

Ключевой компонент KNN — это понятие "близости" или "расстояния" между точками данных. Существует несколько метрик расстояния, каждая со своими особенностями:

Метрика Формула Преимущества Ограничения
Евклидово расстояние √Σ(x<sub>i</sub> – y<sub>i</sub>)² Интуитивно понятна, эффективна для низкоразмерных данных Чувствительна к масштабу признаков
Манхэттенское расстояние Σx<sub>i</sub> – y<sub>i</sub> Менее чувствительна к выбросам, хороша для категориальных данных Не учитывает корреляцию между признаками
Расстояние Минковского x<sub>i</sub> – y<sub>i</sub><sup>p</sup>)<sup>1/p</sup> Обобщение евклидового (p=2) и манхэттенского (p=1) расстояний Сложнее интерпретировать, требует настройки p

Параметр K в KNN определяет число соседей, которые будут учитываться при классификации. Это важный гиперпараметр, требующий тщательной настройки:

  • Малые значения K (например, 1-3): модель может переобучиться, становясь чувствительной к шуму в данных.
  • Большие значения K (например, >10): модель может недообучиться, теряя способность улавливать сложные паттерны.
  • Оптимальное K: обычно нечётное число (чтобы избежать ничьих при голосовании) и выбирается через кросс-валидацию.

Преимущества KNN не ограничиваются простотой. Алгоритм не делает предположений о распределении данных, что делает его мощным инструментом для сложных наборов данных, где линейные методы могут потерпеть неудачу.

Однако у KNN есть и недостатки. Вычислительная сложность растёт с увеличением объёма данных, поскольку для каждого нового наблюдения необходимо рассчитать расстояния до всех точек обучающей выборки. Кроме того, алгоритм чувствителен к "проклятию размерности" — в многомерных пространствах понятие "близости" становится менее информативным.

Александр Петров, Lead Data Scientist

Помню свой первый проект с KNN — мы создавали систему рекомендаций товаров для интернет-магазина. Казалось бы, простая задача: найти товары, похожие на те, что уже покупал пользователь. Но дьявол, как обычно, скрывался в деталях.

Первая версия алгоритма работала катастрофически медленно — с увеличением базы товаров до 50 000 наименований, время генерации рекомендаций выросло до неприемлемых 3-4 секунд. Проблема оказалась классической для KNN — квадратичный рост вычислений с увеличением обучающей выборки.

Решение пришло после профилирования кода: мы реализовали KD-дерево для эффективного поиска соседей и добавили предварительное уменьшение размерности данных через PCA. Время отклика упало до 200 мс, а точность рекомендаций даже выросла благодаря устранению шума. Этот опыт научил меня важному принципу: теоретическая простота алгоритма не всегда означает его практическую эффективность без дополнительных оптимизаций.

Пошаговый план для смены профессии

Подготовка данных и настройка среды для KNN в Python

Прежде чем погрузиться в реализацию KNN, необходимо подготовить среду разработки и данные. Эффективность KNN напрямую зависит от качества предобработки данных — факт, который часто недооценивают новички. 🔧

Начнём с настройки необходимого окружения, импортируя ключевые библиотеки:

Python
Скопировать код
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.neighbors import KNeighborsClassifier
from sklearn.model_selection import train_test_split, GridSearchCV
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import accuracy_score, classification_report, confusion_matrix

Для демонстрации возьмём классический набор данных Iris, который идеально подходит для иллюстрации работы KNN благодаря своей наглядности и структуре:

Python
Скопировать код
from sklearn.datasets import load_iris

iris = load_iris()
X = iris.data
y = iris.target
feature_names = iris.feature_names
target_names = iris.target_names

# Преобразуем в DataFrame для удобства
df = pd.DataFrame(X, columns=feature_names)
df['species'] = [target_names[i] for i in y]

Исследуем наши данные, чтобы лучше понимать, с чем работаем:

Python
Скопировать код
print(df.head())
print("\nСтатистика по признакам:")
print(df.describe())

Следующий критически важный шаг — масштабирование признаков. KNN использует метрики расстояния, поэтому признаки с большими значениями могут доминировать над признаками с меньшими значениями, искажая результаты:

Python
Скопировать код
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)

Теперь разделим данные на обучающую и тестовую выборки, чтобы в дальнейшем оценить качество модели:

Python
Скопировать код
X_train, X_test, y_train, y_test = train_test_split(
X_scaled, y, test_size=0.3, random_state=42, stratify=y
)

Важно понимать, какие этапы предобработки критичны для KNN, а какие имеют второстепенное значение:

Этап предобработки Важность для KNN Причина
Масштабирование признаков Критично KNN напрямую использует расстояния между точками
Обработка пропусков Критично Пропуски искажают расчёт расстояний
Кодирование категориальных признаков Критично Необходимо для численного расчёта расстояний
Уменьшение размерности Рекомендуется Смягчает "проклятие размерности"
Удаление выбросов Рекомендуется Выбросы могут искажать распределение соседей

Для более сложных наборов данных (не как Iris), потребовалось бы дополнительно:

  • Обработать пропущенные значения (например, через импутацию средними или медианами)
  • Преобразовать категориальные признаки (one-hot encoding или target encoding)
  • Устранить мультиколлинеарность (через отбор признаков или методы разложения)
  • Выявить и обработать выбросы (через методы на основе Z-score или IQR)

Для визуализации данных, которая поможет нам лучше понять, как может работать KNN на этих данных, построим график рассеяния:

Python
Скопировать код
plt.figure(figsize=(12, 5))

# Первые два признака
plt.subplot(1, 2, 1)
for i, species in enumerate(target_names):
indices = y == i
plt.scatter(X[indices, 0], X[indices, 1], label=species)
plt.xlabel(feature_names[0])
plt.ylabel(feature_names[1])
plt.legend()
plt.title('Iris Dataset: Первые два признака')

# Третий и четвёртый признаки
plt.subplot(1, 2, 2)
for i, species in enumerate(target_names):
indices = y == i
plt.scatter(X[indices, 2], X[indices, 3], label=species)
plt.xlabel(feature_names[2])
plt.ylabel(feature_names[3])
plt.legend()
plt.title('Iris Dataset: Третий и четвёртый признаки')

plt.tight_layout()
plt.show()

Эти графики наглядно демонстрируют, почему Iris — хороший кандидат для KNN: классы образуют достаточно компактные кластеры, особенно в пространстве третьего и четвёртого признаков.

Реализация K-NN классификации с помощью библиотеки sklearn

Теперь, когда наши данные подготовлены, перейдём к непосредственной реализации алгоритма K-Nearest Neighbors с использованием библиотеки sklearn. Эта библиотека предоставляет элегантный и эффективный интерфейс для работы с алгоритмами машинного обучения, включая KNN. 🚀

Создадим базовую модель KNN с классическими настройками:

Python
Скопировать код
# Создаем классификатор KNN с 5 соседями
knn = KNeighborsClassifier(n_neighbors=5)

# Обучаем модель на тренировочных данных
knn.fit(X_train, y_train)

# Делаем предсказания на тестовых данных
y_pred = knn.predict(X_test)

Оценим качество нашей модели:

Python
Скопировать код
# Рассчитываем точность модели
accuracy = accuracy_score(y_test, y_pred)
print(f"Точность модели: {accuracy:.4f}")

# Выводим подробный отчёт о классификации
print("\nОтчёт о классификации:")
print(classification_report(y_test, y_pred, target_names=target_names))

# Матрица ошибок
print("\nМатрица ошибок:")
print(confusion_matrix(y_test, y_pred))

Одно из преимуществ KNN — возможность получать не только метки классов, но и вероятности принадлежности к каждому классу:

Python
Скопировать код
# Получаем вероятности для каждого класса
y_proba = knn.predict_proba(X_test)

# Выводим вероятности для первых 5 тестовых экземпляров
print("\nВероятности классов для первых 5 тестовых экземпляров:")
for i in range(5):
print(f"Экземпляр {i+1}: {target_names[0]}: {y_proba[i][0]:.4f}, " +
f"{target_names[1]}: {y_proba[i][1]:.4f}, " +
f"{target_names[2]}: {y_proba[i][2]:.4f}")

Визуализируем границы решений нашего классификатора, чтобы лучше понять, как KNN разделяет пространство признаков:

Python
Скопировать код
# Функция для визуализации границ решений
def plot_decision_boundaries(X, y, classifier, feature_idx=(0, 1)):
h = 0.02 # шаг сетки
x_min, x_max = X[:, feature_idx[0]].min() – 1, X[:, feature_idx[0]].max() + 1
y_min, y_max = X[:, feature_idx[1]].min() – 1, X[:, feature_idx[1]].max() + 1
xx, yy = np.meshgrid(np.arange(x_min, x_max, h),
np.arange(y_min, y_max, h))

# Создаем временный набор данных для предсказаний
X_temp = np.zeros((xx.ravel().shape[0], X.shape[1]))
X_temp[:, feature_idx[0]] = xx.ravel()
X_temp[:, feature_idx[1]] = yy.ravel()

# Получаем предсказания
Z = classifier.predict(X_temp)
Z = Z.reshape(xx.shape)

# Визуализируем результат
plt.contourf(xx, yy, Z, alpha=0.3)
plt.scatter(X[:, feature_idx[0]], X[:, feature_idx[1]], c=y, edgecolors='k', marker='o')
plt.xlabel(feature_names[feature_idx[0]])
plt.ylabel(feature_names[feature_idx[1]])
plt.title(f'Границы решений KNN (K={classifier.n_neighbors})')

# Визуализируем границы решений для первой пары признаков
plt.figure(figsize=(10, 6))
plot_decision_boundaries(X_scaled, y, knn, feature_idx=(0, 1))
plt.show()

# Визуализируем границы решений для второй пары признаков
plt.figure(figsize=(10, 6))
plot_decision_boundaries(X_scaled, y, knn, feature_idx=(2, 3))
plt.show()

Отдельного внимания заслуживает анализ влияния параметра K на качество модели. Давайте сравним точность для различных значений K:

Python
Скопировать код
# Исследуем влияние параметра K
k_values = range(1, 31)
train_scores = []
test_scores = []

for k in k_values:
knn = KNeighborsClassifier(n_neighbors=k)
knn.fit(X_train, y_train)

train_scores.append(knn.score(X_train, y_train))
test_scores.append(knn.score(X_test, y_test))

# Визуализируем результаты
plt.figure(figsize=(10, 6))
plt.plot(k_values, train_scores, 'o-', label='Тренировочная выборка')
plt.plot(k_values, test_scores, 's-', label='Тестовая выборка')
plt.xlabel('Число соседей (K)')
plt.ylabel('Точность')
plt.title('Влияние параметра K на точность модели')
plt.legend()
plt.grid(True)
plt.show()

# Находим оптимальное K
optimal_k = k_values[np.argmax(test_scores)]
print(f"Оптимальное значение K: {optimal_k}")

KNN поддерживает различные метрики расстояния, что делает его гибким инструментом для разных типов данных:

Python
Скопировать код
# Сравниваем разные метрики расстояния
metrics = ['euclidean', 'manhattan', 'minkowski']
metric_scores = []

for metric in metrics:
knn = KNeighborsClassifier(n_neighbors=optimal_k, metric=metric)
knn.fit(X_train, y_train)
score = knn.score(X_test, y_test)
metric_scores.append(score)
print(f"Метрика {metric}: точность = {score:.4f}")

Важно понимать реальных соседей для конкретных наблюдений. Давайте визуализируем это:

Python
Скопировать код
# Выберем произвольную точку из тестового набора
test_point_idx = 10
test_point = X_test[test_point_idx].reshape(1, -1)
test_label = y_test[test_point_idx]

# Найдем K ближайших соседей
knn = KNeighborsClassifier(n_neighbors=optimal_k)
knn.fit(X_train, y_train)
neighbors_indices = knn.kneighbors(test_point, return_distance=False)[0]

# Визуализируем точку и её соседей
plt.figure(figsize=(12, 6))
for feature_idx in [(0, 1), (2, 3)]:
plt.subplot(1, 2, feature_idx[0] // 2 + 1)
# Все точки обучающей выборки
for i, species in enumerate(target_names):
indices = y_train == i
plt.scatter(X_train[indices, feature_idx[0]], X_train[indices, feature_idx[1]], 
label=species, alpha=0.3)

# Выбранная точка
plt.scatter(test_point[0, feature_idx[0]], test_point[0, feature_idx[1]], 
color='red', s=100, edgecolor='k', marker='*', label='Тестовая точка')

# Соседи
for idx in neighbors_indices:
plt.scatter(X_train[idx, feature_idx[0]], X_train[idx, feature_idx[1]], 
color='black', s=80, facecolors='none', marker='o')

plt.xlabel(feature_names[feature_idx[0]])
plt.ylabel(feature_names[feature_idx[1]])
plt.title(f'K={optimal_k} соседей для тестовой точки (признаки {feature_idx[0]+1} и {feature_idx[1]+1})')
if feature_idx == (0, 1):
plt.legend()

plt.tight_layout()
plt.show()

print(f"Истинный класс тестовой точки: {target_names[test_label]}")
print(f"Предсказанный класс: {target_names[knn.predict(test_point)[0]]}")

Мария Соколова, Data Scientist

Когда я только начинала работать в сфере биоинформатики, мы столкнулись с задачей классификации генетических последовательностей для диагностики редких заболеваний. Инженеры уже испробовали нейросети и ансамблевые методы, но результаты были нестабильными из-за небольшой выборки — всего 200 пациентов с подтверждённым диагнозом.

Я предложила использовать KNN, хотя коллеги скептически отнеслись к этой "примитивной" модели. После двух дней работы с данными выяснилось, что ключевую роль играет не сам алгоритм, а предобработка: стандартизация генетических маркеров и правильный выбор метрики расстояния.

Мы реализовали KNN с косинусной метрикой расстояния и k=3, что дало точность 89% на кросс-валидации — на 7% выше, чем у нейросети. Самым ценным оказалась интерпретируемость: врачи могли видеть, на основе каких именно "соседей" (похожих пациентов) модель делает вывод о диагнозе. Эта прозрачность повысила доверие к системе и позволила внедрить её в клиническую практику.

Оптимизация гиперпараметров и оценка точности модели

Точная настройка гиперпараметров KNN — это не просто техническая формальность, а настоящее искусство, влияющее на качество модели. Давайте погрузимся в методологию поиска оптимальных параметров и научно обоснованной оценки производительности. 🧪

Начнём с систематического подхода к выбору гиперпараметров с помощью GridSearchCV:

Python
Скопировать код
# Определяем пространство гиперпараметров для поиска
param_grid = {
'n_neighbors': list(range(1, 31, 2)), # Нечетные значения от 1 до 30
'weights': ['uniform', 'distance'], # Варианты взвешивания соседей
'metric': ['euclidean', 'manhattan', 'minkowski'], # Метрики расстояния
'p': [1, 2, 3] # Параметр для метрики Минковского
}

# Создаем базовую модель
knn = KNeighborsClassifier()

# Настраиваем поиск по сетке с 5-кратной кросс-валидацией
grid_search = GridSearchCV(
knn, param_grid, cv=5, 
scoring='accuracy', n_jobs=-1, verbose=1
)

# Запускаем поиск
grid_search.fit(X_train, y_train)

# Выводим лучшие параметры и результаты
print(f"Лучшие параметры: {grid_search.best_params_}")
print(f"Лучшая точность при кросс-валидации: {grid_search.best_score_:.4f}")

# Сохраняем лучшую модель
best_knn = grid_search.best_estimator_

Теперь, когда у нас есть оптимально настроенная модель, проведём её детальную оценку на тестовой выборке:

Python
Скопировать код
# Предсказания на тестовом наборе
y_pred = best_knn.predict(X_test)

# Метрики качества
accuracy = accuracy_score(y_test, y_pred)
print(f"Точность на тестовой выборке: {accuracy:.4f}")

# Детальный отчёт о классификации
print("\nОтчёт о классификации:")
print(classification_report(y_test, y_pred, target_names=target_names))

# Матрица ошибок с визуализацией
cm = confusion_matrix(y_test, y_pred)
plt.figure(figsize=(8, 6))
plt.imshow(cm, interpolation='nearest', cmap=plt.cm.Blues)
plt.title('Матрица ошибок')
plt.colorbar()
tick_marks = np.arange(len(target_names))
plt.xticks(tick_marks, target_names, rotation=45)
plt.yticks(tick_marks, target_names)

# Добавляем значения в ячейки матрицы
thresh = cm.max() / 2.
for i in range(cm.shape[0]):
for j in range(cm.shape[1]):
plt.text(j, i, format(cm[i, j], 'd'),
horizontalalignment="center",
color="white" if cm[i, j] > thresh else "black")

plt.tight_layout()
plt.ylabel('Истинный класс')
plt.xlabel('Предсказанный класс')
plt.show()

Важно понимать, как изменяется качество модели при различных комбинациях гиперпараметров. Визуализируем это для наиболее значимых параметров:

Python
Скопировать код
# Извлекаем результаты для разных комбинаций параметров
results = pd.DataFrame(grid_search.cv_results_)

# Создаем сводную таблицу для параметров n_neighbors и weights
pivot_table = pd.pivot_table(
results,
values='mean_test_score',
index='param_n_neighbors',
columns='param_weights',
aggfunc=np.mean
)

# Визуализируем результаты
plt.figure(figsize=(12, 6))
for weight in ['uniform', 'distance']:
mask = results['param_weights'] == weight
k_values = results.loc[mask, 'param_n_neighbors'].astype(int)
scores = results.loc[mask, 'mean_test_score']

# Сортируем по k
sorted_indices = np.argsort(k_values)
k_values = k_values.iloc[sorted_indices]
scores = scores.iloc[sorted_indices]

plt.plot(k_values, scores, 'o-', label=f'weights={weight}')

plt.xlabel('Число соседей (K)')
plt.ylabel('Средняя точность при кросс-валидации')
plt.title('Влияние числа соседей и схемы взвешивания на качество модели')
plt.legend()
plt.grid(True)
plt.show()

Для практического применения KNN критически важно понимать компромисс между производительностью и вычислительными затратами:

Параметр Влияние на точность Влияние на скорость Рекомендации по настройке
n_neighbors (K) Нелинейное, зависит от данных Минимальное Начинайте с √n и используйте поиск по сетке
weights Умеренное, зависит от распределения классов Минимальное 'distance' часто лучше для несбалансированных данных
metric Высокое, зависит от структуры данных Умеренное Начинайте с 'euclidean', тестируйте альтернативы
algorithm Никакого (влияет только на скорость) Высокое 'auto' обычно оптимален, 'kd_tree' для низкоразмерных данных
leaf_size Никакого (для алгоритмов на основе деревьев) Умеренное 30-50 обычно оптимально, выше для больших выборок

Для оценки устойчивости модели к вариациям в данных используем кросс-валидацию с визуализацией распределения метрик:

Python
Скопировать код
from sklearn.model_selection import cross_val_score

# Получаем оценки при 10-кратной кросс-валидации
cv_scores = cross_val_score(best_knn, X_scaled, y, cv=10, scoring='accuracy')

# Визуализируем распределение оценок
plt.figure(figsize=(10, 6))
plt.hist(cv_scores, bins=10, edgecolor='black')
plt.axvline(cv_scores.mean(), color='r', linestyle='dashed', linewidth=2, label=f'Среднее: {cv_scores.mean():.4f}')
plt.xlabel('Точность')
plt.ylabel('Частота')
plt.title('Распределение оценок точности при 10-кратной кросс-валидации')
plt.legend()
plt.grid(True, alpha=0.3)
plt.show()

# Выводим статистику по оценкам
print(f"Средняя точность: {cv_scores.mean():.4f}")
print(f"Стандартное отклонение: {cv_scores.std():.4f}")
print(f"Минимальная точность: {cv_scores.min():.4f}")
print(f"Максимальная точность: {cv_scores.max():.4f}")

Наконец, для глубокого понимания работы модели, рассмотрим кривую обучения, которая покажет, как размер обучающей выборки влияет на качество предсказаний:

Python
Скопировать код
from sklearn.model_selection import learning_curve

# Генерируем кривую обучения
train_sizes, train_scores, test_scores = learning_curve(
best_knn, X_scaled, y, cv=5, train_sizes=np.linspace(0.1, 1.0, 10),
scoring='accuracy', n_jobs=-1
)

# Вычисляем средние и стандартные отклонения
train_mean = np.mean(train_scores, axis=1)
train_std = np.std(train_scores, axis=1)
test_mean = np.mean(test_scores, axis=1)
test_std = np.std(test_scores, axis=1)

# Визуализируем кривую обучения
plt.figure(figsize=(10, 6))
plt.grid(True, alpha=0.3)

# График для обучающей выборки
plt.fill_between(train_sizes, train_mean – train_std, train_mean + train_std, alpha=0.1, color="r")
plt.plot(train_sizes, train_mean, 'o-', color="r", label="Точность на обучающей выборке")

# График для проверочной выборки
plt.fill_between(train_sizes, test_mean – test_std, test_mean + test_std, alpha=0.1, color="g")
plt.plot(train_sizes, test_mean, 's-', color="g", label="Точность на проверочной выборке")

plt.xlabel("Размер обучающей выборки")
plt.ylabel("Точность")
plt.title("Кривая обучения для KNN")
plt.legend(loc="best")
plt.show()

Важно отметить, что для больших наборов данных KNN может становиться вычислительно неэффективным. В таких случаях следует рассмотреть аппроксимационные методы, такие как Approximate Nearest Neighbors:

  • Методы на основе деревьев: KD-деревья, Ball-деревья (реализованы в sklearn через параметр algorithm)
  • Locality Sensitive Hashing (LSH): для высокоразмерных данных (библиотека FALCONN)
  • Приближенный поиск соседей: библиотеки Annoy, FAISS, NMSLIB для огромных наборов данных

Правильная оптимизация и оценка KNN требуют баланса между точностью, скоростью и интерпретируемостью. Систематический подход, представленный выше, обеспечивает научную строгость и практическую применимость результатов.

Практические сценарии применения KNN: от теории к практике

Алгоритм K-Nearest Neighbors выходит далеко за рамки учебных примеров и находит применение в самых разнообразных областях. Рассмотрим конкретные практические сценарии, где KNN проявляет свои сильные стороны, и кодовые реализации для этих задач. 💼

Прежде всего, KNN применяется в рекомендательных системах, где похожесть объектов играет ключевую роль:

Python
Скопировать код
# Пример рекомендательной системы с KNN
from sklearn.neighbors import NearestNeighbors

# Предположим, у нас есть матрица "пользователи-товары" с оценками
user_item_matrix = np.array([
[5, 4, 0, 0, 1], # Оценки пользователя 1
[4, 5, 0, 0, 2], # Оценки пользователя 2
[0, 0, 5, 4, 0], # Оценки пользователя 3
[0, 0, 4, 5, 0], # Оценки пользователя 4
[1, 2, 0, 0, 5] # Оценки пользователя 5
])

# Инициализируем модель KNN для поиска похожих пользователей
model_knn = NearestNeighbors(metric='cosine', algorithm='brute')
model_knn.fit(user_item_matrix)

# Для заданного пользователя находим похожих пользователей
query_user_id = 0 # Пользователь, для которого ищем рекомендации
distances, indices = model_knn.kneighbors(
user_item_matrix[query_user_id].reshape(1, -1), 
n_neighbors=3
)

print(f"Наиболее похожие пользователи для пользователя {query_user_id + 1}:")
for i, idx in enumerate(indices[0][1:]): # Пропускаем самого себя
print(f"Пользователь {idx + 1}, сходство: {1 – distances[0][i+1]:.4f}")

# Генерируем рекомендации на основе предпочтений похожих пользователей
def generate_recommendations(user_id, user_item_matrix, model_knn, n_neighbors=3, top_n=2):
distances, indices = model_knn.kneighbors(
user_item_matrix[user_id].reshape(1, -1), 
n_neighbors=n_neighbors + 1
)

# Получаем индексы товаров, которые пользователь еще не оценивал
user_ratings = user_item_matrix[user_id]
unrated_items = np.where(user_ratings == 0)[0]

# Собираем оценки похожих пользователей для неоцененных товаров
item_scores = np.zeros(user_item_matrix.shape[1])
for i, idx in enumerate(indices[0][1:]): # Пропускаем самого пользователя
# Взвешиваем оценки по сходству
similarity = 1 – distances[0][i+1]
item_scores += similarity * user_item_matrix[idx]

# Сортируем товары по предсказанным оценкам
recommended_items = []
for item_id in np.argsort(-item_scores):
if item_id in unrated_items:
recommended_items.append((item_id, item_scores[item_id]))
if len(recommended_items) == top_n:
break

return recommended_items

recommendations = generate_recommendations(query_user_id, user_item_matrix, model_knn)
print("\nРекомендуемые товары:")
for item_id, score in recommendations:
print(f"Товар {item_id + 1}, предсказанная оценка: {score:.2f}")

В медицинской диагностике KNN применяется для классификации заболеваний по симптомам и показателям анализов:

Python
Скопировать код
# Пример диагностической системы с KNN
# (используем синтетические данные для иллюстрации)

# Генерируем синтетический датасет для диагностики диабета
from sklearn.datasets import make_classification

# Создаем синтетические данные с признаками, похожими на медицинские показатели
X_medical, y_medical = make_classification(
n_samples=300, n_features=5, n_informative=3, n_redundant=1,
n_classes=2, random_state=42, weights=[0\.7, 0.3] # Имитируем несбалансированность классов
)

# Имитируем названия медицинских показателей
medical_features = ['Глюкоза', 'ИМТ', 'Возраст', 'Инсулин', 'Кровяное давление']
medical_target = ['Здоров', 'Диабет']

# Разделяем на обучающую и тестовую выборки
X_med_train, X_med_test, y_med_train, y_med_test = train_test_split(
X_medical, y_medical, test_size=0.3, random_state=42, stratify=y_medical
)

# Нормализуем данные
scaler_med = StandardScaler()
X_med_train_scaled = scaler_med.fit_transform(X_med_train)
X_med_test_scaled = scaler_med.transform(X_med_test)

# Применяем KNN с оптимизацией параметров
knn_medical = KNeighborsClassifier(n_neighbors=5, weights='distance')
knn_medical.fit(X_med_train_scaled, y_med_train)

# Оцениваем модель
y_med_pred = knn_medical.predict(X_med_test_scaled)
med_accuracy = accuracy_score(y_med_test, y_med_pred)
print(f"Точность диагностической модели: {med_accuracy:.4f}")
print("\nОтчёт о классификации:")
print(classification_report(y_med_test, y_med_pred, target_names=medical_target))

# Визуализируем важность каждого показателя через анализ чувствительности
def feature_importance_permutation(model, X, y, n_repeats=10):
accuracy = accuracy_score(y, model.predict(X))
importances = []
for i in range(X.shape[1]):
feature_importance = []
for _ in range(n_repeats):
X_permuted = X.copy()
np.random.shuffle(X_permuted[:, i])
accuracy_permuted = accuracy_score(y, model.predict(X_permuted))
feature_importance.append(accuracy – accuracy_permuted)
importances.append(np.mean(feature_importance))
return importances

feature_importances = feature_importance_permutation(knn_medical, X_med_test_scaled, y_med_test)

plt.figure(figsize=(10, 6))
plt.bar(medical_features, feature_importances)
plt.xlabel('Медицинский показатель')
plt.ylabel('Важность (снижение точности при перемешивании)')
plt.title('Важность медицинских показателей для диагностики')
plt.xticks(rotation=45)
plt.tight_layout()
plt.show()

В задачах компьютерного зрения, KNN может использоваться для распознавания объектов по их визуальным признакам:

Python
Скопировать код
# Пример распознавания рукописных цифр с KNN
from sklearn.datasets import load_digits
from sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay

# Загружаем датасет рукописных цифр
digits = load_digits()
X_digits = digits.data
y_digits = digits.target

# Разделяем на обучающую и тестовую выборки
X_digits_train, X_digits_test, y_digits_train, y_digits_test = train_test_split(
X_digits, y_digits, test_size=0.25, random_state=42
)

# Стандартизируем данные
scaler_digits = StandardScaler()
X_digits_train_scaled = scaler_digits.fit_transform(X_digits_train)
X_digits_test_scaled = scaler_digits.transform(X_digits_test)

# Создаем и обучаем модель KNN
knn_digits = KNeighborsClassifier(n_neighbors=7)
knn_digits.fit(X_digits_train_scaled, y_digits_train)

# Оцениваем модель
y_digits_pred = knn_digits.predict(X_digits_test_scaled)
digits_accuracy = accuracy_score(y_digits_test, y_digits_pred)
print(f"Точность распознавания цифр: {digits_accuracy:.4f}")

# Визуализируем матрицу ошибок
cm_digits = confusion_matrix(y_digits_test, y_digits_pred)
disp = ConfusionMatrixDisplay(confusion_matrix=cm_digits)
disp.plot(cmap=plt.cm.Blues)
plt.title('Матрица ошибок для распознавания цифр')
plt.show()

# Визуализируем некоторые ошибки классификации
def plot_misclassified(X, y_true, y_pred, indices):
plt.figure(figsize=(12, 4))
for i, idx in enumerate(indices):
if i >= 5: # Ограничиваемся 5 примерами
break
plt.subplot(1, 5, i+1)
img = X[idx].reshape(8, 8)
plt.imshow(img, cmap='gray')
plt.title(f'Истинная: {y_true[idx]}\nПредсказ: {y_pred[idx]}')
plt.axis('off')
plt.tight_layout()
plt.show()

# Находим индексы ошибочно классифицированных изображений
misclassified = np.where(y_digits_test != y_digits_pred)[0]
plot_misclassified(X_digits_test, y_digits_test, y_digits_pred, misclassified)

В финансовой сфере KNN используется для оценки кредитоспособности клиентов и выявления мошеннических транзакций:

Python
Скопировать код
# Пример системы определения мошеннических транзакций
# (используем синтетические данные)
from sklearn.datasets import make_classification
from sklearn.metrics import roc_auc_score, roc_curve, precision_recall_curve

# Создаем синтетические данные для обнаружения мошенничества
X_fraud, y_fraud = make_classification(
n_samples=1000, n_features=10, n_informative=6, n_redundant=2,
n_classes=2, random_state=42, weights=[0\.95, 0.05] # Сильный дисбаланс классов
)

# Разделяем на обучающую и тестовую выборки
X_fraud_train, X_fraud_test, y_fraud_train, y_fraud_test = train_test_split(
X_fraud, y_fraud, test_size=0.3, random_state=42, stratify=y_fraud
)

# Стандартизируем данные
scaler_fraud = StandardScaler()
X_fraud_train_scaled = scaler_fraud.fit_transform(X_fraud_train)
X_fraud_test_scaled = scaler_fraud.transform(X_fraud_test)

# Создаем и обучаем модель KNN, учитывая дисбаланс классов
knn_fraud = KNeighborsClassifier(n_neighbors=11, weights='distance')
knn_fraud.fit(X_fraud_train_scaled, y_fraud_train)

# Получаем вероятности для ROC-анализа
y_fraud_proba = knn_fraud.predict_proba(X_fraud_test_scaled)[:, 1]

# Рассчитываем и выводим метрики
auc_score = roc_auc_score(y_fraud_test, y_fraud_proba)
print(f"AUC-ROC: {auc_score:.4f}")

# Строим ROC-кривую
fpr, tpr, thresholds = roc_curve(y_fraud_test, y_fraud_proba)
plt.figure(figsize=(10, 6))
plt.plot(fpr, tpr, color='blue', lw=2, label=f'ROC curve (AUC = {auc_score:.4f})')
plt.plot([0, 1], [0, 1], color='gray', lw=1, linestyle='--')
plt.xlim([0\.0, 1.0])
plt.ylim([0\.0, 1.05])
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.title('ROC-кривая для обнаружения мошенничества')
plt.legend(loc="lower right")
plt.grid(True, alpha=0.3)
plt.show()

# Строим PR-кривую, которая лучше для несбалансированных данных
precision, recall, _ = precision_recall_curve(y_fraud_test, y_fraud_proba)
plt.figure(figsize=(10, 6))
plt.plot(recall, precision, color='green', lw=2)
plt.xlabel('Recall')
plt.ylabel('Precision')
plt.title('Precision-Recall кривая для обнаружения мошенничества')
plt.grid(True, alpha=0.3)
plt.show()

В ритейле и маркетинге KNN используется для сегментации клиентов и персонализированных предложений:

Python
Скопировать код
# Пример сегментации клиентов для маркетинговых кампаний
from sklearn.cluster import KMeans
from sklearn.preprocessing import MinMaxScaler

# Создаем синтетические данные, имитирующие поведение клиентов
np.random.seed(42)
n_customers = 200

# Имитируем признаки клиентов: частота покупок, средний чек, время с последней покупки
frequency = np.random.exponential(scale=2, size=n_customers)
monetary = np.rando

**Читайте также**
- [Машинное обучение: как компьютеры учатся без программирования](/python/chto-takoe-mashinnoe-obuchenie-vvedenie/)
- [Обучение с учителем: как машины учатся на примерах данных](/python/chto-takoe-obuchenie-s-uchitelem-v-mashinnom-obuchenii/)
- [Обучение без учителя: мощные методы анализа немаркированных данных](/python/chto-takoe-obuchenie-bez-uchitelya-v-mashinnom-obuchenii/)
- [Молниеносное обучение моделей: от сырых данных к ML-решениям](/python/obuchenie-modelej-s-pomoshyu-sklearn-i-keras/)
- [Типы машинного обучения: гайд по выбору оптимального алгоритма](/python/vidy-i-tipy-mashinnogo-obucheniya/)
- [Математика для машинного обучения: от основ к глубокому пониманию](/python/matematika-dlya-mashinnogo-obucheniya/)
- [Машинное обучение в кибербезопасности: новое оружие защиты](/python/mashinnoe-obuchenie-v-informacionnoj-bezopasnosti/)
- [GPU-революция в машинном обучении: ускорение вычислений в 100 раз](/python/oblachnye-vychisleniya-i-mashinnoe-obuchenie-na-gpu/)
- [Random Forest: от принципов работы до практического применения](/python/random-forest-v-mashinnom-obuchenii/)
- [Google Таблицы и машинное обучение: 5 методов для анализа данных](/python/ispolzovanie-google-tablic-v-mashinnom-obuchenii/)

Проверь как ты усвоил материалы статьи
Пройди тест и узнай насколько ты лучше других читателей
Что такое K-Nearest Neighbors?
1 / 5

Загрузка...