python_K近邻(KNN)

前言

提醒:
文章内容为方便作者自己后日复习与查阅而进行的书写与发布,其中引用内容都会使用链接表明出处(如有侵权问题,请及时联系)。
其中内容多为一次书写,缺少检查与订正,如有问题或其他拓展及意见建议,欢迎评论区讨论交流。


分类与回归算法

机器学习中的分类与回归算法是两种主要的监督学习任务,它们分别用于解决不同类型的问题。以下是这两种算法的总结:

  1. 分类算法
    分类算法用于将数据分成不同的类别,适用于输出为离散标签的问题。常见的分类算法包括:

    1. 逻辑回归:使用逻辑函数来估计概率,用于二分类问题,也可以扩展到多分类问题。
    2. 支持向量机(SVM):通过找到最优的决策边界来最大化样本的分类准确率,适用于高维数据。
    3. 决策树:通过树结构来进行决策,每个节点代表一个特征的选择,叶子节点代表分类结果。
    4. 随机森林:由多个决策树组成的集成学习方法,通过投票来决定最终分类结果。
    5. 梯度提升决策树(GBDT):通过构建和结合多个弱学习器来形成强学习器,适用于分类和回归问题。
    6. 朴素贝叶斯:基于贝叶斯定理,假设特征之间相互独立,适用于文本分类等场景。
    7. K近邻(KNN):根据样本之间的距离进行分类,适用于小规模数据集。
    8. 神经网络:通过多层感知机学习数据的复杂模式,适用于图像、语音等复杂分类问题。
  2. 回归算法
    回归算法用于预测连续数值输出,适用于输出为连续变量的问题。常见的回归算法包括:

    1. 线性回归:通过拟合一条直线来预测目标变量的值,是最简单的回归方法。
    2. 岭回归:线性回归的扩展,通过引入L2正则化项来防止过拟合。
    3. Lasso回归:线性回归的另一种扩展,通过引入L1正则化项来进行特征选择。
    4. 弹性网回归:结合了岭回归和Lasso回归,同时引入L1和L2正则化项。
    5. 决策树回归:使用决策树结构来进行回归预测,适用于非线性关系。
    6. 随机森林回归:由多个决策树组成的集成学习方法,通过平均来决定最终回归结果。
    7. 梯度提升决策树回归(GBDT回归):通过构建和结合多个弱学习器来形成强学习器,适用于回归问题。
    8. 支持向量回归(SVR):支持向量机在回归问题上的应用,通过找到最优的决策边界来最大化样本的回归准确率。
    9. 神经网络回归:通过多层感知机学习数据的复杂模式,适用于复杂的回归问题。
  3. 分类与回归算法的比较

    • 输出类型:分类算法输出离散标签,回归算法输出连续数值。
    • 评估指标:分类算法常用准确率、召回率、F1分数等指标,回归算法常用均方误差(MSE)、均方根误差(RMSE)等指标。
    • 问题类型:分类算法适用于类别预测问题,如垃圾邮件检测;回归算法适用于数值预测问题,如房价预测。 在实际应用中,选择分类还是回归算法取决于问题的性质和需求。有时,可以将回归问题转化为分类问题,或者将分类问题转化为回归问题,具体取决于问题的特点和目标。

K近邻(KNN)

KNN分类算法

KNN分类算法的步骤:

  1. 选择K: 确定最近邻的数量。选择过小的K可能会使算法对噪声过于敏感,而选择过大的K可能会平滑掉重要的模式。选择合适的K至关重要。

  2. 计算距离: 确定如何测量数据点之间的距离。常用的距离度量包括欧氏距离、曼哈顿距离和余弦相似性。使用欧氏距离时:
    d ( x ′ , x i ) = ∑ j = 1 m ( x j ′ − x i , j ) 2 d(x', x_i) = \sqrt{\sum_{j=1}^{m} (x'_j - x_{i,j})^2} d(x,xi)=j=1m(xjxi,j)2
    其中 m m m 是特征的数量。

  3. 找到K个最近邻: 根据选定的距离度量,检索K个最近的点 N K = { ( x i 1 , y i 1 ) , … , ( x i K , y i K ) } N_K = \{ (x_{i_1}, y_{i_1}), \dots, (x_{i_K}, y_{i_K}) \} NK={(xi1,yi1),,(xiK,yiK)}

  4. 多数投票: N K N_K NK 中统计每个类别的出现次数。具有最高频率的类别 y ^ \hat{y} y^ 将被分配给 x ′ x' x。数学上:
    y ^ = argmax c { ∑ k = 1 K δ ( y i k , c ) } \hat{y} = \text{argmax}_{c} \left\{ \sum_{k=1}^{K} \delta(y_{i_k}, c) \right\} y^=argmaxc{k=1Kδ(yik,c)}
    其中 δ \delta δ 是克罗内克δ函数,当 y i k = c y_{i_k} = c yik=c 时为1,否则为0。

  5. 返回预测: 预测完成。

KNN的变体和改进

KNN的变体和改进:

  1. 加权KNN: 不同的邻居可以根据它们的距离对分类进行不同的加权。例如,赋予较近的邻居更高的权重:
    y ^ = argmax c { ∑ k = 1 K δ ( y i k , c ) d ( x ′ , x i k ) } \hat{y} = \text{argmax}_{c} \left\{ \sum_{k=1}^{K} \frac{\delta(y_{i_k}, c)}{d(x', x_{i_k})} \right\} y^=argmaxc{k=1Kd(x,xik)δ(yik,c)}

  2. 自适应K: 不是全局固定K,而是根据局部数据密度自适应地选择K。

  3. 特征加权距离度量: 根据特征的重要性对它们进行加权。

实施中的挑战:

  1. 选择K: 通过交叉验证来选择最优的K。将数据分成几折,对每个 K 值进行训练和验证,选择验证性能最好的 K。

  2. 距离度量: 根据数据选择合适的距离度量。有时需要进行数据归一化以避免某些特征主导距离计算。

  3. 计算效率: 对于大型数据集,计算所有距离可能是计算密集型的。使用数据结构如kd树或近似最近邻方法可以提高效率。

实际示例

示例:

假设我们有一个数据集 D = { ( x 1 , y 1 ) , ( x 2 , y 2 ) , … , ( x 6 , y 6 ) } D = \{ (x_1, y_1), (x_2, y_2), \dots, (x_6, y_6) \} D={(x1,y1),(x2,y2),,(x6,y6)},具体如下:

  • x 1 = ( 1 , 2 ) , y 1 = A x_1 = (1, 2), y_1 = A x1=(1,2),y1=A
  • x 2 = ( 2 , 3 ) , y 2 = A x_2 = (2, 3), y_2 = A x2=(2,3),y2=A
  • x 3 = ( 3 , 3 ) , y 3 = B x_3 = (3, 3), y_3 = B x3=(3,3),y3=B
  • x 4 = ( 6 , 2 ) , y 4 = B x_4 = (6, 2), y_4 = B x4=(6,2),y4=B
  • x 5 = ( 7 , 1 ) , y 5 = C x_5 = (7, 1), y_5 = C x5=(7,1),y5=C
  • x 6 = ( 8 , 1 ) , y 6 = C x_6 = (8, 1), y_6 = C x6=(8,1),y6=C

需要对 x ′ = ( 4 , 2 ) x' = (4, 2) x=(4,2) 进行分类,假设 K = 3 K = 3 K=3

计算距离:

采用欧氏距离公式:
d ( x ′ , x i ) = ( 4 − x i , 1 ) 2 + ( 2 − x i , 2 ) 2 d(x', x_i) = \sqrt{(4 - x_{i,1})^2 + (2 - x_{i,2})^2} d(x,xi)=(4xi,1)2+(2xi,2)2

具体计算如下:

  • d ( x ′ , x 1 ) = ( 4 − 1 ) 2 + ( 2 − 2 ) 2 = 3 d(x', x_1) = \sqrt{(4-1)^2 + (2-2)^2} = 3 d(x,x1)=(41)2+(22)2 =3
  • d ( x ′ , x 2 ) = ( 4 − 2 ) 2 + ( 2 − 3 ) 2 = 5 ≈ 2.236 d(x', x_2) = \sqrt{(4-2)^2 + (2-3)^2} = \sqrt{5} \approx 2.236 d(x,x2)=(42)2+(23)2 =5 2.236
  • d ( x ′ , x 3 ) = ( 4 − 3 ) 2 + ( 2 − 3 ) 2 = 2 ≈ 1.414 d(x', x_3) = \sqrt{(4-3)^2 + (2-3)^2} = \sqrt{2} \approx 1.414 d(x,x3)=(43)2+(23)2 =2 1.414
  • d ( x ′ , x 4 ) = ( 4 − 6 ) 2 + ( 2 − 2 ) 2 = 2 d(x', x_4) = \sqrt{(4-6)^2 + (2-2)^2} = 2 d(x,x4)=(46)2+(22)2 =2
  • d ( x ′ , x 5 ) = ( 4 − 7 ) 2 + ( 2 − 1 ) 2 = 10 ≈ 3.162 d(x', x_5) = \sqrt{(4-7)^2 + (2-1)^2} = \sqrt{10} \approx 3.162 d(x,x5)=(47)2+(21)2 =10 3.162
  • d ( x ′ , x 6 ) = ( 4 − 8 ) 2 + ( 2 − 1 ) 2 = 17 ≈ 4.123 d(x', x_6) = \sqrt{(4-8)^2 + (2-1)^2} = \sqrt{17} \approx 4.123 d(x,x6)=(48)2+(21)2 =17 4.123

找到3个最近邻:

将距离从小到大排序:

  1. x 3 x_3 x3:≈1.414
  2. x 2 x_2 x2:≈2.236
  3. x 4 x_4 x4:2

因此,3个最近邻分别是 x 3 x_3 x3 x 2 x_2 x2,和 x 4 x_4 x4

多数投票:

  • x 3 x_3 x3:B
  • x 2 x_2 x2:A
  • x 4 x_4 x4:B

统计频率:

  • B:2
  • A:1

因此, y ^ = B \hat{y} = B y^=B

经典应用案例

更复杂的应用:

MNIST数据集:

  • 数据集描述: 包含 70,000 个手写数字的灰度图像(0-9),每个图像大小为 28x28 像素,flatten 后结果为 784 个特征。
  • 挑战:
    • 高维数据:每个样本有 784 个特征,计算密集型。
    • 大型数据集:70,000 个样本,使用标准方法计算距离耗时较长。
    • 距离度量:选择适合图像数据的距离度量。
  • 方法:
    1. 降维: 应用 PCA 将维数降低到更易管理的数量,例如 50 个主成分。
    2. 优化 KNN 实现: 使用基于 kd 树的 KNN 实现,可以高效处理大量数据点。
    3. 选择 K: 通过交叉验证,确定最优的 K 值。例如,从 K=1, 3, 5, 7, 9 中选择。
    4. 距离度量: 尝试不同的距离度量,如欧氏距离和曼哈顿距离,以查看哪种在该数据集上表现更好。
    5. 性能评估: 在测试集上评估性能,使用准确率、召回率、精确度和 F1 分数。

实施步骤:

  1. 加载数据: 将 MNIST 数据集加载到训练集和测试集中。
  2. 预处理:
    • 将图像 flatten 为 1D 数组。
    • 归一化像素值,范围为 0-1。
    • 应用 PCA 降维到 50 个成分。
  3. 初始化 KNN: 使用基于 kd 树的 KNN 实现,以提高效率。
  4. 交叉验证: 对每个 K 候选值,进行交叉验证以评估性能并选择最佳 K。
  5. 训练 KNN: 使用最佳 K 在整个训练集上训练 KNN。
  6. 预测: 使用训练的 KNN 对测试集进行预测。
  7. 评估: 计算并报告性能指标。

算法实现

K近邻(KNN)手动实现

import numpy as np
import matplotlib.pyplot as plt

# 定义欧氏距离函数
def euclidean_distance(x1, x2):
    return np.sqrt(np.sum((x1 - x2) ** 2))

# 定义 KNN 分类器类
class KNN:
    def __init__(self, k=3):
        self.k = k

    def fit(self, X, y):
        self.X_train = X
        self.y_train = y

    def predict(self, X):
        y_pred = [self._predict(x) for x in X]
        return np.array(y_pred)

    def _predict(self, x):
        # 计算距离
        distances = [euclidean_distance(x, x_train) for x_train in self.X_train]
        # 获取距离最近的 K 个样本的索引
        k_indices = np.argsort(distances)[:self.k]
        # 获取这些样本的标签
        k_nearest_labels = [self.y_train[i] for i in k_indices]
        # 统计各类别的数量
        most_common = np.bincount(k_nearest_labels).argmax()
        return most_common

# 生成示例数据
X_train = np.array([[1, 2], [2, 3], [3, 1], [6, 5], [7, 7], [8, 6]])
y_train = np.array([0, 0, 0, 1, 1, 1])

# 创建 KNN 分类器实例
knn = KNN(k=3)
# 拟合数据
knn.fit(X_train, y_train)

# 待分类的样本
X_test = np.array([[3, 2], [7, 6]])
# 进行预测
predictions = knn.predict(X_test)

# 可视化部分
# 定义颜色映射
colors = {0: 'blue', 1: 'red'}

# 绘制训练数据点
for label in np.unique(y_train):
    indices = np.where(y_train == label)
    plt.scatter(X_train[indices, 0], X_train[indices, 1], c=colors[label], label=f'Class {label} (Train)')

# 绘制测试数据点及预测结果
for i, test_point in enumerate(X_test):
    plt.scatter(test_point[0], test_point[1], c=colors[predictions[i]], marker='x', s=100, label=f'Class {predictions[i]} (Test)' if i == 0 else "")

plt.xlabel('Feature 1')
plt.ylabel('Feature 2')
plt.title('KNN Classification Visualization')
plt.legend()
plt.show()

运行结果:
在这里插入图片描述

KNN python函数库实现

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import ListedColormap
from sklearn import datasets, neighbors
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score

# 1. 加载数据
# 使用鸢尾花数据集 (iris),只取前两个特征
iris = datasets.load_iris()
X = iris.data[:, :2]  # 取前两个特征(萼片长度和萼片宽度)
y = iris.target

# 将数据集划分为训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)

# 2. 训练 KNN 分类器
k = 15  # 选择 K=15
knn = neighbors.KNeighborsClassifier(n_neighbors=k)
knn.fit(X_train, y_train)

# 3. 预测测试集
y_pred = knn.predict(X_test)

# 4. 计算准确率
accuracy = accuracy_score(y_test, y_pred)
print(f"模型准确率: {accuracy:.2f}")

# 5. 可视化决策边界
# 定义颜色映射
cmap_light = ListedColormap(['#FFAAAA', '#AAFFAA', '#AAAAFF'])
cmap_bold = ListedColormap(['#FF0000', '#00FF00', '#0000FF'])

# 创建网格点来绘制决策边界
h = 0.02  # 网格点的步长
x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1
y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1
xx, yy = np.meshgrid(np.arange(x_min, x_max, h),
                     np.arange(y_min, y_max, h))

# 对每个网格点进行预测
Z = knn.predict(np.c_[xx.ravel(), yy.ravel()])

# 将预测结果重新整形为网格形状
Z = Z.reshape(xx.shape)

# 绘制决策边界和数据点
plt.figure(figsize=(8, 6))
plt.pcolormesh(xx, yy, Z, cmap=cmap_light, shading='auto')  # 决策边界
plt.scatter(X[:, 0], X[:, 1], c=y, cmap=cmap_bold, edgecolor='k', s=50)  # 数据点
plt.xlabel('Sepal Length (cm)')
plt.ylabel('Sepal Width (cm)')
plt.title(f'KNN Classification (k = {k}, Accuracy = {accuracy:.2f})')
plt.xlim(xx.min(), xx.max())
plt.ylim(yy.min(), yy.max())
plt.show()

运行结果:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值