为了账号安全,请及时绑定邮箱和手机立即绑定

机器学习:kNN算法(一)—— 原理与代码实现(不调用库)

标签:
机器学习

一 理论基础

  • kk近邻法是一种基本地分类与回归算法,属于判别模型。没有学习策略,不具备显式学习过程。本文主要讨论分类问题。

  • 原理:给定一个训练数据集,对于新的输入实例,在训练数据集中找到与该实例最邻近的kk个点,这kk个点的多数属于某个类,就把输入实例归为这个类。

  • 三个基本要素:kk值得选择,距离度量以及分类决策规则
    1.超参数k:选择较小的k值,对噪声比较敏感。意味着整体模型变得复杂,容易过拟合;选择较大的k值,较远的实例也会对预测起作用,使预测发生错误。意味着模型变得简单。
    2.距离度量:距离是空间两个实力点相似程度的反映。xi=(x(1)i,x(2)i,...,x(n)i)T,xj=(x(1)j,x(2)j,...,x(n)j)Txi=(xi(1),xi(2),...,xi(n))T,xj=(xj(1),xj(2),...,xj(n))T,距离定义如下:

    Lp=(∑l=1n|x(l)i−x(l)j|p)1pLp=(∑l=1n|xi(l)−xj(l)|p)1p


     p=1时称为曼哈顿距离,p=2时称为欧氏距离。
    3.分类决策规则:一般采用多数表决。

二 代码实现

  • 编写的分类器实现功能:超参数k,超参数p,拟合训练集,对新的数据进行分类,对分类结果计算精度。感兴趣的还可以加入超参数距离的权重以及kd树,球树等实现方法。这里不再赘述。

  • KNN算法实现代码如下

class KNNClassify():

    def __init__(self,k=5, p=2):

        self.k = k
        self.p = p
        self._X_train = None
        self._y_train = None

    def fit(self, X_train, y_train):

        self._X_train = X_train
        self._y_train = y_train        return self    def predict_y(self, X_test):

        m = self._X_train.shape[0]
        y_pre = []        for intX in X_test:
            minus_mat = np.fabs(np.tile(intX, (m, 1)) - self._X_train)       # 将新的实例复制成m行1列,并进行相减
            sq_minus_mat = minus_mat ** self.p
            sq_distance = sq_minus_mat.sum(axis=1)
            diff_sq_distance = sq_distance ** float(1/self.p)

            sorted_distance_index = diff_sq_distance.argsort()               # 记录距离最近的k个点的索引
            class_count = {}
            vola = []            for i in range(self.k):
                vola = self._y_train[sorted_distance_index[i]]
                class_count[vola] = class_count.get(vola, 0) + 1             # 统计k个点中所属各个类别的实例数目

            sorted_class_count = sorted(class_count.items(), key=operator.itemgetter(1), reverse=True)    # 返回列表,元素为元组。每个类别以及对应的实例数目
            y_pre.append((sorted_class_count[0][0]))        return (np.array(y_pre))    def score(self, X_test, y_test):

        j = 0
        for i in range(len(self.predict_y(X_test))):            if self.predict_y(X_test)[i] == y_test[i]:
                j += 1
        return ('accuracy: {:.10%}'.format(j / len(y_test)))
  • 下面以鸢尾花数据集来评估编写的分类器效果

import numpy as np
import operator

from sklearn import datasets
from sklearn.model_selection import train_test_split# 获取数据集,并进行8:2切分iris = datasets.load_iris()
X = iris.data
y = iris.target

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)# 定义分类器的实例,并进行拟合预测f = KNNClassify()
f.fit(X_train, y_train)
y_pre = f.predict_y(X_test)
accuracy = f.score(X_test, y_test)print(y_test)print(y_pre)print(accuracy)
  • 输出结果如下,可以看出分类效果还可以。
    [1 2 2 2 0 1 2 0 0 0 1 2 0 0 2 1 2 0 2 2 2 2 0 2 1 1 0 2 0 1]
    [1 2 2 2 0 1 2 0 0 0 1 2 0 0 2 1 1 0 2 2 2 2 0 2 1 1 0 2 0 1]
    accuracy: 96.6666666667%

  • 需要注意的是KNN由于与距离有关,如果某个特征数值相比其他特征较大大,会对距离产生很大的影响。例如具有实例x1=[1 3 1000 2],x2=[1.5 4 1100 2],计算距离时第三个特征差基本起到了主导作用,弱化了其他特征。为避免这种情况,应先对数据进行预理。

  • 预处理方法。关于标准化与归一化,不同的人有不同看法,这里以sklearn为准,标准化对象为特征,归一化对象为样本,当然两者实质都是对训练集数据的改变。可以参考[http://sklearn.apachecn.org/cn/0.19.0/modules/preprocessing.html#preprocessing-scaler]
    1.标准化(对特征),也称去均值和方差按比例缩放。数据集的标准化对scikit-learn中实现的大多数机器学习算法来说是常见的要求 。(对象为特征,依赖于训练集中所有样本)

    2.归一化(对样本)。归一化 是缩放单个样本以具有单位范数的过程。注意对象为样本而非某个特征!!通常使用 L1 或 L2 范数。例如实例x1=(1,2,2)Tx1=(1,2,2)T,归一化后x1=(0.33,0.66,0.66)Tx1=(0.33,0.66,0.66)T。不依赖于其他样本特征数值。
    3.二值化。
    4.非线性变换
    5.特征编码L
    6.缺失值插补

    • 如果个别特征或多或少看起来不是很像标准正态分布(具有零均值和单位方差),那么它们的表现力可能会较差。在实际情况中,我们经常忽略特征的分布形状,直接减去均值来对某个特征进行中心化,再通过除以非常量特征(non-constant features)的标准差进行缩放。

      x=x−x¯σx=x−x¯σ

    • 将特征缩放到给定的区间,通常为[0,1]。或者也可以将每个特征的最大值转换至单位大小,它通过除以每个特征的最大值将训练数据特征缩放至 [-1, 1] 范围内,这就意味着训练数据应该是已经零中心化或者是稀疏数据。两者分别使用MinMaxScaler和MaxAbsScaler实
      现。对于两者计算公式分别为

      x=x−min(x)max(x)−min(x),x=xmax(x)x=x−min(x)max(x)−min(x),x=xmax(x)

  • 由此可以看出,对于kNN而言,当某个特征的差值相比其他特征较大时,可以采用标准化,以避免某个特征对距离影响。如果进行归一化,虽然也是改变了特征取值区间,但是特征间量级关系依然会相差很大。

  • 当我们得出一个算法模型后,如何评判模型的好坏呢?包括许多性能度量方法,例如精度与错误率、查准率查全率与F1、ROC与AUC等等。假如我们选择精度作为衡量指标,我们采用多次留出法或者p次k折交叉验证,然后将各个精度取均值作为此模型的评估指标。
    1.留出法。将数据集分成互斥的训练集与测试集,可以得出一个精度。因为划分方式存在多种方式,因此使用留出法时,采用若干次随机划分,重复进行实验取平均值作为留出法评估结果。
    2.交叉验证。将数据划分成k个互斥大小相似的集合,每次采用k-1个作为训练集,剩下一个作为测试集,总共可进行k次,最终返回k次结果的均值。同样由于划分方式不同,可进行p次划分,每次都进行k折交叉验证,取最后均值作为评估结果,称为p次k折交叉验证。

原文出处:https://www.cnblogs.com/lyxML/p/9509059.html

点击查看更多内容
1人点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消