KNN в Python: пошаговая реализация алгоритма для классификации данных
Для кого эта статья:
- Студенты и начинающие специалисты в области анализа данных и машинного обучения
- Практикующие аналитики и данные ученые, ищущие способы использования KNN в проектах
Преподаватели и исследователи, заинтересованные в объяснении и внедрении алгоритмов машинного обучения
K-Nearest Neighbors (KNN) — один из тех редких алгоритмов машинного обучения, который сочетает в себе математическую элегантность с практической простотой. Представьте: вы можете классифицировать новые данные, просто "спросив мнения" у их ближайших соседей! 🔍 В этой статье мы не просто поговорим о KNN — мы засучим рукава и реализуем этот алгоритм в Python шаг за шагом, превратив теоретические концепции в работающий код. Готовы построить классификатор, который действительно работает на реальных данных?
Погружение в мир алгоритмов машинного обучения — путь от новичка к профессионалу. На Профессии аналитик данных от Skypro вы не только изучите KNN и другие алгоритмы, но и научитесь применять их для решения бизнес-задач. Вместо бездушной теории — практические кейсы и менторская поддержка. Превратите свой интерес к данным в востребованную профессию за 9 месяцев!
Основы алгоритма K-Nearest Neighbors для анализа данных
Алгоритм K-Nearest Neighbors (KNN) — это метод машинного обучения с учителем, который использует принцип "подобное классифицируется подобным". По своей сути, KNN — воплощение интуитивной идеи: если нечто выглядит как утка, плавает как утка и крякает как утка, то это, вероятно, утка. 🦆
Принцип работы KNN удивительно прост:
- Для каждого нового наблюдения алгоритм ищет K ближайших соседей в обучающем наборе данных.
- Для классификации: новая точка получает класс, который встречается чаще всего среди K соседей.
- Для регрессии: значение для новой точки вычисляется как среднее (или взвешенное среднее) значений 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 напрямую зависит от качества предобработки данных — факт, который часто недооценивают новички. 🔧
Начнём с настройки необходимого окружения, импортируя ключевые библиотеки:
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 благодаря своей наглядности и структуре:
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]
Исследуем наши данные, чтобы лучше понимать, с чем работаем:
print(df.head())
print("\nСтатистика по признакам:")
print(df.describe())
Следующий критически важный шаг — масштабирование признаков. KNN использует метрики расстояния, поэтому признаки с большими значениями могут доминировать над признаками с меньшими значениями, искажая результаты:
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
Теперь разделим данные на обучающую и тестовую выборки, чтобы в дальнейшем оценить качество модели:
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 на этих данных, построим график рассеяния:
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 с классическими настройками:
# Создаем классификатор KNN с 5 соседями
knn = KNeighborsClassifier(n_neighbors=5)
# Обучаем модель на тренировочных данных
knn.fit(X_train, y_train)
# Делаем предсказания на тестовых данных
y_pred = 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))
# Матрица ошибок
print("\nМатрица ошибок:")
print(confusion_matrix(y_test, y_pred))
Одно из преимуществ KNN — возможность получать не только метки классов, но и вероятности принадлежности к каждому классу:
# Получаем вероятности для каждого класса
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 разделяет пространство признаков:
# Функция для визуализации границ решений
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:
# Исследуем влияние параметра 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 поддерживает различные метрики расстояния, что делает его гибким инструментом для разных типов данных:
# Сравниваем разные метрики расстояния
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}")
Важно понимать реальных соседей для конкретных наблюдений. Давайте визуализируем это:
# Выберем произвольную точку из тестового набора
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:
# Определяем пространство гиперпараметров для поиска
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_
Теперь, когда у нас есть оптимально настроенная модель, проведём её детальную оценку на тестовой выборке:
# Предсказания на тестовом наборе
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()
Важно понимать, как изменяется качество модели при различных комбинациях гиперпараметров. Визуализируем это для наиболее значимых параметров:
# Извлекаем результаты для разных комбинаций параметров
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 обычно оптимально, выше для больших выборок |
Для оценки устойчивости модели к вариациям в данных используем кросс-валидацию с визуализацией распределения метрик:
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}")
Наконец, для глубокого понимания работы модели, рассмотрим кривую обучения, которая покажет, как размер обучающей выборки влияет на качество предсказаний:
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 применяется в рекомендательных системах, где похожесть объектов играет ключевую роль:
# Пример рекомендательной системы с 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 применяется для классификации заболеваний по симптомам и показателям анализов:
# Пример диагностической системы с 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 может использоваться для распознавания объектов по их визуальным признакам:
# Пример распознавания рукописных цифр с 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 используется для оценки кредитоспособности клиентов и выявления мошеннических транзакций:
# Пример системы определения мошеннических транзакций
# (используем синтетические данные)
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 используется для сегментации клиентов и персонализированных предложений:
# Пример сегментации клиентов для маркетинговых кампаний
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/)