Алгоритм k-ближайших соседей классифицируется путем измерения расстояния между различными собственными значениями.
Принцип алгоритма k-ближайших соседей
Для обучающей выборки с метками, после ввода новых данных без меток, сравнить каждый признак новых данных с признаками, соответствующими данным в выборке, выбрать топ k наиболее похожих данных в выборке данных по алгоритму , и выберите k Классификация с наибольшим количеством вхождений в наиболее похожих данных используется в качестве классификации новых данных.
k-алгоритм ближайшего соседа
Здесь представлен только прогноз одних новых данных, а прогноз нескольких новых данных одновременно будет дан позже.
Предположим, что имеется обучающая выборка X_train (X_train.shape=(10, 2)
), соответствующая метка y_train (y_train.shape=(10,)
, включая 0, 1), использоватьmatplotlib.pyplot
График выглядит следующим образом (зеленые точки представляют маркер 0, красные точки представляют маркер 1):
Есть новые данные: x (x = np.array([3.18557125, 6.03119673])
), нанесенный следующим образом (синие точки):
Сначала рассчитайте расстояние от x до каждой выборки в X_train, используя формулу расстояния Эйлера:
import math
distances = [math.sqrt(np.sum((x_train - x) ** 2)) for x_train in X_train]
Во-вторых, чтобы выполнить операцию возрастания на расстояниях, используйтеnp.argsort()
Метод возвращает отсортированный индекс без какого-либо влияния на порядок исходных данных:
import numpy as np
nearest = np.argsort(distances)
В-третьих, возьмите метки, соответствующие k ближайшим образцам:
topK_y = [y_train[i] for i in nearest[:k]]
Наконец, подсчитайте теги, соответствующие k ближайшим образцам, и найдите прогнозируемую классификацию с наибольшей долей тега, равной x. В этом случае прогнозируемая классификация равна 0:
from collections import Counter
votes = Counter(topK_y)
votes.most_common(1)[0][0]
Оберните приведенный выше код в метод:
import numpy as np
import math
from collections import Counter
def kNN(k, X_train, y_train, x):
distances = [math.sqrt(np.sum((x_train - x) ** 2)) for x_train in X_train]
nearest = np.argsort(distances)
topK_y = [y_train[i] for i in nearest[:k]]
votes = Counter(topK_y)
return votes.most_common(1)[0][0]
Алгоритм k-ближайших соседей в Scikit Learn
Типичный процесс алгоритма машинного обучения заключается в обучении (подгонке) модели из набора обучающих данных с помощью алгоритма машинного обучения и использовании этой модели для прогнозирования результата входного примера.
Для алгоритма k-ближайших соседей это специальный алгоритм без модели, но мы рассматриваем его обучающий набор данных как модель. Вот как это обрабатывается в Scikit Learn.
Алгоритм k-ближайшего соседа, используемый в Scikit Learn
Алгоритм k-neighbor в Scikit Learn находится в модуле Neighbors, а входящий параметр n_neighbors равен 6 во время инициализации, то есть указанному выше k:
from sklearn.neighbors import KNeighborsClassifier
kNN_classifier = KNeighborsClassifier(n_neighbors=6)
fit()
Метод «обучает» классификатор на обучающем наборе данных, который возвращает сам классификатор:
kNN_classifier.fit(X_train, y_train)
predict()
Метод предсказывает результат ввода, и метод требует, чтобы передаваемый тип параметра был матрицей. Поэтому здесь мы сначала делаем xreshape
работать:
X_predict = x.reshape(1, -1)
y_predict = kNN_classifier.predict(X_predict)
Значение y_predict равно 0, что согласуется с результатом метода kNN, реализованного ранее.
Внедрение классификатора KNeighborsClassifier в Scikit Learn
Определите класс KNNClassifier, метод конструктора которого передает параметр k, представляющий количество наиболее похожих данных, выбранных во время прогнозирования:
class KNNClassifier:
def __init__(self, k):
self.k = k
self._X_train = None
self._y_train = None
fit()
метод обучает классификатор и возвращает сам классификатор:
def fit(self, X_train, y_train):
self._X_train = X_train
self._y_train = y_train
return self
predict()
Метод прогнозирует набор данных для проверки, а параметр X_predict имеет тип matrix. Этот метод перебирает X_predict, используя понимание списка, вызывая один раз для каждых тестируемых данных._predict()
метод.
def predict(self, X_predict):
y_predict = [self._predict(x) for x in X_predict]
return np.array(y_predict)
def _predict(self, x):
distances = [math.sqrt(np.sum((x_train - x) ** 2))
for x_train in self._X_train]
nearest = np.argsort(distances)
topK_y = [self._y_train[i] for i in nearest[:self.k]]
votes = Counter(topK_y)
return votes.most_common(1)[0][0]
Точность алгоритма
Проблемы с моделью
Модель обучается на обучающей выборке, заданной выше, но я не знаю, хороша модель или плоха, и есть две проблемы.
- Если модель плоха, прогнозы не те, что нам нужны. При этом в реальных ситуациях получить настоящую этикетку сложно, а протестировать модель невозможно.
- Обучающие выборки не содержали всех меток при обучении модели.
Для первого вопроса определенная доля (например, 20%) данных в выборке обычно используется в качестве тестовых данных, а остальные данные используются в качестве обучающих данных.
Возьмем в качестве примера данные радужной оболочки, представленные в Scikit Learn, которые содержат 150 образцов.
import numpy as np
from sklearn import datasets
iris = datasets.load_iris()
X = iris.data
y = iris.target
Теперь разделите выборку на 20% выборочных тестовых данных и 80% данных обучения масштаба:
test_ratio = 0.2
test_size = int(len(X) * test_ratio)
X_train = X[test_size:]
y_train = y[test_size:]
X_test = X[:test_size]
y_test = y[:test_size]
Используйте X_train и y_train в качестве обучающих данных для обучения модели, а X_test и y_test в качестве тестовых данных для проверки точности модели.
Для второго вопроса возьмите в качестве примера данные радужной оболочки, предоставленные в Scikit Learn, содержание метки y:
array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2])
Обнаружено, что по порядку сохраняются 0, 1 и 2. В процессе разделения выборок на обучающие данные и тестовые данные, если в обучающие данные включены только 0 и 1, такие обучающие данные будут фатальными для обучающей модели. . Следовательно, выборочные данные должны быть предварительно обработаны случайным образом.
np.random.permutation()
Метод передает целое число n и возвращает случайно отсортированный одномерный массив в интервале [0, n). Передача длины X в качестве параметра возвращает случайный массив индексов X:
shuffle_indexes = np.random.permutation(len(X))
Разделите массив рандомизированных индексов на две части: индекс обучающих данных и индекс тестовых данных:
test_ratio = 0.2
test_size = int(len(X) * test_ratio)
test_indexes = shuffle_indexes[:test_size]
train_indexes = shuffle_indexes[test_size:]
Затем данные выборки делятся на обучающие данные и тестовые данные с помощью индекса, состоящего из двух частей:
X_train = X[train_indexes]
y_train = y[train_indexes]
X_test = X[test_indexes]
y_test = y[test_indexes]
Решение этих двух проблем может быть заключено в метод, начальное число представляет собой начальное число случайного числа, которое действует наnp.random
середина:
import numpy as np
def train_test_split(X, y, test_ratio=0.2, seed=None):
if seed:
np.random.seed(seed)
shuffle_indexes = np.random.permutation(len(X))
test_size = int(len(X) * test_ratio)
test_indexes = shuffle_indexes[:test_size]
train_indexes = shuffle_indexes[test_size:]
X_train = X[train_indexes]
y_train = y[train_indexes]
X_test = X[test_indexes]
y_test = y[test_indexes]
return X_train, X_test, y_train, y_test
Упаковано в Scikit Learntrain_test_split()
метод, размещенный в модуле model_selection:
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)
Точность алгоритма
пройти черезtrain_test_split()
После предварительной обработки выборочных данных метод начинает обучать модель и проверяет тестовые данные:
from sklearn.neighbors import KNeighborsClassifier
kNN_classifier = KNeighborsClassifier(n_neighbors=6)
kNN_classifier.fit(X_train, y_train)
y_predict = kNN_classifier.predict(X_test)
y_predict — это результат прогнозирования тестовых данных X_test, в котором число, равное y_test, деленное на число y_test, является правильной скоростью модели, Сравнивая ее с y_test, можно рассчитать правильную скорость модели:
def accuracy_score(y_true, y_predict):
return sum(y_predict == y_true) / len(y_true)
Вызовите этот метод, чтобы вернуть число с плавающей запятой, меньшее или равное 1:
accuracy_score(y_test, y_predict)
Также инкапсулирован в модуль метрик Scikit Learn.accuracy_score()
метод:
from sklearn.metrics import accuracy_score
accuracy_score(y_test, y_predict)
Родительский класс ClassifierMixin класса KNeighborsClassifier в Scikit Learn имеетscore()
метод, который называетсяaccuracy_score()
метод, передайте тестовые данные X_test и y_test в качестве параметров в этот метод, и точность алгоритма может быть рассчитана напрямую.
class ClassifierMixin(object):
def score(self, X, y, sample_weight=None):
from .metrics import accuracy_score
return accuracy_score(y, self.predict(X), sample_weight=sample_weight)
Гиперпараметры
Упомянутое в предыдущей статье k — это своего рода гиперпараметр, а гиперпараметр — это параметр, который необходимо определить перед запуском алгоритма. Алгоритм k-ближайшего соседа в Scikit Learn содержит множество гиперпараметров, которые указываются в конструкторе инициализации:
def __init__(self, n_neighbors=5,
weights='uniform', algorithm='auto', leaf_size=30,
p=2, metric='minkowski', metric_params=None, n_jobs=None,
**kwargs):
# code here
Значение этих гиперпараметров есть в исходниках и официальной документации[scikit-learn.org] описаны.
Преимущества и недостатки алгоритмов
Алгоритм k-ближайших соседей — это относительно простой алгоритм, который имеет свои преимущества, но также и недостатки.
Преимущество в том, что идея проста, но эффект мощный, и он, естественно, подходит для задач с несколькими классификациями.
Недостатком является низкая эффективность, например, если обучающий набор имеет m выборок и n признаков, сложность алгоритма прогнозирования новых данных составляет O (m * n), расстояние между двумя точками также может быть большим, например расстояние между (0,0,0,...,0) и (1,1,1,...,1) (10000 измерений) равно 100.