使用KNN算法的一般步骤:
1、获取数据并转换数据格式(基本上就是转换为一个列表的形式,前面几列都是数据的相关参数,最后一列是该行数据的一个类别)
2、准备数据:归一化数值
在处理不同取值范围的特征值时,通常采用数值的归一化,如将取值范围处理为0到1或者-1到1之间
newValue = (oldValue-min)/(max-min)
3、测试算法
4、使用算法
一、准备数据
生成我们需要的已知的一个对应关系,即我们的数据(group)和改数据对应的类别(labels)
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
要求labels包含的元素个数等于group矩阵的行数
二、实施KNN分类算法
基本思路:计算已知点(group)与当前点之间的距离,然后将距离按递增排序,选取与当前点距离最小的前K个点,确定该K个点中它们对应类别出现的频率,返回该K个点中频率最高的类别属性,则当前点即被预测为该类别属性。
#k-临近算法
def classify0(inX, dataSet, labels, k): #这里第一个inX即为你要判断的数据,后边的dataSet和labels则对应前面的已知的group和labels,
dataSetSize = dataSet.shape[0] #获取dataSet的行数
#接下来几步为求解欧式距离
diffMat = tile(inX,(dataSetSize,1)) - dataSet
sqDiffMat = diffMat**2 #平方
sqDistances = sqDiffMat.sum(axis=1)
distances = sqDistances**0.5
sortedDistIndicies = distances.argsort() #对distances的数据进行排序,并返回下标数组
classCount = {} #创建了一个空字典
for i in range(k): #选择距离最小的k个点
voteIlabel = labels[sortedDistIndicies[i]]
classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1 #利用字典统计数组中的元素出现的次数
sortedClassCount = sorted(classCount.items(),key=operator.itemgetter(1),reverse=True)
return sortedClassCount[0][0] #返回最相似的值
三、完整代码
from numpy import *
import operator
import matplotlib
import matplotlib.pyplot as plt
def file2matrix(filename):
fr = open(filename) #打开文件
arrayOLines = fr.readlines()
numberOfLines = len(arrayOLines)
returnMat = zeros((numberOfLines,3))
classLabelVector = []
index = 0
for line in arrayOLines:
line = line.strip() #用于删除每行首部的空格 round(float("1.0"))
listFromLine = line.split('\t')
returnMat[index,:] = listFromLine[0:3] #将前面三列数据存入到数组里面,即生成group数组
classLabelVector.append(0.01*ord(listFromLine[-1][0])) #将最后一列数据存放到一个向量里面,即labels向量
index += 1
return returnMat,classLabelVector #返回group 数组labels
def autoNorm(dataSet): #将数据转换为0和1之间
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 classify0(inX, dataSet, labels, k): #这里第一个inX即为你要判断的数据,后边的dataSet和labels则对应前面的已知的group和labels,
dataSetSize = dataSet.shape[0] #获取dataSet的行数
#接下来几步为求解欧式距离
diffMat = tile(inX,(dataSetSize,1)) - dataSet #待定,看不懂????
sqDiffMat = diffMat**2 #平方
sqDistances = sqDiffMat.sum(axis=1) #待定,看不懂?????
distances = sqDistances**0.5
sortedDistIndicies = distances.argsort() #对distances的数据进行排序,并返回下标数组
classCount = {} #创建了一个空字典
for i in range(k): #选择距离最小的k个点
voteIlabel = labels[sortedDistIndicies[i]]
classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1 #利用字典统计数组中的元素出现的次数
sortedClassCount = sorted(classCount.items(),key=operator.itemgetter(1),reverse=True)
return sortedClassCount[0][0] #返回最相似的值
datingDataMat,datingLabels = file2matrix('helen.txt')
normMat,ranges,minVals = autoNorm(datingDataMat)
print(normMat)
def datingClassTest():
hoRatio = 0.10
datingDataMat,datingLabels = file2matrix('helen.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],4)
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)))
def classifyPerson():
resultList = ['not at all','in small doses','in large doses']
percentTats = float(input("percentage of time spent playing video games??"))
ffMiles = float(input("frequent flier miles earned per year?"))
iceCream = float(input('liters of ice cream consumed per year?'))
datingDataMat,datingLabels = file2matrix('helen.txt')
normMat,ranges ,minVals = autoNorm(datingDataMat)
inArr = array([ffMiles,percentTats,iceCream])
classifierResult = classify0((inArr-minVals)/ranges,normMat,datingLabels,3)
print("you will probably like this person:",(resultList[int(classifierResult-1)]))
if __name__ == '__main__':
classifyPerson()