1 Определение
Учитывая обучающие данные, для нового входного экземпляра найдите k экземпляров, ближайших к экземпляру в обучающем наборе.Согласно принципу правила большинства, класс, к которому принадлежит большинство этих k экземпляров, является классом, к которому принадлежит экземпляр к.
Модель: обучающий набор данных для алгоритма k-ближайших соседей сам по себе является моделью.
2 Оценка производительности алгоритмов машинного обучения
Невозможно обучить все наборы данных, необходимо выбрать часть обучающих выборок и часть тестовых выборок и использовать тестовые выборки для проверки производительности.
import numpy as np
def train_test_split(X, y, test_ratio=0.2, seed=None):
"""将数据 X 和 y 按照test_ratio分割成X_train, X_test, y_train, y_test"""
assert X.shape[0] == y.shape[0], \
"the size of X must be equal to the size of y"
assert 0.0 <= test_ratio <= 1.0, \
"test_ration must be valid"
# 如果下次测试要还原上次随机过程,可以设置这个种子
if seed:
np.random.seed(seed)
# 0~len(X)的乱序数,因为需要对(X,y)进行乱序
shuffled_indexes = np.random.permutation(len(X))
test_size = int(len(X) * test_ratio)
test_indexes = shuffled_indexes[:test_size]
train_indexes = shuffled_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
3 Точность классификации:
Количество правильных прогнозов / количество прогнозов
def accuracy_score(y_true, y_predict):
'''计算y_true和y_predict之间的准确率'''
assert y_true.shape[0] == y_predict.shape[0], \
"the size of y_true must be equal to the size of y_predict"
return sum(y_true == y_predict) / len(y_true)
4 Код классификатора КНН
import numpy as np
from math import sqrt
from collections import Counter
from .metrics import accuracy_score
class KNNClassifier:
def __init__(self, k):
"""初始化kNN分类器"""
assert k >= 1, "k must be valid"
self.k = k
self._X_train = None
self._y_train = None
def fit(self, X_train, y_train):
"""根据训练数据集X_train和y_train训练kNN分类器"""
assert X_train.shape[0] == y_train.shape[0], \
"一个样本必须对应一个分类"
assert self.k <= X_train.shape[0], \
"k必须要小于样本数."
self._X_train = X_train
self._y_train = y_train
return self
def predict(self, X_predict):
"""给定待预测数据集X_predict,返回表示X_predict的结果向量"""
assert self._X_train is not None and self._y_train is not None
assert X_predict.shape[1] == self._X_train.shape[1], \
"预测实例要与样本实例的特征个数相同"
y_predict = [self._predict(x) for x in X_predict]
return np.array(y_predict)
def _predict(self, x):
"""给定单个待预测数据x,返回x的预测结果值"""
assert x.shape[0] == self._X_train.shape[1], \
"x为一个预测实例特征行向量,要与样本的特征量相同"
# 与每一个样本的距离集合
distances = [sqrt(np.sum((x_train - x) ** 2)) for x_train in self._X_train]
#distance从小到大排序的索引index
nearest = np.argsort(distances)
topK_y = [self._y_train[i] for i in nearest[:self.k]]
votes = Counter(topK_y)
# 假如topK_y=[1, 1, 1, 1, 1, 0], 则votes = Counter({0: 1, 1: 5}),
#votes.most_common(1) = [(1, 5)],列表里是个元祖votes.most_common(1)[0] = (1,5)
return votes.most_common(1)[0][0]
def score(self, X_test, y_test):
"""根据测试数据集 X_test 和 y_test 确定当前模型的准确度"""
y_predict = self.predict(X_test)
return accuracy_score(y_test, y_predict)
def accuracy_score(y_true, y_predict):
'''计算y_true和y_predict之间的准确率'''
assert y_true.shape[0] == y_predict.shape[0], \
"the size of y_true must be equal to the size of y_predict"
return sum(y_true == y_predict) / len(y_true)
def __repr__(self):
return "KNN(k=%d)" % self.k
5 Гиперпараметры и параметры модели
- Гиперпараметры: параметры, которые необходимо определить перед запуском алгоритма.
- Параметры модели: параметры, полученные в ходе алгоритма.
Алгоритм KNN не имеет параметров модели Гиперпараметры knn:
- 1. Размер значения k
- 2 правила классификации: решение голосования или дистанция
- 3 Гиперпараметр p: Если вы рассчитываете расстояние, какая формула расстояния используется, то есть расстояние Минковского
5.1 Поиск лучшего k
best_score = 0.0
best_k = -1
for k in range(1, 11):
knn_clf = KNeighborsClassifier(n_neighbors=k)
knn_clf.fit(X_train, y_train)
score = knn_clf.score(X_test, y_test)
if score > best_score:
best_k = k
best_score = score
print("best_k =", best_k)
print("best_score =", best_score)
результат операции: лучший_к = 4 лучший_счет = 0,991666666667
Примечание. Если k находится на границе, может быть лучшее значение k. Если результат добавления k равен 10, то может быть лучшее значение k. Он должен принимать значение (10, 20) и проверять его. снова
5.2 Какое правило принятия решения о классификации выбрать?
- Количество слов: синий выигрывает
- Если вы посчитаете расстояние, учтите расстояние: красный: 1, синий: 1/3+1/4=7/12, тогда красный побеждает.
- Есть и польза от решения проблемы равных голосов:
best_score = 0.0
best_k = -1
best_method = ""
# 两种决策规则:个数or距离
for method in ["uniform", "distance"]:
for k in range(1, 11):
knn_clf = KNeighborsClassifier(n_neighbors=k, weights=method)
knn_clf.fit(X_train, y_train)
score = knn_clf.score(X_test, y_test)
if score > best_score:
best_k = k
best_score = score
best_method = method
print("best_method =", best_method)
print("best_k =", best_k)
print("best_score =", best_score)
Результат: лучший_метод = равномерный лучший_к = 4 лучший_счет = 0,991666666667
5.3. Поиск p, соответствующего расстоянию Минковского
best_score = 0.0
best_k = -1
best_p = -1
for k in range(1, 11):
for p in range(1, 6):
knn_clf = KNeighborsClassifier(n_neighbors=k, weights="distance", p=p)
knn_clf.fit(X_train, y_train)
score = knn_clf.score(X_test, y_test)
if score > best_score:
best_k = k
best_p = p
best_score = score
print("best_k =", best_k)
print("best_p =", best_p)
print("best_score =", best_score)
Результат: лучший_к = 3 лучший_р = 2 лучший_счет = 0,988888888889
По умолчанию используется расстояние Минковского, но есть и другие формулы:SCI kit-learn.org/stable/Modu…, например добавление параметров метрики в поиск по сетке
5.4 Поиск по сетке и другие гиперпараметры в kNN
Как пользоваться поиском по сетке: добавить в список несколько словарей
param_grid = [
{
'weights': ['uniform'],
'n_neighbors': [i for i in range(1, 11)]
},
{
'weights': ['distance'],
'n_neighbors': [i for i in range(1, 11)],
'p': [i for i in range(1, 6)]
}
]
Как пользоваться
knn_clf = KNeighborsClassifier()
from sklearn.model_selection import GridSearchCV
grid_search = GridSearchCV(knn_clf, param_grid)
grid_search.fit(X_train, y_train)
返回结果:
GridSearchCV(cv=None, error_score='raise',
estimator=KNeighborsClassifier(algorithm='auto', leaf_size=30, metric='minkowski', metric_params=None, n_jobs=1, n_neighbors=5, p=2, weights='uniform'),
fit_params={}, iid=True, n_jobs=1,
param_grid=[{'weights': ['uniform'], 'n_neighbors': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]}, {'weights': ['distance'], 'n_neighbors': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 'p': [1, 2, 3, 4, 5]}],
pre_dispatch='2*n_jobs', refit=True, return_train_score=True,
scoring=None, verbose=1)
# 获取最好的分类器
grid_search.best_estimator_
结果为:
KNeighborsClassifier(algorithm='auto', leaf_size=30, metric='minkowski',
metric_params=None, n_jobs=1, n_neighbors=3, p=3,
weights='distance')
# 获取最好的准确率
grid_search.best_score_
结果为:
0.98538622129436326
Другие гиперпараметры: проверьте документацию:SCI kit-learn.org/stable/Modu…
6 Нормализация данных
-
Решение: сопоставьте все данные с одинаковым масштабом
-
Нормализация максимального значения: сопоставьте все данные между 0-1 и используйте ее, когда распределение имеет очевидные границы (изображения находятся в диапазоне 0-255, распределение оценок учащихся и т. д.), если границ нет, с ними будет трудно справиться ( например, распределение доходов)
-
Нормализация средней дисперсии: нормализуйте все данные к распределению со средним значением 0 и дисперсией 1.
6.1 Как нормализовать тестовый набор данных
import numpy as np
class StandardScaler:
def __init__(self):
self.mean_ = None
self.scale_ = None
def fit(self, X):
"""根据训练数据集X获得数据的均值和方差"""
assert X.ndim == 2, "The dimension of X must be 2"
self.mean_ = np.array([np.mean(X[:,i]) for i in range(X.shape[1])])
self.scale_ = np.array([np.std(X[:,i]) for i in range(X.shape[1])])
return self
def transform(self, X):
"""将X根据这个StandardScaler进行均值方差归一化处理"""
assert X.ndim == 2, "The dimension of X must be 2"
assert self.mean_ is not None and self.scale_ is not None
assert X.shape[1] == len(self.mean_), \
"每一列对应一个均值"
resX = np.empty(shape=X.shape, dtype=float)
for col in range(X.shape[1]):
resX[:,col] = (X[:,col] - self.mean_[col]) / self.scale_[col]
return resX
Как пользоваться:
from sklearn.preprocessing import StandardScaler
standardScalar = StandardScaler()
standardScalar.fit(X_train)
# 对训练集归一化
X_train = standardScalar.transform(X_train)
# 对测试集归一化
X_test_standard = standardScalar.transform(X_test)
使用归一化后的数据进行knn分类
from sklearn.neighbors import KNeighborsClassifier
knn_clf = KNeighborsClassifier(n_neighbors=3)
knn_clf.fit(X_train, y_train)
knn_clf.score(X_test_standard, y_test)
7 Резюме
Разделите образцы на обучающий набор и тестовый набор -> обработка нормализации данных -> путем оценки точности классификации, используйте поиск по сетке, чтобы определить лучшие гиперпараметры, и возобновите модель
недостаток:
- Самый большой недостаток: низкая эффективность, если обучающая выборка имеет m выборок и n признаков, то для прогнозирования каждых новых данных требуется O(m*n), оптимизация: использовать древовидную структуру: KD-Tree, Ball-Tree и т.д.
- Высокая корреляция данных: при использовании алгоритма трех ближайших соседей, если два прогноза неверны, возникает проблема.
- Результаты предсказания не поддаются интерпретации: можно получить только результаты предсказания, но я не знаю, почему оно в этой категории, и на его основе нельзя открыть новые теории.
- Проклятие размерности: по мере увеличения размерности расстояние между двумя "на первый взгляд похожими" точками становится все больше и больше, решение - уменьшение размерности
Отказ от ответственности: эта статья является моими заметками, а курс взят из MOOC: Python3 Introduction to Machine Learning Classic Algorithms and Applications. Я также хотел бы поблагодарить г-на Бобо за его прекрасное объяснение.
Если вы сочтете это полезным, пожалуйста, обратите внимание на мой официальный аккаунт. Время от времени я буду публиковать свои собственные учебные заметки, материалы по ИИ и идеи. Пожалуйста, оставьте сообщение и исследуйте путь ИИ вместе с вами.