65.9K
CodeProject 正在变化。 阅读更多。
Home

实现机器学习的分步指南 I - KNN

starIconstarIcon
emptyStarIcon
starIcon
emptyStarIconemptyStarIcon

2.25/5 (5投票s)

2019年5月4日

CPOL

2分钟阅读

viewsIcon

7587

易于实现的机器学习

引言

K近邻(KNN)是一种简单的机器学习算法,其原理是计算测试对象与训练集之间的距离。然后,根据距离选择训练集中的对象添加到K-NN集合中,直到K-NN集合包含预定义的最近邻数量,可以表示为

y = argmax\sum_{x_{j}\in N_{k}}^{k}{I(y_{i}=c_{i})}

其中 N_{k} 是KNN集合,I 由下式给出

I(x)= \begin{cases} 0,& \text{if x is true}\\ 1,& \text{else} \end{cases}

KNN模型

KNN模型包括距离计算、选择K和分类。

距离计算

距离用于衡量特征空间中两个对象之间的相似性。有很多方法可以计算两个对象之间的距离,例如欧几里得距离、余弦距离、编辑距离、曼哈顿距离等。最简单的方法是欧几里得距离,计算公式如下

L_{2}(x_{i},x_{j})=\left( \sum_{l=1}^{n}{|x_{i}^{(l)}-x_{j}^{(l)}|^{2}}\right)^\frac{1}{2}

其中 n 是特征维度。

由于特征值的尺度不同,较大的值对距离的影响更大。因此,需要对所有特征进行归一化。具体来说,有两种归一化方法。一种是最小-最大归一化,公式如下

x'=\frac{x-min(x)}{max(x)-min(x)}

    def Normalization(self, data):
        # get the max and min value of each column
        minValue = data.min(axis=0)
        maxValue = data.max(axis=0)
        diff = maxValue - minValue
        # normalization
        mindata = np.tile(minValue, (data.shape[0], 1))
        normdata = (data - mindata)/np.tile(diff, (data.shape[0], 1))
        return normdata

另一种是z-score归一化,公式如下

x'=\frac{x-\mu}{\sigma}

其中 \mux 的均值,\sigmax 的标准差。

    def Standardization(self, data):
        # get the mean and the variance of each column
        meanValue = data.mean(axis=0)
        varValue = data.std(axis=0)
        standarddata = (data - np.tile(meanValue, 
                       (data.shape[0], 1)))/np.tile(varValue, (data.shape[0], 1))
        return standarddata

归一化后,欧几里得距离的代码如下所示

train_num = train_data.shape[0]
# calculate the distances
distances = np.tile(input, (train_num, 1)) - train_data
distances = distances**2
distances = distances.sum(axis=1)
distances = distances**0.5

选择K

如果我们选择一个较小的K,模型将使用较小的邻居进行学习,这将导致较小的“近似误差”而较大的“估计误差”。 换句话说,较小的K会使模型复杂并倾向于过拟合。 相反,如果我们选择一个较大的K,模型将使用较大的邻居进行学习,这将导致较大的“近似误差”而较小的“估计误差”。 换句话说,较大的K会使模型简单并倾向于更大的计算量。

分类

确定K后,我们可以利用投票进行分类,这意味着少数服从多数,其代码如下所示

disIndex = distances.argsort()
labelCount = {}
for i in range(k):
    label = train_label[disIndex[i]]
    labelCount[label] = labelCount.get(label, 0) + 1
prediction = sorted(labelCount.items(), key=op.itemgetter(1), reverse=True)
label = prediction[0][0]

在上面的代码中,我们首先使用 argsorts() 获取排序后的索引,然后计算前K个样本中每种标签的数量,最后对 labelCount 进行排序以获得投票最多的标签,这就是对测试对象的预测。 整个预测函数如下所示

def calcuateDistance(self, input_sample, train_data, train_label, k):
        train_num = train_data.shape[0]
        # calculate the distances
        distances = np.tile(input, (train_num, 1)) - train_data
        distances = distances**2
        distances = distances.sum(axis=1)
        distances = distances**0.5

        # get the labels of the first k distances
        disIndex = distances.argsort()
        labelCount = {}
        for i in range(k):
            label = train_label[disIndex[i]]
            labelCount[label] = labelCount.get(label, 0) + 1

        prediction = sorted(labelCount.items(), key=op.itemgetter(1), reverse=True)
        label = prediction[0][0]
        return label

结论与分析

本文通过线性遍历实现KNN。 然而,存在更有效的方法来实现KNN,例如kd树。 此外,应用交叉验证以获得更合适的K是有效的。 最后,让我们将我们的KNN与Sklearn中的KNN进行比较,检测性能如下所示。

从图中可以看出,本文中的KNN在准确性方面优于sklearn knn,运行时间几乎相同。

本文相关的代码和数据集可以在 MachineLearning 中找到。

© . All rights reserved.