在机器学习领域,K近邻算法(K-Nearest Neighbor, KNN)是最基础且常用的算法之一。无论是分类任务还是回归任务,KNN都能通过简单直观的方式实现高效的预测。在这篇博客中,我们将基于MindSpore框架,使用KNN算法对Wine数据集进行聚类实验。通过这个实验,我们不仅能够深入了解KNN算法的基本概念和原理,还能学习如何在MindSpore中实现和应用该算法。
K近邻算法原理
基本概念
K近邻算法(K-Nearest-Neighbor, KNN)是一种用于分类和回归的非参数统计方法。其核心思想是:要确定一个样本的类别,可以计算它与所有训练样本的距离,然后找出和该样本最接近的k个样本,统计这些样本的类别并进行投票,票数最多的那个类就是分类的结果。
KNN的三个基本要素
- K值:K值越小,模型越容易受噪声影响;K值越大,类别之间的界限会变得模糊。
- 距离度量:常用的有欧氏距离、曼哈顿距离、海明距离等。
- 分类决策规则:通常是多数表决,或者基于距离加权的多数表决。
分类问题与回归问题
- 分类问题:找到距离待测样本最近的k个样本,统计每一类样本的个数,最终的分类结果为出现次数最多的那个类。
- 回归问题:对样本的回归预测输出值为所有邻居标签的均值,或者带权重的均值。
距离的定义
KNN算法的实现依赖于样本之间的距离,最常用的距离函数是欧氏距离。公式如下:
[ d(x,y) = \sqrt{\sum_{i=1}{n}{(x_{i}-y_{i})2}} ]
为了减少特征值尺度范围不同带来的干扰,使用欧氏距离时应将特征向量的每个分量归一化。
数据处理
数据准备
Wine数据集是模式识别中最著名的数据集之一,包含了对来自意大利同一地区但来自三个不同品种的葡萄酒进行化学分析的结果。数据集分析了三种葡萄酒中每种所含13种成分的量。
数据读取与处理
首先,我们需要导入所需的Python库,并读取Wine数据集。
解释:首先,我们读取Wine数据集并将其转换为NumPy数组。X
包含了所有样本的13个属性,而Y
则包含了样本的类别标签。这样做的目的是将数据转换为易于处理的格式,以便后续的模型训练和预测。
import os
import csv
import numpy as np
import matplotlib.pyplot as plt
import mindspore as ms
from mindspore import nn, ops
ms.set_context(device_target="CPU")
# 读取数据
with open('wine.data') as csv_file:
data = list(csv.reader(csv_file, delimiter=','))
print(data[56:62]+data[130:133])
# 处理数据
X = np.array([[float(x) for x in s[1:]] for s in data[:178]], np.float32)
Y = np.array([s[0] for s in data[:178]], np.int32)
数据可视化
我们可以取样本的某两个属性进行二维可视化,观察样本的分布情况及可分性。
解释:我们通过取样本的某两个属性进行二维可视化,观察样本的分布情况及可分性。这样做的目的是帮助我们直观地理解数据的分布情况,从而更好地选择特征和参数。
attrs = ['Alcohol', 'Malic acid', 'Ash', 'Alcalinity of ash', 'Magnesium', 'Total phenols',
'Flavanoids', 'Nonflavanoid phenols', 'Proanthocyanins', 'Color intensity', 'Hue',
'OD280/OD315 of diluted wines', 'Proline']
plt.figure(figsize=(10, 8))
for i in range(0, 4):
plt.subplot(2, 2, i+1)
a1, a2 = 2 * i, 2 * i + 1
plt.scatter(X[:59, a1], X[:59, a2], label='1')
plt.scatter(X[59:130, a1], X[59:130, a2], label='2')
plt.scatter(X[130:, a1], X[130:, a2], label='3')
plt.xlabel(attrs[a1])
plt.ylabel(attrs[a2])
plt.legend()
plt.show()
数据集划分
将数据集按128:50划分为训练集(已知类别样本)和验证集(待验证样本)。
解释:我们将数据集按128:50划分为训练集和验证集。训练集用于模型的训练,验证集用于评估模型的性能。这样做的目的是确保模型在未见过的数据上也能表现良好,避免过拟合。
train_idx = np.random.choice(178, 128, replace=False)
test_idx = np.array(list(set(range(178)) - set(train_idx)))
X_train, Y_train = X[train_idx], Y[train_idx]
X_test, Y_test = X[test_idx], Y[test_idx]
模型构建
解释:我们利用MindSpore提供的算子,通过矩阵运算的方式计算输入样本和训练样本的距离,并找出top k近邻。这样做的目的是提高计算效率,通过批量操作加速距离计算。
class KnnNet(nn.Cell):
def __init__(self, k):
super(KnnNet, self).__init__()
self.k = k
def construct(self, x, X_train):
x_tile = ops.tile(x, (128, 1))
square_diff = ops.square(x_tile - X_train)
square_dist = ops.sum(square_diff, 1)
dist = ops.sqrt(square_dist)
values, indices = ops.topk(-dist, self.k)
return indices
def knn(knn_net, x, X_train, Y_train):
x, X_train = ms.Tensor(x), ms.Tensor(X_train)
indices = knn_net(x, X_train)
topk_cls = [0]*len(indices.asnumpy())
for idx in indices.asnumpy():
topk_cls[Y_train[idx]] += 1
cls = np.argmax(topk_cls)
return cls
模型预测
解释:我们在验证集上验证KNN算法的有效性,取k=5,计算验证集上的精度。这样做的目的是评估模型的性能,确保其在实际应用中的有效性。
在验证集上验证KNN算法的有效性,取 k = 5 k = 5 k=5,验证精度接近80%。
acc = 0
knn_net = KnnNet(5)
for x, y in zip(X_test, Y_test):
pred = knn(knn_net, x, X_train, Y_train)
acc += (pred == y)
print('label: %d, prediction: %s' % (y, pred))
print('Validation accuracy is %f' % (acc/len(Y_test)))