k-近邻算法属于一种分类算法。假设每一个数据都有其唯一对应的类别,k近邻算法实际就是在数据集里面确定与当前值最近的前k个点,然后确定前k个点所在的分类出现的频率,将前k个点出现频率最高的类别作为当前值的预测分类。下面以简单的程序来实现算法。
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
#k-近邻算法
#计算输入点与数据集所有点的欧氏距离,确定排序后的前k个点的类别,频率最高的类别就是预测分类
def classify0(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={}
for i in range(k):
voteIlabel=labels[sortedDistIndicies[i]]
classCount[voteIlabel]=classCount.get(voteIlabel,0)+1
sortedClassCount=sorted(classCount.iteritems(),
key=operator.itemgetter(1),reverse=True)
return sortedClassCount[0][0]
group,labels=createDataSet()
print classify0([0,0],group,labels,3)
运行的结果是:B
以上就是k-近邻算法的简单实现。
However,我们并不满足于分类的数据集只有上述例子那么少!!!如果我们用文档输入更多数据的话,我们就要将文档里面的数据读取,并将它们转化成我们需要的格式!!!下面就将k-近邻算法延伸出去。
举个实际例子。小丽是个黄花大闺女,在相亲网站上面相亲。给出的对象选择标准是“每年飞行里程数”,“玩游戏时间的百分比”,“每周吃冰激凌公斤数”。自己的喜欢程度指标有“很喜欢”,“一般喜欢”,“你是个好人”。为了能够输入数据之后就能够自动分类,因此k-近邻算法派上大用场了。首先,小丽在相亲网站上面收集了1000个数据样本,并给出了自己的喜欢程度。
为了更好表示喜欢的程度,我将“很喜欢”,“一般喜欢”,“你是个好人”转化成“3”,“2”,“1”
文档传送门:https://download.csdn.net/download/kou_ching/10855212
接下来就是数据输入转换:
#数据输入
def file2matrix(filename):
fr = open(filename)
arrayOLines=fr.readlines() #得到所有行的字符串,并生成列表
numberOfLines = len(arrayOLines) #得到文件的行数
returnMat = zeros((numberOfLines,3)) #得到 numberOfLines x 3 数组
classLabelVector = [] #p创建返回的数组
fr = open(filename)
index = 0
for line in fr.readlines():
line = line.strip() #截取这一行所有的回车字符
listFromLine = line.split('\t') #将一行数据分割成一个元素列表
returnMat[index,:] = listFromLine[0:3] #将列表的前两列放到矩阵returnMat中
classLabelVector.append(int(listFromLine[-1])) #将这一列表的最后一列放到classLabelVector中
index += 1
return returnMat,classLabelVector
但是计算两个样本的欧氏距离的时候,数据集中数值大的会影响计算结果,因此我们需要归一化数据集。
newValue=(oldValue-min) / (max-min)
#归一化数据集
def autoNorm(dataSet):
minVals = dataSet.min(0) #得到数据集每一列的最小值,得到数组
maxVals = dataSet.max(0) #得到数据集每一列的最大值,得到数组
ranges = maxVals - minVals
normDataSet = zeros(shape(dataSet))
m = dataSet.shape[0]
normDataSet = dataSet - tile(minVals, (m,1))
normDataSet = normDataSet/tile(ranges, (m,1))
return normDataSet, ranges, minVals
现在万事俱备,接下来就是测试我们算法的精确度。一般来说,训练算法是使用数据集的90%数量,而测试算法就是使用数据集的10%数量,由于小丽是无规律收集数据的,因此就可以看作是随机抽取样本来训练以及测试。
#测试算法
def datingClassTest():
hoRatio = 0.50 #hold out 10%
datingDataMat,datingLabels = file2matrix('datingTestSet2.txt') #载入数据集
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 #错误数量
将上面代码整合一下即可得到:
# -*- coding: cp936 -*-
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
def classify0(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={}
for i in range(k):
voteIlabel=labels[sortedDistIndicies[i]]
classCount[voteIlabel]=classCount.get(voteIlabel,0)+1
sortedClassCount=sorted(classCount.iteritems(),
key=operator.itemgetter(1),reverse=True)
return sortedClassCount[0][0]
#数据输入
def file2matrix(filename):
fr = open(filename)
arrayOLines=fr.readlines() #得到所有行的字符串,并生成列表
numberOfLines = len(arrayOLines) #得到文件的行数
returnMat = zeros((numberOfLines,3)) #得到 numberOfLines x 3 矩阵
classLabelVector = [] #p创建返回的numpy矩阵
fr = open(filename)
index = 0
for line in fr.readlines():
line = line.strip() #截取这一行所有的回车字符
listFromLine = line.split('\t') #将一行数据分割成一个元素列表
returnMat[index,:] = listFromLine[0:3] #将列表的前两列放到矩阵returnMat中
classLabelVector.append(int(listFromLine[-1])) #将这一列表的最后一列放到classLabelVector中
index += 1
return returnMat,classLabelVector
#归一化数据集
def autoNorm(dataSet):
minVals = dataSet.min(0) #得到数据集每一列的最小值,得到数组
maxVals = dataSet.max(0) #得到数据集每一列的最大值,得到数组
ranges = maxVals - minVals
normDataSet = zeros(shape(dataSet))
m = dataSet.shape[0]
normDataSet = dataSet - tile(minVals, (m,1))
normDataSet = normDataSet/tile(ranges, (m,1))
return normDataSet, ranges, minVals
#测试算法
def datingClassTest():
hoRatio = 0.50 #hold out 10%
datingDataMat,datingLabels = file2matrix('datingTestSet2.txt') #载入数据集
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 #错误数量
运行一次测试算法函数,得到
误差率是6.4%,相当不错的结果,可见k-近邻算法可以顺利帮小丽解决筛选对象的问题!!!
接下来就是调用整个算法框架了!!!
下面简单地使用:
# -*- coding: cp936 -*-
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
def classify0(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={}
for i in range(k):
voteIlabel=labels[sortedDistIndicies[i]]
classCount[voteIlabel]=classCount.get(voteIlabel,0)+1
sortedClassCount=sorted(classCount.iteritems(),
key=operator.itemgetter(1),reverse=True)
return sortedClassCount[0][0]
#数据输入
def file2matrix(filename):
fr = open(filename)
arrayOLines=fr.readlines() #得到所有行的字符串,并生成列表
numberOfLines = len(arrayOLines) #得到文件的行数
returnMat = zeros((numberOfLines,3)) #得到 numberOfLines x 3 矩阵
classLabelVector = [] #p创建返回的numpy矩阵
fr = open(filename)
index = 0
for line in fr.readlines():
line = line.strip() #截取这一行所有的回车字符
listFromLine = line.split('\t') #将一行数据分割成一个元素列表
returnMat[index,:] = listFromLine[0:3] #将列表的前两列放到矩阵returnMat中
classLabelVector.append(int(listFromLine[-1])) #将这一列表的最后一列放到classLabelVector中
index += 1
return returnMat,classLabelVector
#归一化数据集
def autoNorm(dataSet):
minVals = dataSet.min(0) #得到数据集每一列的最小值,得到数组
maxVals = dataSet.max(0) #得到数据集每一列的最大值,得到数组
ranges = maxVals - minVals
normDataSet = zeros(shape(dataSet))
m = dataSet.shape[0]
normDataSet = dataSet - tile(minVals, (m,1))
normDataSet = normDataSet/tile(ranges, (m,1))
return normDataSet, ranges, minVals
#测试算法
def datingClassTest():
hoRatio = 0.50 #hold out 10%
datingDataMat,datingLabels = file2matrix('datingTestSet2.txt') #载入数据集
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 #错误数量
#应用k-近邻算法
def classifyPerson():
resultList=['He is a good man','Xiao Li likes him','Xiao Li likes him so much']
percentTats=float (raw_input("percentage of time spent playing video games?"))
ffMiles=float(raw_input("frequent flier miles earned per year?"))
iceCream=float(raw_input("liters of ice-cream consumed per year"))
datingDataMat,datingLabels=file2matrix('datingTestSet2.txt')
normMat, ranges, minVals = autoNorm(datingDataMat)
inArr=array([ffMiles,percentTats,iceCream])
classifierResult=classify0((inArr-minVals)/ranges,normMat,datingLabels,3)
print "Xiao Li probably like this person: ",resultList[classifierResult-1]
classifyPerson() #应用k-近邻算法
结果: