Перейти к содержимому

KNNClassifier

KNNClassifier — модель классификации, основанная на идее ближайших соседей.

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

Если среди ближайших соседей больше объектов одного класса, этот класс и становится предсказанием модели.

KNN расшифровывается как k-nearest neighborsk ближайших соседей.

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

  • если рядом больше бульдогов, модель предсказывает бульдог;
  • если рядом больше спаниелей, модель предсказывает спаниель.

Число k задаёт, сколько ближайших соседей учитывается при голосовании.

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

После обучения мы передаём новый объект: собака весом 20 кг и высотой 38 см. Модель находит пять ближайших соседей и выбирает класс большинством голосов.

uses MLABC;
begin
var df := DataFrame.FromCsvText('''
Вес,ВысотаВХолке,Порода
20,33,бульдог
22,34,бульдог
24,35,бульдог
25,36,бульдог
19,35,бульдог
21,35,бульдог
26,34,бульдог
20,36,бульдог
14,39,спаниель
15,40,спаниель
16,41,спаниель
18,42,спаниель
17,43,спаниель
15,38,спаниель
19,40,спаниель
16,40,спаниель
''');
var X := df.ToMatrix(['Вес', 'ВысотаВХолке']);
var target := df.EncodeTarget('Порода');
var y := target.Labels;
var model := new KNNClassifier(5);
model.Fit(X, y);
var example := Vector([20.0, 38.0]);
var pred := model.PredictOne(example);
Println('Предсказанная порода:', target.ClassNames[pred]);
Println('Ближайшие соседи:');
var neigh := model.GetNearestNeighbors(example);
foreach var n in neigh do
Println(target.ClassName(n.Index):10, n.Distance:0:2);
end.

Вывод:

Предсказанная порода: бульдог
Ближайшие соседи:
бульдог 2.00
спаниель 2.24
бульдог 3.16
бульдог 3.16
спаниель 4.47

Здесь GetNearestNeighbors возвращает ближайшие обучающие объекты. Для каждого соседа хранится:

  • Index — номер строки в обучающей таблице;
  • Distance — расстояние от нового объекта до этого соседа.

Метод target.ClassName(n.Index) позволяет получить исходное название класса для строки с номером n.Index.

В примере используется KNNClassifier(5), значит модель смотрит на пять ближайших объектов.

Среди них:

  • три бульдога;
  • два спаниеля.

Поэтому большинство голосов получает класс бульдог, и модель предсказывает именно его.

Чтобы увидеть работу KNN на графике, можно подключить PlotML и нарисовать обучающие точки, новый объект и линии к ближайшим соседям.

uses MLABC, PlotML;
begin
var df := DataFrame.FromCsvText('''
Вес,ВысотаВХолке,Порода
20,33,бульдог
22,34,бульдог
24,35,бульдог
25,36,бульдог
19,35,бульдог
21,35,бульдог
26,34,бульдог
20,36,бульдог
14,39,спаниель
15,40,спаниель
16,41,спаниель
18,42,спаниель
17,43,спаниель
15,38,спаниель
19,40,спаниель
16,40,спаниель
''');
var X := df.ToMatrix(['Вес', 'ВысотаВХолке']);
var target := df.EncodeTarget('Порода');
var y := target.Labels;
var model := new KNNClassifier(5);
model.Fit(X, y);
var example := Vector([20.0, 38.0]);
var neigh := model.GetNearestNeighbors(example);
Plot.XLabel := df.ColumnNames[0];
Plot.YLabel := df.ColumnNames[1];
Plot.Title := 'Бульдоги и спаниели';
Plot.Points(X.Col(0), X.Col(1), y);
var (x0, y0) := (example[0], example[1]);
foreach var n in neigh do
begin
var (x1, y1) := (X[n.Index, 0], X[n.Index, 1]);
var color := Plot.PaletteColor(y[n.Index]);
Plot.Point(x1, y1, color);
Plot.LineGraph([x0, x1], [y0, y1], color);
end;
Plot.Point(x0, y0);
end.
Ближайшие соседи для KNNClassifier

На графике цветные точки — обучающие данные, чёрная точка — новый объект. Линии показывают пять ближайших соседей, которые участвуют в голосовании.

Главный гиперпараметр KNN — количество соседей k.

var model := new KNNClassifier(5);

Если k слишком маленькое, модель может слишком сильно реагировать на случайные отдельные точки. Если k слишком большое, модель начинает усреднять слишком много объектов и может хуже различать локальные группы.

KNN использует расстояния между объектами, поэтому масштаб признаков очень важен.

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

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

  • Очень простая идея: класс выбирается по ближайшим похожим объектам.
  • Хорошо подходит для первых учебных примеров.
  • Можно посмотреть, какие соседи повлияли на решение.
  • Чувствителен к масштабу признаков.
  • Может работать медленнее на больших наборах данных.
  • Лишние или шумные признаки могут заметно ухудшать качество.