手撕KNN算法
对未知类别属性的数据集中的每个点依次执行以下操作:
(1) 计算已知类别数据集中的点与当前点之间的距离;
(2) 按照距离递增次序排序;
(3) 选取与当前点距离最小的k个点;
(4) 确定前k个点所在类别的出现频率;
(5) 返回前k个点出现频率最高的类别作为当前点的预测分类
from numpy import *
import operator
from os import listdir
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]
print(tile(inX, (dataSetSize, 1)))#主要是为了可以让【0,0】依次跟所有的点相减
diffMat = tile(inX, (dataSetSize, 1)) - dataSet#这一步就是,计算每个点跟【0,0】的距离差
print(diffMat)
sqDiffMat = diffMat ** 2#用欧氏距离公式,差值进行平方之和
sqDistances = sqDiffMat.sum(axis=1)#对矩阵的每一行求和
distances = sqDistances ** 0.5#对每一行的值求开方
sortedDistIndicies = distances.argsort()#根据argsort()函数是将x中的元素从小到大排列,提取其对应的index(索引)索引进行排序
classCount = {}
for i in range(k):
voteIlabel = labels[sortedDistIndicies[i]]#得到离【0,0】值最近的距离是B类别
classCount[voteIlabel] = classCount.get(voteIlabel, 0) + 1#代表这个标签加一
sortedClassCount = sorted(classCount.items(), key=operator.itemgetter(1), reverse=True)
return sortedClassCount[0][0]
group, labels = createDataSet()
print(group, labels)
classify0([0,0], group, labels, 3)
使用 k-近邻算法改进约会网站的配对效果
(1) 收集数据:提供文本文件。
(2) 准备数据:使用Python解析文本文件。
(3) 分析数据:使用Matplotlib画二维扩散图。
(4) 训练算法:此步骤不适用于k-近邻算法。
(5) 测试算法:使用海伦提供的部分数据作为测试样本。
测试样本和非测试样本的区别在于:测试样本是已经完成分类的数据,如果预测分类
与实际类别不同,则标记为一个错误。
(6) 使用算法:产生简单的命令行程序,然后海伦可以输入一些特征数据以判断对方是否
为自己喜欢的类型。
1.处理数据解析
def file2matrix(filename):
love_dictionary={'largeDoses':3, 'smallDoses':2, 'didntLike':1}
fr = open(filename)
arrayOLines = fr.readlines()#拿到所有行数据
numberOfLines = len(arrayOLines) #get the number of lines in the file
returnMat = zeros((numberOfLines,3))#构建一个1000行3列的数组,俗称三维数组
print(returnMat)#prepare matrix to return
classLabelVector = [] #prepare labels return
index = 0
for line in arrayOLines:
line = line.strip()
listFromLine = line.split('\t')
returnMat[index,:] = listFromLine[0:3]#可以理解为插入,每一行的数据的前三个,插入到哪个三维数组里
print(returnMat[index,:])
if(listFromLine[-1].isdigit()):
classLabelVector.append(int(listFromLine[-1]))
else:
classLabelVector.append(love_dictionary.get(listFromLine[-1]))#找到对应的字典的数填进去
index += 1
return returnMat,classLabelVector
path = r'F:\2022\机器学习实战源码\machine_learning_in_action_py3-master\src\ch02\datingTestSet.txt'
#数据可以网上搜
returnMat,classLabelVector = file2matrix(path)
准备数据:归一化数值
#在处理这种不同取值范围的特征值时,我们通常采用的方法是将数值归一化,如将取值范围处理为0到1或者1到1之间。下面的公式可以将任意取值范围的特征值转化为0到1区间内的值
def autoNorm(dataSet):
minVals = dataSet.min(0)#把这个三维数组的每一列的最小值找出来,拼成一个新的数组【0,0,0.001156】
maxVals = dataSet.max(0)#拿到这个三维数组的最大值拼成一个新的数组【[9.1273000e+04 2.0919349e+01 1.6955170e+00]】
ranges = maxVals - minVals#【[9.1273000e+04 2.0919349e+01 1.6943610e+00]】
normDataSet = zeros(shape(dataSet))
m = dataSet.shape[0]
normDataSet = dataSet - tile(minVals, (m,1))#每一行的值减去最小值
normDataSet = normDataSet/tile(ranges, (m,1)) #element wise divide
return normDataSet, ranges, minVals
normat , ranges , minvals = autoNorm(returnMat)
预测
def classifyPerson(path):
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(path)
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: {}".format(resultList[classifierResult - 1]))
path2 = r'F:\2022\机器学习实战源码\machine_learning_in_action_py3-master\src\ch02\datingTestSet2.txt'
classifyPerson(path2)