机器学习入门:K近邻算法(KNN)原理与实践
机器学习入门:K近邻算法(KNN)原理与实践
KNN(K-Nearest Neighbor)算法是机器学习中一个非常基础且直观的分类算法。它通过测量不同特征值之间的距离来判断各个数据点之间的相似性,从而实现对新数据点的分类。本文将从KNN算法的基本原理出发,详细讲解其工作流程、距离度量方法、数据预处理技巧以及K值选择策略,帮助读者全面理解这一经典算法。
1. 为什么学习KNN算法
KNN是监督学习分类算法,主要解决现实生活中分类问题。根据目标的不同将监督学习任务分为了分类学习及回归预测问题。
KNN(K-Nearest Neihbor,KNN)K近邻是机器学习算法中理论最简单,最好理解的算法,是一个非常适合入门的算法,拥有如下特性:
- 思想极度简单,应用数学知识少(近乎为零),对于很多不擅长数学的小伙伴十分友好
- 虽然算法简单,但效果也不错
2. KNN 原理
上图中每一个数据点代表一个肿瘤病历:
- 横轴表示肿瘤大小,纵轴表示发现时间
- 恶性肿瘤用蓝色表示,良性肿瘤用红色表示
疑问:新来了一个病人(下图绿色的点),如何判断新来的病人(即绿色点)是良性肿瘤还是恶性肿瘤?
解决方法:k-近邻算法的做法如下:
(1)取一个值k=3(k值后面介绍,现在可以理解为算法的使用者根据经验取的最优值)
(2)在所有的点中找到距离绿色点最近的三个点
(3)让最近的点所属的类别进行投票
(4)最近的三个点都是蓝色的,所以该病人对应的应该也是蓝色,即恶性肿瘤。
3. 距离度量方法
机器学习算法中,经常需要判断两个样本之间是否相似,比如KNN,K-means,推荐算法中的协同过滤等等,常用的套路是将相似的判断转换成距离的计算,距离近的样本相似程度高,距离远的相似程度低。所以度量距离是很多算法中的关键步骤。
KNN算法中要求数据的所有特征都用数值表示。若在数据特征中存在非数值类型,必须采用手段将其进行量化为数值。
比如样本特征中包含有颜色(红、绿、蓝)一项,颜色之间没有距离可言,可通过将颜色转化为灰度值来实现距离计算。
每个特征都用数值表示,样本之间就可以计算出彼此的距离来
3.1 欧式距离
3.2 曼哈顿距离
3.3 切比雪夫距离(了解)
3.4 闵式距离
闵氏距离不是一种距离,而是一组距离的定义,是对多个距离度量公式的概括性的表述。
其中p是一个变参数:
当 p=1 时,就是曼哈顿距离;
当 p=2 时,就是欧氏距离;
当 p→∞ 时,就是切比雪夫距离。
根据 p 的不同,闵氏距离可以表示某一类/种的距离。
4. 归一化和标准化
样本中有多个特征,每一个特征都有自己的定义域和取值范围,他们对距离计算也是不同的,如取值较大的影响力会盖过取值较小的参数。因此,为了公平,样本参数必须做一些归一化处理,将不同的特征都缩放到相同的区间或者分布内。
4.1 归一化
from sklearn.preprocessing import MinMaxScaler
# 1. 准备数据
data = [[90, 2, 10, 40],
[60, 4, 15, 45],
[75, 3, 13, 46]]
# 2. 初始化归一化对象
transformer = MinMaxScaler()
# 3. 对原始特征进行变换
data = transformer.fit_transform(data)
# 4. 打印归一化后的结果
print(data)
归一化受到最大值与最小值的影响,这种方法容易受到异常数据的影响, 鲁棒性较差,适合传统精确小数据场景
4.2 标准化
from sklearn.preprocessing import StandardScaler
# 1. 准备数据
data = [[90, 2, 10, 40],
[60, 4, 15, 45],
[75, 3, 13, 46]]
# 2. 初始化标准化对象
transformer = StandardScaler()
# 3. 对原始特征进行变换
data = transformer.fit_transform(data)
# 4. 打印归一化后的结果
print(data)
对于标准化来说,如果出现异常点,由于具有一定数据量,少量的异常点对于平均值的影响并不大
5. K 值选择问题
KNN算法的关键是什么?
答案一定是K值的选择,下图中K=3,属于红色三角形,K=5属于蓝色的正方形。这个时候就是K选择困难的时候。
使用 scikit-learn 提供的
GridSearchCV
工具, 配合交叉验证法可以搜索参数组合.
from sklearn.datasets import load_iris
from sklearn.preprocessing import StandardScaler
from sklearn.neighbors import KNeighborsClassifier
from sklearn.model_selection import GridSearchCV
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
# 加载数据集
iris = load_iris()
X = iris.data
y = iris.target
# 数据标准化
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)
# 定义KNN分类器
knn = KNeighborsClassifier()
# 定义参数网格
param_grid = {'n_neighbors': range(1, 31)}
# 使用GridSearchCV进行参数搜索
grid_search = GridSearchCV(knn, param_grid, cv=5)
grid_search.fit(X_train, y_train)
# 输出最佳参数
print("Best parameters: ", grid_search.best_params_)
# 使用最佳参数进行预测
best_knn = grid_search.best_estimator_
y_pred = best_knn.predict(X_test)
# 计算准确率
accuracy = accuracy_score(y_test, y_pred)
print("Accuracy: ", accuracy)
这段代码展示了如何使用GridSearchCV来自动寻找最佳的K值。通过交叉验证,可以有效地避免过拟合问题,选择出最适合当前数据集的K值。