【机器学习实战】KNN近邻算法

K-近邻算法概述

采用不同特征值之间的距离方法进行分类

优点:精度高、对异常值不敏感、无数据输入假定

缺点:计算复杂度高,空间复杂度高

适用范围:数值类型和标称型

 

有一个训练样本集,每个样本都有标签,输入新数据,将新数据和旧的进行比较,然后提取最相似数据的标签。一般是选择K个,不大于20,最后选择k个最相似数据中出现次数最多的分类,作为新数据的分类。

电影:亲吻次数、打斗次数来分类爱情片还是动作片

数据如下:

电影名称

打斗镜头

亲吻镜头

电影类型

California Man

3

104

爱情片

He's Not Really into Dues

2

100

爱情片

Robo Salyer 3000

99

5

动作片

计算出新电影与旧电影的距离,按照距离递增排序,找到k个距离最近的电影,它们的类型来决定未知电影的类型

2.1.1 准备:适用Python导入数据

代码:kNN.py

from numpy import *
import operator

def createDataSet():
    group = array([[1.0,1.1],[1.0,1.0],[0,0],[0,0.1]])
    labels = ['A','A','B','B']
    return group,labels
    
group,labels = kNN.createDataSet()

 

2.1.2 从文本文件中解析数据

伪代码

对未知类别属性的数据集中的每个点依次执行以下操作:

  1. 计算已知类别数据集中点与当前点之间的距离
  2. 按照距离递增排序
  3. 选取与当前点距离最小的k个点
  4. 确定前k个点所在类别的出现频率
  5. 返回前K个点出现频率最高的类别作为当前点的预测分类
def classifyKNN(inX,dataSet,labels,k):
    dataSetSize = dataSet.shape[0]
    # 距离计算
    diffMat = tile(inx,(dataSetSize,1)) - dataSet
    sqDiffMat = diffMat ** 2
    sqDistances = sqDiffMat.sum(axis=1)
    distances = sqDistances ** 0.5
    sortedDistIndicies = distances.argsort()
    classCount = {}
    # 选择k个点
    for i in range(k):
        voteIlabel = labels[sortedDistIndicies[i]]
        classCount[voteIlabel ] = classCount.get(voteIlabel ,0) + 1
   # 排序
   sortedClassCount = sorted(classCount.iteritems(),key=operator.itegetter(1),reverse=True)     
   return sortedClassCount[0][0]
kNN.classifyKNN([0,0],group,labels,3)  

使用的是欧式距离

d= sqrt( (xA0-xB0)^2 + (xA1-xB1)^2)

点(0,0)与(1,2)的距离是:sqrt(5)

np.tile(testData, (rowSize, 1)) 是将 testData 这个数据扩展为 rowSize 列,这样能避免运算错误;

sorted(count.items(), key=operator.itemgetter(1), reverse=True) 排序函数,里面的参数 key=operator.itemgetter(1), reverse=True 表示按照 count 这个字典的值(value)从高到低排序,如果把 1 换成 0,则是按字典的键(key)从高到低排序。把 True 换成 False 则是从低到高排序。

 

完整的的代码

#!/user/bin/env python
#-*- coding:utf-8 -*-
import numpy as np
import operator as opt

# 标准化数据
def normData(dataSet):
    maxVals = dataSet.max(axis=0)#按列获取最大值,并返回数组
    minVals = dataSet.min(axis=0)
    ranges = maxVals - minVals
    retData = (dataSet - minVals) / ranges
    return retData, ranges, minVals
    
def kNN(dataSet, labels, testData, k):
    distSquareMat = (dataSet - testData) ** 2 # 计算差值的平方
    distSquareSums = distSquareMat.sum(axis=1) # 求每一行的差值平方和,axis=0则按列计算
    distances = distSquareSums ** 0.5 # 开根号,得出每个样本到测试点的距离
    sortedIndices = distances.argsort() # 排序,得到排序后的下标
    indices = sortedIndices[:k] # 取最小的k个
    labelCount = {} # 存储每个label的出现次数,出现次数最多的就是我们要选择的类别
    for i in indices:
        label = labels[i]
        labelCount[label] = labelCount.get(label, 0) + 1 # 次数加一,使用字典的get方法,第一次出现时默认值是0
    sortedCount = sorted(labelCount.items(), key=opt.itemgetter(1), reverse=True) # 对label出现的次数从大到小进行排序
 return sortedCount[0][0] # 返回出现次数最大的label
 
if __name__ == "__main__":
 dataSet = np.array([[2, 3], [6, 8]])#训练集
 normDataSet, ranges, minVals = normData(dataSet)
 labels = ['a', 'b']#训练集分别为a和b类
 testData = np.array([3.9, 5.5])#测试数据
 normTestData = (testData - minVals) / ranges#同样需要将测试数据标准化
 result = kNN(normDataSet, labels, normTestData, 1)#k=1
 print(result)  


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值