一、概述
优点:精度高、对异常值不敏感、无数据输入限定
缺点:计算复杂度高、空间复杂度高
使用数据范围:数值型和标称型。
二、原理
存在一个样本数据集合(训练样本集合),并且样本集中每一个数据都存在标签,即我们知道样本集中每一个数据与所属分类的对应关系。输入没有标签的新数据,将新数据的每个特征值与样本集中的数据对应的特征进行比较。然后算法提取样本集中特征最相似的分类标签。通常k不大于20的整数。
三、例子1:电影分类
分类爱情片和动作片。统计很多电影中打斗镜头和接吻镜头。
电影名称 | 打斗镜头 | 接吻镜头 | 电影类型 |
california man | 3 | 104 | 爱情片 |
he's not really into dudes | 2 | 100 | 爱情片 |
beautiful woman | 1 | 81 | 爱情片 |
kevin longblade | 101 | 10 | 动作片 |
robo slayer 3000 | 99 | 5 | 动作片 |
amped II | 98 | 2 | 动作片 |
? | 18 | 90 | ? |
电影名称 | 与未知电影距离 |
california man | 20.5 |
he's not really into dudes | 18.7 |
beautiful woman | 19.2 |
kevin longblade | 115.3 |
robo slayer 3000 | 117.4 |
amped II | 118.9 |
假定k=3 依次是california man,he's not really into dudes,beautiful woman ===> 判定为爱情片
四、例子2:约会网站的配对效果
玩视频游戏所耗时间百分比 | 每年获得飞行常客里程数 | 每周消费的冰激凌公升数 | 样本分类 |
0.8 | 400 | 0.5 | 1 |
12 | 134000 | 0.9 | 3 |
0 | 20000 | 1.1 | 2 |
1.收集数据:提供文本文件
==>每个样本数据占据一行,总共1000行,包含3个特征
a.每年获得飞行常客里程数
b.玩视频游戏所耗时间百分比
c.每周消费的冰激凌公升数
2.准备数据:数据归一化
kNN使用欧几里得距离公式
[(0.8-12)^2 + (400 - 134000)^2 + (0.5 - 0.9)^2]^0.5
===> 容易看出,数值大的属性对计算结果的影响最大。也就是说“每年获得飞行常客里程数”的影响要远远大于其他属性的影响。我们需要等权重特征化。
newValue = (oldValue - min)/(max - min)
$ cat datingTestSet2.txt | head -n 4
40920 8.326976 0.953952 3
14488 7.153469 1.673904 2
26052 1.441871 0.805124 1
75136 13.147394 0.428964 1
# 文本文件转换成数据矩阵
def file2matrix(filename):
fr = open(filename)
arrayOLines = fr.readlines() ==>读取文档有多少行,要构建矩阵
numberOfLines = len(arrayOLines)
returnMat = zeros((numberOfLines,3)) ==>初始0矩阵
classLabelVector= []
index = 0
for line in arrayOLines:
line = line.strip()
listFromLine = line.split('\t') ==> \t 分隔每一行
returnMat[index,:] = listFromLine[0:3] ==> 每一行特征值组成矩阵的一行
classLabelVector.append(int(listFromLine[-1])) ==> 标签向量
index += 1
return returnMat,classLabelVector
#数据归一化
#newValue = (oldValue - min)/(max - min)
def autoNorm(dataSet):
minVals = dataSet.min(0) ==>计算矩阵每一列最小值
maxVals = dataSet.max(0) ==>计算矩阵每一列最大值
ranges = maxVals - minVals ==>矩阵相减,即对应行向减
m = dataSet.shape[0] ==>矩阵行数
normDataSet = dataSet - tile(minVals, (m,1)) ==>tile(minVals, (m,1))构建行数相同的最小值矩阵
normDataSet = normDataSet / tile(ranges, (m,1)) ==>tile(ranges, (m,1))构建行数相同的差值矩阵
return normDataSet,ranges,minVals
def datingClassTest():
hoRatio = 0.1 ==>切分样本,一部分作为训练样本,一部分作为测试样本
datingDataMat,datingLabels = file2matrix('') ==>加载文本文件,并转化为数据矩阵
normMat,ranges,minVals = autoNorm(datingDataMat) ==>数据归一化
m = normMat.shape[0]
numTestVecs = int(m*hoRatio)
errorCount = 0.0
for i in range(numTestVecs):
classifierResult = classify0(normMat[i,:], normMat[numTestVecs:m,:], datingLabels[numTestVecs:m], 3) ==>对输入的测试集的每一行进行判定
print 'the classifier came back with:%d, the real answer is:%d' % (classifierResult,datingLabels[i])
if(classifierResult != datingLabels[i]): ==>对比计算结果和原始结果,统计错误率
errorCount+=1.0
print 'the total error rate is: %f' % (errorCount/float(numTestVecs))
print errorCount