一、算法简介
K 近邻 (KNN,K Nearest Neighbours) 是一种分类算法。
算法的思想为:要判断一个东西属于哪一类,看看跟它特征最近似的 K 个东西都属于什么,如果这 K 个东西属于 A 类的最多,那我们就认为未知的那个东西也是 A 类的。其步骤为:
1)计算一个测试数据点与各个训练数据点之间的距离(一般是欧氏距离);
2)按照距离大小对训练数据点进行排序;
3)选取距离最小的 K 个点;
4)确定这 K 个点所在类别的出现频率(即次数);
5)返回这 K 个点中出现频率最高的类别作为测试数据的预测分类
与之前学习的算法不同的是,KNN 属于**“非参数方法”**。也就是说,我们没有假设样本符合什么样的分布情况,没有把分类问题转换为求解参数的过程。
逻辑回归(包括 softmax 回归)的复杂度取决于迭代算法,而 KNN 的时间复杂度为 O (mn),其中 m 为样本维度,n 为样本数量。
可以看出,在运算效率上 KNN 并不占优势。但是逻辑回归由于有较严格的定义,会存在“欠拟合”的情况,所以我们应根据实际需要选择算法。
如图,假设输入特征是二元的,我们把样本数据的特征
(
x
1
,
x
2
)
(x_1,x_2)
(x1,x2) 作为二维平面的点坐标,并用不同形状表示样本的类。那么想要判断点属于哪一类,只要把它也放在平面中,观察离它最近的 K(图中 K = 5)个点,发现三角形最多,于是需要预测的点就可以被认为属于三角形所代表的类。
我们通常使用 “欧氏距离” 来表示两数据点的相近程度。当输入特征为多元时,假设平面中有两点 x = ( x 1 , x 2 , . . . x n ) x = (x_1,x_2,...x_n) x=(x1,x2,...xn) 和 y = ( y 1 , y 2 , . . . y n ) y = (y_1,y_2,...y_n) y=(y1,y2,...yn),其距离为
d i s t a n c e = ∑ i n ( x i − y i ) 2 distance = \sqrt{\sum_i^n(x_i - y_i)^2} distance=i∑n(xi−yi)2
注意:
使用欧氏距离存在一个问题,如果不同特征的值不在一个数量级上,那么数量级大的特征将会对距离产生决定性影响,所以,我们需要先进行「数据预处理」,对特征进行缩放。
二、Python 代码实现
示例数据地址:GitHub - Avik-Jain/100-Days-Of-ML-Code/datasets
1 数据预处理
# 导入库
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
# 导入数据
dataset = pd.read_csv('Social_Network_Ads.csv')
X = dataset.iloc[:, [2, 3]].values
y = dataset.iloc[:, 4].values
# 分割
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.25, random_state = 0)
# 特征缩放
from sklearn.preprocessing import StandardScaler
sc = StandardScaler()
X_train = sc.fit_transform(X_train)
X_test = sc.transform(X_test)
2 使用训练集拟合算法
from sklearn.neighbors import KNeighborsClassifier
classifier = KNeighborsClassifier(n_neighbors = 5, metric = 'minkowski', p = 2)
classifier.fit(X_train, y_train)
3 预测与评价
# 使用测试集预测
y_pred = classifier.predict(X_test)
# 生成混淆矩阵
from sklearn.metrics import confusion_matrix
cm = confusion_matrix(y_test, y_pred)
上述代码是对 KNN 算法的简单测试。感兴趣的同学可以利用这个算法做一些有趣的小项目,比如为约会网站用户判断约会对象是否值得约见、简单的手写数字识别系统等。