zoukankan      html  css  js  c++  java
  • 第三章-KNN(分类和回归算法模型)

    上上一章已经学习了感知机模型、策略和算法,感知机对于分类任务有着其优点,但是该模型是在具有强假设的条件下——训练数据集必须是线性可分的,但是如果数据集是呈现无规则的分布,那么此时如果要做分类任务,还可以考虑k近邻(KNN),这是一种基本的分类和回归方法,既可以做简单的二分类也可以做复杂的多分类任务,还可以做回归任务。

    KNN模型

    KNN模型实际上对应于对特征空间的划分,虽然没有具体的数学抽象语言描述,但是仍然存在其三要素:距离度量、K值的选择、分类决策规则

    距离度量

    [设特征空间chi是n维实数向量空间R^n,x_i,x_j in chi,x_i=(x_i^{(1)},x_i^{(2)},x_i^{(3)}...,x_i^{(n)})^T,\ x_j=(x_j^{(1)},x_j^{(2)},x_j^{(3)}...,x_j^{(n)})^T,x_i,x_j的距离可定义为:\ L_P(x_i,x_j)=(sum^n_{l=1}|x_i^{(l)}-x_j^{(l)}|^p)^{frac{1}{p}}\ 一般地,当p=1时,L_1(x_i,x_j)=(sum^n_{l=1}|x_i^{(l)}-x_j^{(l)}|),称为曼哈顿距离;\ 当p=2时,L_2(x_i,x_j)=(sum^n_{l=1}|x_i^{(l)}-x_j^{(l)}|^2)^{frac{1}{2}},其实形式上也是L2范数,称为欧式距离,平常使用的比较多;\ 当p=infty,它是各个坐标距离的最大值,即为:L_{infty}(x_i,x_j)=max|x_i^{(l)}-x_j^{(l)}| ]

    K值的选择

    除了距离度量外,还有K值的选择对KNN算法的结果也会产生重大影响。

    • 如果选择较小的k值,就相当于用较小的领域中的训练实例进行预测,“学习”的近似误差会减小,只有与输入实例较近的实例才会对预测结果起到作用,但缺点就是学习的估计误差就会增大,预测结果就会近邻的实例点非常敏感;
    • 如果选择较大的值,学习的误差估计会减小,但是与此同时,近似误差就会增大,这时会出现对于距离比较远的实例点起不到预测作用,使得预测结果错误。

    分类决策规则

    KNN中的决策规则通常就是“投票选举”——少数服从多数的方式。

    如果损失函数是0-1损失函数,那么分类函数就是:

    [f:R^n ightarrow {{c_1,c_2,...,c_k}} ]

    对于相邻k个训练实例点构成集合N,误分类率是:

    [frac{1}{k}sum_{x_iin N_k(x)}I(y_i eq c_j )=1-frac{1}{k}sum_{x_iin N_k(x)}I(y_i = c_j ) ]

    要使误分类率最小,那么就是要求正确的概率最大,所以少数服从多数的规则正好可以满足经验风险最小化。

    KNN算法

    算法描述

    [输入:训练数据集:T={(x_1,y_1),(x_2,y_2),(x_3,y_3)...,(x_N,y_N)},其中x_i in chi subseteq R^n为实例的特征向量,\ y_i in y={c_1,c_2,...,c_K}为实例得类别,i=1,2,...,;实例特征向量x;\ 输出:实例x所属的类别y。\ (1)根据给定的距离向量,在训练集T中找出与x最近邻的k个点,包含k个点的x的领域记作N_k(x);\ (2)在N_k(x)中根据分类决策规则决定x的类别y:y=argmaxsum_{x_iin N_k(x)}I(y_i = c_j ),i,j=1,2,..,N。 ]

    实现KNN时,主要是考虑的问题时如何对训练数据进行快速K近邻搜索,如果特征空间的维数大或者训练数据容量大时,那么数据存储就是一个大问题。KNN最简单的实现方法是线性扫描,这时当数据集很大,计算就非常地耗时。为了提高这种搜索效率,使用特殊地结构进行存储训练数据——kd树(kd tree)。kd树是一种对k维空间中的点进行存储以便于对其进行快速搜索的树形数据结构。实质上,kd树是一种二叉树,表示对k维空间的一个划分

    代码实现

    自编程实现

    class KNN:
        """
        使用自编程实现KNN算法
        @author cecilia
        """
        def __init__(self,X_train,y_train,k=3):
            # 所需参数初始化
            self.k=k   # 所取k值
            self.X_train=X_train
            self.y_train=y_train
    
        def predict(self,X_new):
            # 计算欧氏距离
            dist_list=[(np.linalg.norm(X_new-self.X_train[i],ord=2),self.y_train[i])
                       for i in range(self.X_train.shape[0])]
            #[(d0,-1),(d1,1)...]
            # 对所有距离进行排序
            dist_list.sort(key=lambda x: x[0])
            # 取前k个最小距离对应的类别(也就是y值)
            y_list=[dist_list[i][-1] for i in range(self.k)]
            # [-1,1,1,-1...]
            # 对上述k个点的分类进行统计
            y_count=Counter(y_list).most_common()
            # [(-1, 3), (1, 2)]
            return y_count[0][0]
    
    def main():
      	# 初始化数据
        X_train=np.array([[5,4],
                          [9,6],
                          [4,7],
                          [2,3],
                          [8,1],
                          [7,2]])
        y_train=np.array([1,1,1,-1,-1,-1])
        # 测试数据
        X_new = np.array([[5, 3]])
        # 不同的k(取奇数)对分类结果的影响
        for k in range(1,6,2):
            #构建KNN实例
            clf=KNN(X_train,y_train,k=k)
            #对测试数据进行分类预测
            y_predict=clf.predict(X_new)
            print("k={},class label is:{}".format(k,y_predict))
    

    Sklearn库

    from sklearn.neighbors import KNeighborsClassifier
    
    def sklearn_knn():
        """
        使用sklearn库实现KNN算法
        @author cecilia
        """
        X_train=np.array([[5,4],
                          [9,6],
                          [4,7],
                          [2,3],
                          [8,1],
                          [7,2]])
        y_train=np.array([1,1,1,-1,-1,-1])
        # 待预测数据
        X_new = np.array([[5, 3]])
        # 不同k值对结果的影响
        for k in range(1,6,2):
            # 构建实例
            clf = KNeighborsClassifier(n_neighbors=k,n_jobs=-1)
            # 选择合适算法
            clf.fit(X_train, y_train)
            # print(clf.kneighbors(X_new))
            # 预测
            y_predict=clf.predict(X_new)
            #print(clf.predict_proba(X_new))
            print("accuracy:{:.0%}".format(clf.score([[5,3]],[[1]])))
            print("k={},label lcass is:{}".format(k,y_predict))
    

    结果显示:

    思考

    KNN算法模型的复杂度主要是体现在哪儿?什么情况下会造成过拟合?

    k临近算法的模型复杂度体现在k值上;k值较小容易造成过拟合,k值较大容易造成欠拟合。

  • 相关阅读:
    docker 入门5
    docker 入门4
    Machine概念和获取帮助 【翻译】
    docker 入门3
    docker 入门2
    docker 入门1
    在生产环境中使用Compose 【翻译】
    docker常用命令整理
    ASP.NET WebAPI 06 HttpMessageHandler管道
    ASP.NET WebAPI 05 参数绑定
  • 原文地址:https://www.cnblogs.com/cecilia-2019/p/11329640.html
Copyright © 2011-2022 走看看