目录
⭐️引言
K-近邻算法(K-Nearest Neighbors, KNN)是一种基本的模式识别与机器学习分类算法。它的核心思想是根据输入实例在特征空间中的最近(相似度最高)的训练实例来决定其类别。
⭐️理论
实现K-近邻算法(KNN)主要依赖于scikit-learn(简称sklearn)这个库。scikit-learn是一个免费软件机器学习库,它包含了一系列用于数据挖掘和数据分析的简单高效的工具。sklearn中的neighbors模块提供了KNN分类器和回归器的实现。
1、算法原理:
对于给定的数据点,KNN会找到训练集中距离该点最近的k个数据点。
根据这k个最近邻的多数类别来预测新的数据点的类别。
距离通常采用欧几里得距离或其他距离度量方法计算。
2、距离度量:
欧几里得距离是最常用的度量方式,对于两个点 ( ) 和 (),其距离可以表示为: [ ]
import numpy as np
def euclidean_distance(x, y):
return np.sqrt(np.sum((x - y) ** 2))
曼哈顿距离(Manhattan Distance)是一种常用的距离度量方法,适用于连续数值型特征。曼哈顿距离定义为两个点在各个维度上的绝对差值之和。对于两个点 ( ) 和 (),曼哈顿距离可以表示为:[ ]
import numpy as np
def manhattan_distance(x, y):
return np.sum(np.abs(x - y))
切比雪夫距离(Chebyshev Distance)是一种常用的距离度量方法,适用于连续数值型特征。切比雪夫距离定义为两个点在各个维度上的最大绝对差值。对于两个点( 和 ,切比雪夫距离可以表示为:
( ) 和 ( ) 分别是两个点在第 ( ) 维度上的坐标。
( ) 表示两个点在第 ( ) 维度上的绝对差值。
最终的距离是所有维度上绝对差值的最大值
import numpy as np
def chebyshev_distance(x, y):
return np.max(np.abs(x - y))
余弦相似度适用于高维空间中的向量比较,通常用于文本数据。它衡量的是两个向量之间的夹角余弦值,值范围在 ([-1, 1]) 之间。余弦相似度越接近 1,表示两个向量越相似;越接近 -1,表示两个向量越不相似;0 表示两个向量正交。
对于两个向量 ( ) ) 和 ( ),余弦相似度可以表示为:
其中:
( ) 是向量 ( ) 和 ( ) 的点积(内积)。
( ) 和 ( ) 分别是向量 ( ) 和 ( ) 的范数(长度)。
import numpy as np
def cosine_similarity(x, y):
dot_product = np.dot(x, y)
norm_x = np.linalg.norm(x)
norm_y = np.linalg.norm(y)
return dot_product / (norm_x * norm_y)
Jaccard 相似度适用于二元特征数据,如集合之间的相似度。它衡量的是两个集合的交集大小相对于它们并集大小的比例。
对于两个集合 ( ) 和 ( ),Jaccard 相似度可以表示为:
其中:
( ) 是集合 ( ) 和 ( ) 的交集大小。
( ) 是集合 ( ) 和 ( ) 的并集大小。
import numpy as np
def cosine_similarity(x, y):
dot_product = np.dot(x, y)
norm_x = np.linalg.norm(x)
norm_y = np.linalg.norm(y)
return dot_product / (norm_x * norm_y)
3、选择k值:
k值的选择对模型的影响很大,较小的k值会导致模型过拟合,较大的k值则可能导致欠拟合。通常通过交叉验证来选择最佳的k值。
import numpy as np
from sklearn.model_selection import cross_val_score
from sklearn.neighbors import KNeighborsClassifier
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
# 加载数据集
data = load_iris()
X = data.data
y = data.target
# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# 定义 k 值的范围
k_values = range(1, 31)
# 存储每个 k 值对应的交叉验证得分
cv_scores = []
# 对每个 k 值进行交叉验证
for k in k_values:
knn = KNeighborsClassifier(n_neighbors=k)
scores = cross_val_score(knn, X_train, y_train, cv=5, scoring='accuracy')
cv_scores.append(scores.mean())
# 找到最佳 k 值
best_k = k_values[np.argmax(cv_scores)]
# 输出结果
print(f"最佳 k 值: {best_k}")
print(f"最佳 k 值对应的交叉验证准确率: {max(cv_scores)}")
4、处理不平衡数据集:
当类别分布不均匀时,可以通过加权投票来调整不同类别的影响,例如,根据类别出现的频率来加权。
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
from sklearn.metrics import classification_report
from sklearn.datasets import make_classification
# 生成不平衡数据集
X, y = make_classification(n_samples=1000, n_features=20, n_classes=2, weights=[0.9, 0.1], random_state=42)
# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# 计算类别权重
class_weights = {}
unique, counts = np.unique(y_train, return_counts=True)
total_samples = len(y_train)
for label, count in zip(unique, counts):
class_weights[label] = total_samples / (len(unique) * count)
# 创建加权 KNN 模型
knn_weighted = KNeighborsClassifier(n_neighbors=5, weights=lambda x: [class_weights[label] for label in y_train[x]])
# 训练模型
knn_weighted.fit(X_train, y_train)
# 预测测试集
y_pred = knn_weighted.predict(X_test)
# 输出分类报告
print(classification_report(y_test, y_pred))
5、归一化:
在计算距离之前,通常需要对特征进行归一化处理,以消除不同尺度特征的影响。
Min-Max 归一化
Min-Max 归一化将每个特征的值缩放到 [0, 1] 之间。
# 使用 Min-Max 归一化
min_max_scaler = MinMaxScaler()
X_train_minmax = min_max_scaler.fit_transform(X_train)
X_test_minmax = min_max_scaler.transform(X_test)
# 创建 KNN 模型
knn_minmax = KNeighborsClassifier(n_neighbors=5)
knn_minmax.fit(X_train_minmax, y_train)
# 预测测试集
y_pred_minmax = knn_minmax.predict(X_test_minmax)
# 输出分类报告
print("Min-Max 归一化分类报告:")
print(classification_report(y_test, y_pred_minmax))
Z-Score 标准化
Z-Score 标准化将每个特征的值标准化为均值为 0、标准差为 1 的分布。
# 使用 Z-Score 标准化
standard_scaler = StandardScaler()
X_train_standard = standard_scaler.fit_transform(X_train)
X_test_standard = standard_scaler.transform(X_test)
# 创建 KNN 模型
knn_standard = KNeighborsClassifier(n_neighbors=5)
knn_standard.fit(X_train_standard, y_train)
# 预测测试集
y_pred_standard = knn_standard.predict(X_test_standard)
# 输出分类报告
print("Z-Score 标准化分类报告:")
print(classification_report(y_test, y_pred_standard))
6、决策规则:
多数表决:预测类别为k个最近邻中出现次数最多的类别。
# 创建 KNN 模型,使用多数表决
knn_majority = KNeighborsClassifier(n_neighbors=5)
# 训练模型
knn_majority.fit(X_train, y_train)
# 预测测试集
y_pred_majority = knn_majority.predict(X_test)
# 输出分类报告
print("多数表决分类报告:")
print(classification_report(y_test, y_pred_majority))
加权多数表决:每个邻居的投票权重与它到目标样本的距离成反比。
# 创建 KNN 模型,使用加权多数表决
knn_weighted = KNeighborsClassifier(n_neighbors=5, weights='distance')
# 训练模型
knn_weighted.fit(X_train, y_train)
# 预测测试集
y_pred_weighted = knn_weighted.predict(X_test)
# 输出分类报告
print("加权多数表决分类报告:")
print(classification_report(y_test, y_pred_weighted))
⭐️结语
K-近邻算法(K-Nearest Neighbors, KNN)是一种基于实例的学习方法,广泛应用于分类和回归任务。其基本原理是通过计算待预测样本与训练集中所有样本的距离,选取距离最近的 k 个邻居,并根据这些邻居的信息进行预测。对于分类任务,预测类别为 k 个最近邻中出现次数最多的类别;对于回归任务,预测值为 k 个最近邻的目标值的平均值。常用的距离度量方法包括欧氏距离、曼哈顿距离和闵可夫斯基距离,其中欧氏距离最为常用。为了消除不同特征尺度的影响,通常需要对特征进行归一化处理,如 Min-Max 归一化和 Z-Score 标准化。k 值的选择对模型影响很大,较小的 k 值可能导致过拟合,较大的 k 值可能导致欠拟合,通常通过交叉验证来选择最佳的 k 值。KNN 算法支持多种决策规则,包括多数表决和加权多数表决。该算法的优点在于简单易懂、适用于多分类问题且能处理非线性问题;缺点在于计算复杂度较高,特别是对于大数据集,且对噪声和异常值敏感。