美文网首页机器学习KNN
机器学习-KNN算法

机器学习-KNN算法

作者: fe512e011afe | 来源:发表于2019-08-18 10:19 被阅读7次

    本文简述KNN算法的理解。

    定义

    如果一个样本在特征空间中的k个最相似(即特征空间中最邻近)的样本中的大多数属于某一个类别,则该样本也属于这个类别。

    本文采用欧式距离,即两点之间的直接距离。

    思想

    通过你的邻居,判断你是哪种类型

    KNN算法流程总结

    
    1)计算已知类别数据集中的点与当前点之间的距离
    
    2)按距离递增次序排序
    
    3)选取与当前点距离最小的k个点
    
    4)统计前k个点所在的类别出现的频率
    
    5)返回前k个点出现频率最高的类别作为当前点的预测分类
    
    
    
    from sklearn.neighbors import KNeighborsClassifier
    
    # achieve data
    
    x = [[1],[2],[3],[-1],[-4]]
    
    y = [1,1,1,0,-1]
    
    estimator = KNeighborsClassifier(n_neighbors=3)
    
    estimator.fit(x,y)
    
    result = estimator.predict([[-3]])
    
    print(result)
    
    
    [-1]
    

    问题一:距离选取

    1.距离公式,除了欧式距离,还有哪些距离公式可以使用?

    
    (1)欧式距离(两点距离问题):两个点在空间中的距离。
    
    (2)曼哈顿距离(城市街区问题):在曼哈顿街区要从一个十字路口开车到另一个十字路口,驾驶距离显然不是两点间的直线距离。这个实际驾驶距离就是“曼哈顿距离”。曼哈顿距离也称为“城市街区距离”(City Block distance)。
    
        d(i,j)=|X1-X2|+|Y1-Y2|
    
    (3)切比雪夫距离 (Chebyshev Distance):国际象棋中,国王可以直行、横行、斜行,所以国王走一步可以移动到相邻8个方格中的任意一个。国王从格子(x1,y1)走到格子(x2,y2)最少需要多少步?这个距离就叫切比雪夫距离。在公式里体现就是某个维度上的最大距离。
    
    (4)闵可夫斯基距离(Minkowski Distance):闵氏距离不是一种距离,而是一组距离的定义,是对多个距离度量公式的概括性的表述。
    
    两个n维变量a(x11,x12,…,x1n)与b(x21,x22,…,x2n)间的闵可夫斯基距离定义为:
    
    其中p是一个变参数:
    
    当p=1时,就是曼哈顿距离;
    
    当p=2时,就是欧氏距离;
    
    当p→∞时,就是切比雪夫距离。
    
    根据p的不同,闵氏距离可以表示某一类/种的距离
    
    

    小结:

    1 闵氏距离,包括曼哈顿距离、欧氏距离和切比雪夫距离都存在明显的缺点:

    e.g. 二维样本(身高[单位:cm],体重[单位:kg]),现有三个样本:a(180,50),b(190,50),c(180,60)。

    a与b的闵氏距离(无论是曼哈顿距离、欧氏距离或切比雪夫距离)等于a与c的闵氏距离。但实际上身高的10cm并不能和体重的10kg划等号。

    闵氏距离的缺点:

    
    ​ (1)将各个分量的量纲(scale),也就是“单位”相同的看待了;
    
    ​ (2)未考虑各个分量的分布(期望,方差等)可能是不同的。
    
    

    改进

    
    标准化欧氏距离 (Standardized EuclideanDistance):标准化欧氏距离是针对欧氏距离的缺点而作的一种改进。
    
    思路:既然数据各维分量的分布不一样,那先将各个分量都“标准化”到均值、方差相等。
    
    

    其他距离

    
    (1)余弦距离(Cosine Distance):
    
    几何中,夹角余弦可用来衡量两个向量方向的差异;机器学习中,借用这一概念来衡量样本向量之间的差异。
    
    (2)汉明距离(Hamming Distance):
    
    两个等长字符串s1与s2的汉明距离为:将其中一个变为另外一个所需要作的最小字符替换次数。
    
    (3)杰卡德距离(Jaccard Distance):
    
    杰卡德相似系数(Jaccard similarity coefficient):两个集合A和B的交集元素在A,B的并集中所占的比例,称为两个集合的杰卡德相似系数,用符号J(A,B)。
    
    杰卡德距离(Jaccard Distance):与杰卡德相似系数相反,用两个集合中不同元素占所有元素的比例来衡量两个集合的区分度
    
    (4)马氏距离(Mahalanobis Distance):马氏距离是由印度统计学家马哈拉诺比斯提出的,表示数据的协方差距离。它是一种有效的计算两个位置样本集的相似度的方法。马氏距离也可以定义为两个服从同一分布并且其协方差矩阵为∑的随机变量的差异程度:如果协方差矩阵为单位矩阵,马氏距离就简化为欧式距离;如果协方差矩阵为对角矩阵,则其也可称为正规化的欧式距离。
    
    马氏距离特性:
    
        1.量纲无关,排除变量之间的相关性的干扰;
    
        2.马氏距离的计算是建立在总体样本的基础上的,如果拿同样的两个样本,放入两个不同的总体中,最后计算得出的两个样本间的马氏距离通常是不相同的,除非这两个总体的协方差矩阵碰巧相同;
    
        3 .计算马氏距离过程中,要求总体样本数大于样本的维数,否则得到的总体样本协方差矩阵逆矩阵不存在,这种情况下,用欧式距离计算即可。
    
        4.还有一种情况,满足了条件总体样本数大于样本的维数,但是协方差矩阵的逆矩阵仍然不存在,比如三个样本点(3,4),(5,6),(7,8),这种情况是因为这三个样本在其所处的二维空间平面内共线。这种情况下,也采用欧式距离计算。
    
    

    问题二:K值的选取

    2.选取K值的大小?

    
    K值过小:
    
    容易受到异常点的影响
    
    k值过大:
    
    受到样本均衡的问题
    
    
    解决方法

    参考:

    
    K值选择问题,李航博士的一书「统计学习方法」上所说:
    
    1) 选择较小的K值,就相当于用较小的领域中的训练实例进行预测,“学习”近似误差会减小,只有与输入实例较近或相似的训练实例才会对预测结果起作用,与此同时带来的问题是“学习”的估计误差会增大,换句话说,K值的减小就意味着整体模型变得复杂,容易发生过拟合;
    
    2) 选择较大的K值,就相当于用较大领域中的训练实例进行预测,其优点是可以减少学习的估计误差,但缺点是学习的近似误差会增大。这时候,与输入实例较远(不相似的)训练实例也会对预测器作用,使预测发生错误,且K值的增大就意味着整体的模型变得简单。
    
    3) K=N(N为训练样本个数),则完全不足取,因为此时无论输入实例是什么,都只是简单的预测它属于在训练实例中最多的类,模型过于简单,忽略了训练实例中大量有用信息。
    
    

    在实际应用中,K值一般取一个比较小的数值,例如采用交叉验证法(简单来说,就是把训练数据在分成两组:训练集和验证集)来选择最优的K值。

    近似误差:

    对现有训练集的训练误差,关注训练集.

    如果近似误差过小可能会出现过拟合的现象,对现有的训练集能有很好的预测,但是对未知的测试样本将会出现较大偏差的预测。

    模型本身不是最接近最佳模型。

    估计误差:

    理解为对测试集的测试误差,关注测试集。

    估计误差小说明对未知数据的预测能力好。

    模型本身最接近最佳模型。

    鸢尾花代码实现

    
    """
    
    1.获取数据集
    
    2,数据基本处理
    
    3. 特征工程
    
    4. 机器学习(模型训练)
    
    5. 模型评估
    
    """
    
    from sklearn.datasets import load_iris
    
    from sklearn.model_selection import train_test_split
    
    from sklearn.preprocessing import StandardScaler
    
    from sklearn.neighbors import KNeighborsClassifier
    
    # 1.获取数据集
    
    iris = load_iris()
    
    # 2,数据基本处理
    
    # 2.1 数据分割
    
    x_train, x_test, y_train, y_test = train_test_split(iris.data, iris.target, random_state=23, test_size=0.1)
    
    # 3. 特征工程
    
    # 3.1 实例化一个转化器
    
    transfer = StandardScaler()
    
    # 3.2 调用fit_transform方法
    
    x_train = transfer.fit_transform(x_train)
    
    x_test = transfer.fit_transform(x_test)
    
    # 4. 机器学习(模型训练)
    
    # 4.1 实例化一个估计器
    
    estimator = KNeighborsClassifier(n_neighbors=5)
    
    # 4.2 模型训练
    
    estimator.fit(x_train,y_train)
    
    # 5. 模型评估
    
    # 5.1 输出预测值
    
    y_pre = estimator.predict(x_test)
    
    print("预测值是:\n", y_pre)
    
    # 5.2 输出准确率
    
    ret = estimator.score(x_test, y_test)
    
    print("准确率:\n", ret)
    
    

    KNN 算法总结

    优点
    • 简单有效

    • 重新训练代价低

    • 适合类域交叉样本:KNN方法主要靠周围有限的邻近的样本,而不是靠判别类域的方法来确定所属类别的,因此对于类域的交叉或重叠较多的待分样本集来说,KNN方法较其他方法更为适合。

    • 该算法比较适用于样本容量比较大的类域的自动分类,而那些样本容量较小的类域采用这种算法比较容易产生误分。

    缺点
    • 惰性算法

    • 类别评分不是规格化

    • 对不均衡的样本不擅长

    当样本不平衡时,如一个类的样本容量很大,而其他类样本容量很小时,有可能导致当输入一个新样本时,该样本的K个邻居中大容量类的样本占多数。该算法只计算“最近的”邻居样本,某一类的样本数量很大,那么或者这类样本并不接近目标样本,或者这类样本很靠近目标样本。无论怎样,数量并不能影响运行结果。可以采用权值的方法(和该样本距离小的邻居权值大)来改进。

    • 计算量较大

    目前常用的解决方法是事先对已知样本点进行剪辑,事先去除对分类作用不大的样本。

    【引入】交叉验证&网格搜索

    交叉验证

    交叉验证:将拿到的训练数据,分为训练和验证集。以下图为例:将数据分成4份,其中一份作为验证集。然后经过4次(组)的测试,每次都更换不同的验证集。即得到4组模型的结果,取平均值作为最终结果。又称4折交叉验证。

    目的:为了让被评估的模型更加准确可信

    为了让从训练得到模型结果更加准确。做以下处理

    
    训练集:训练集+验证集
    
    测试集:测试集
    
    

    [图片上传失败...(image-f3335f-1566094680975)]

    网格搜索

    通常情况下,有很多参数是需要手动指定的(如k-近邻算法中的K值),这种叫超参数。但是手动过程繁杂,所以需要对模型预设几种超参数组合。每组超参数都采用交叉验证来进行评估。最后选出最优参数组合建立模型。

    atater
    代码实现
    
    sklearn.model_selection.GridSearchCV(estimator, param_grid=None,cv=None)
    
    estimator -- 选择了哪个训练模型
    
    param_grid -- 需要传递的超参数
    
    cv -- 几折交叉验证
    
    
    
    """
    
    1.获取数据集
    
    2,数据基本处理
    
    3. 特征工程
    
    4. 机器学习(模型训练)
    
    5. 模型评估
    
    """
    
    from sklearn.datasets import load_iris
    
    from sklearn.model_selection import train_test_split, GridSearchCV
    
    from sklearn.preprocessing import StandardScaler
    
    from sklearn.neighbors import KNeighborsClassifier
    
    # 1.获取数据集
    
    iris = load_iris()
    
    # 2,数据基本处理
    
    # 2.1 数据分割
    
    x_train, x_test, y_train, y_test = train_test_split(iris.data, iris.target, test_size=0.2)
    
    # 3. 特征工程
    
    # 3.1 实例化一个转化器
    
    transfer = StandardScaler()
    
    # 3.2 调用fit_transform方法
    
    x_train = transfer.fit_transform(x_train)
    
    x_test = transfer.fit_transform(x_test)
    
    # 4. 机器学习(模型训练)
    
    # 4.1 实例化一个估计器
    
    estimator = KNeighborsClassifier(n_neighbors=1)
    
    # 4.2 调用交叉验证网格搜索模型
    
    param_grid = {"n_neighbors": [1, 3, 5, 7, 9]}
    
    estimator = GridSearchCV(estimator, param_grid=param_grid, cv=10, n_jobs=4)
    
    # 4.3 模型训练
    
    estimator.fit(x_train, y_train)
    
    # 5. 模型评估
    
    # 5.1 输出预测值
    
    y_pre = estimator.predict(x_test)
    
    print("预测值是:\n", y_pre)
    
    # 5.2 输出准确率
    
    ret = estimator.score(x_test, y_test)
    
    print("准确率:\n", ret)
    
    # 5.3 其他平均指标
    
    print("最好的模型:\n", estimator.best_estimator_)
    
    print("最好的结果:\n", estimator.best_score_)
    
    print("整体模型结果:\n", estimator.cv_results_)
    
    

    相关文章

      网友评论

        本文标题:机器学习-KNN算法

        本文链接:https://www.haomeiwen.com/subject/vlqrsctx.html