引言
K近邻(K-Nearest Neighbors,简称KNN)算法是一种简单却强大的监督学习算法,常用于分类和回归任务。它的核心思想基于“物以类聚”的理念,即一个样本的类别可以由它的K个最近邻样本的类别来决定。本文将详细介绍KNN算法的原理、使用时需要注意的地方、常见应用场景,并通过Python代码进行实现和解释。
算法原理
基本思想
KNN算法的基本思想是:对于一个待分类的样本,在训练数据集中找到与它距离最近的K个样本,然后根据这K个样本所属的类别进行投票,得票最多的类别即为待分类样本的类别。在回归任务中,则通常取这K个样本的目标值的平均值作为待预测样本的预测值。
距离度量
在KNN算法中,距离的计算是关键步骤之一。常用的距离度量方法有:
- 欧氏距离(Euclidean Distance):对于两个n维向量
x
=
(
x
1
,
x
2
,
⋯
,
x
n
)
x=(x_1,x_2,\cdots,x_n)
x=(x1,x2,⋯,xn)和
y
=
(
y
1
,
y
2
,
⋯
,
y
n
)
y=(y_1,y_2,\cdots,y_n)
y=(y1,y2,⋯,yn),欧氏距离的计算公式为:
d ( x , y ) = ∑ i = 1 n ( x i − y i ) 2 d(x,y)=\sqrt{\sum_{i=1}^{n}(x_i - y_i)^2} d(x,y)=∑i=1n(xi−yi)2 - 曼哈顿距离(Manhattan Distance):计算公式为:
d ( x , y ) = ∑ i = 1 n ∣ x i − y i ∣ d(x,y)=\sum_{i=1}^{n}|x_i - y_i| d(x,y)=∑i=1n∣xi−yi∣
算法步骤
- 数据准备:收集并整理训练数据集,包括特征向量和对应的标签。
- 计算距离:对于待分类的样本,计算它与训练数据集中每个样本的距离。
- 选择K值:确定K的大小,即选择最近邻的样本数量。
- 选择K个最近邻:根据计算得到的距离,选择距离最近的K个样本。
- 进行分类或回归:
- 分类任务:统计这K个样本中各个类别的数量,选择数量最多的类别作为待分类样本的类别。
- 回归任务:计算这K个样本的目标值的平均值,作为待预测样本的预测值。
需要注意的地方
K值的选择
K值的选择对KNN算法的性能影响很大。如果K值过小,模型容易过拟合,因为它对噪声和异常值比较敏感;如果K值过大,模型容易欠拟合,因为它会忽略样本的局部特征。通常可以使用交叉验证的方法来选择合适的K值。
数据预处理
由于KNN算法是基于距离的,因此数据的尺度对算法的性能有很大影响。在使用KNN算法之前,通常需要对数据进行标准化或归一化处理,以确保各个特征具有相同的尺度。
计算复杂度
KNN算法的计算复杂度较高,尤其是在处理大规模数据集时。因为每次预测都需要计算待分类样本与训练数据集中所有样本的距离。可以使用一些优化算法,如KD树(KD-Tree)或球树(Ball Tree)来加速距离计算。
常用场景
分类任务
- 图像识别:将图像的特征向量作为输入,使用KNN算法对图像进行分类,如手写数字识别、人脸识别等。
- 文本分类:将文本的特征向量(如词袋模型、TF-IDF等)作为输入,使用KNN算法对文本进行分类,如新闻分类、垃圾邮件分类等。
回归任务
- 房价预测:将房屋的特征(如面积、房间数、地理位置等)作为输入,使用KNN算法预测房屋的价格。
- 股票价格预测:将股票的历史数据(如开盘价、收盘价、成交量等)作为输入,使用KNN算法预测股票的未来价格。
Python代码实现与解释
import numpy as np
from collections import Counter
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import accuracy_score
# 定义KNN分类器类
class KNN:
def __init__(self, k=3):
# 初始化K值,默认为3
self.k = k
def fit(self, X, y):
# 保存训练数据和标签
self.X_train = X
self.y_train = y
def predict(self, X):
# 对每个待预测样本进行预测
predictions = [self._predict(x) for x in X]
return np.array(predictions)
def _predict(self, x):
# 计算待分类样本与训练数据集中每个样本的欧氏距离
distances = [np.linalg.norm(x - x_train) for x_train in self.X_train]
# 获取距离最近的K个样本的索引
k_indices = np.argsort(distances)[:self.k]
# 获取这K个样本的标签
k_nearest_labels = [self.y_train[i] for i in k_indices]
# 统计这K个样本中各个类别的数量
most_common = Counter(k_nearest_labels).most_common(1)
# 返回数量最多的类别作为预测结果
return most_common[0][0]
# 加载鸢尾花数据集
iris = load_iris()
X = iris.data
y = iris.target
# 划分训练集和测试集,测试集占30%
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
# 数据标准化(关键步骤!)
scaler = StandardScaler()
X_train = scaler.fit_transform(X_train)
X_test = scaler.transform(X_test)
# 创建KNN分类器实例,设置K值为3
knn = KNN(k=3)
# 训练模型
knn.fit(X_train, y_train)
# 进行预测
y_pred = knn.predict(X_test)
# 计算并输出准确率
accuracy = accuracy_score(y_test, y_pred)
print(f"模型在测试集上的准确率为: {accuracy:.2f}")
代码解释
-
KNN类的定义:
__init__
方法:初始化K值。fit
方法:保存训练数据。predict
方法:对输入的样本进行预测,调用_predict
方法对每个样本进行分类。_predict
方法:计算待分类样本与训练数据集中每个样本的欧氏距离,选择距离最近的K个样本,统计这K个样本中各个类别的数量,返回数量最多的类别。
-
数据加载与预处理:
- 使用
load_iris
函数加载鸢尾花数据集。 - 使用
train_test_split
函数将数据集划分为训练集和测试集。 - 使用
StandardScaler
对数据进行标准化处理。
- 使用
-
模型训练与预测:
- 创建KNN分类器实例,设置K值为3。
- 调用
fit
方法训练模型。 - 调用
predict
方法对测试集进行预测。
-
准确率计算:
- 计算预测结果与真实标签的匹配率,即准确率。
总结
KNN算法是一种简单易懂、易于实现的监督学习算法,适用于分类和回归任务。在使用KNN算法时,需要注意K值的选择、数据预处理和计算复杂度等问题。通过合理选择K值和进行数据预处理,可以提高KNN算法的性能。