"""
(1) 收集数据:提供文本文件
(2) 准备数据:使用Python解析文本文件
(3) 分析数据:使用Matplotlib画二维扩散图
(4) 训练算法:此步骤不适用k-近邻算法
(5) 测试算法:使用海伦提供的部分数据作为测试样本
测试样本和非测试样本的区别在于:测试样本是已经完成分类的数据,如果预测分类与实际样本类别不同
则标记为一个错误
(6) 使用算法:产生简单的命令行程序,然后海伦可以输入一些特征数据以判断对方
是否为自己喜欢的类型
"""
import matplotlib.pyplot as plt
from numpy import *
def classify0(inX, dataSet, labels, k):
"""
共有四个输入参数:用于分类的输入向量是inX,输入的训练样本集为dataSet
标签向量为labels, 最后的参数k表示用于选择最邻近的数目,其中标签向量的元素数目和
矩阵dataSet的行数相同。计算的距离为欧氏距离
:param inX:
:param dataSet:
:param labels:
:param k:
:return:
"""
# 计算欧氏距离
dataSetSize = dataSet.shape[0] # dataSet.shape[0]输出的是数据集的行数,shape[1]输出的是数据集的列数
diffMat = tile(inX, (dataSetSize, 1)) - dataSet # tile函数共有两个参数,tile(A, reps), A指待输入数组,reps决定A重复的次数,整个函数用于重复数组A来构建新的数组
sqDiffMat = diffMat ** 2 # 计算欧氏距离
sqDistances = sqDiffMat.sum(axis=1) # 按行求和,
distance = sqDistances ** 0.5 # 开根号,结果为该未知数据集到每一个已知数据集的欧氏距离
# 选择距离最小的k个点
sortedDistIndicies = distance.argsort() # argsort()方法返回数组值从小到大的索引
classCount = {}
for i in range(k):
voteIlabel = labels[sortedDistIndicies[i]] # 获取所属类别
classCount[voteIlabel] = classCount.get(voteIlabel, 0) + 1 # get方法返回指定键的值,如果不存在则返回默认值(0:设置默认值为0)
sortedClassCount = sorted(classCount.items(), key=operator.itemgetter(1), reverse=True) # items()返回字典列表操作后的迭代 sorted(可迭代对象, 自定义的比较函数, 顺序默认为Fslse,正序)
return sortedClassCount[0][0]
def file2matrix(filename):
"""
该函数输入为文件名字符转, 输出为训练样本矩阵和类标签向量
:param filename:
:return:
"""
fr = open(filename)
arrayLines = fr.readlines() # readlines()方法读取整个文件所有行,保存在一个列表变量中,每行作为一个元素,但读取大文件时比较占内存
numberOfLines = len(arrayLines) # 输出列表的长度,即文件的长度
print("文件的长度为:", numberOfLines)
returnMat = zeros((numberOfLines, 3)) # 创建返回的NumPy矩阵zeros方法返回来一个给定形状和类型的用0填充的数组
classLabelVector = []
index = 0
for line in arrayLines:
line = line.strip() # strip方法可饭会移除字符串头尾指定的字符串生成新的字符串(传入指定参数)截取所有的回车符
# print(line)
# print("-"*100)
listFromLine = line.split("\t")
# print(listFromLine)
# print("-" * 100)
returnMat[index, :] = listFromLine[0: 3]
classLabelVector.append(int(listFromLine[-1]))
index += 1
return returnMat, classLabelVector
def myplot(returnMat):
"""
绘图
:param returnMat:
:return:
"""
fig = plt.figure()
ax = fig.add_subplot(111)
ax.scatter(returnMat[:, 1], returnMat[:, 2])
plt.show()
def autoNorm(dataSet):
"""
归一化处理,每一列的最小值放在变量minVals中,将最大值放在变量maxVals中,其中
dataSet.min(0)中的参数0使得函数可以从列中选取最小值,而不是选取当前行的最小值
然后,函数计算可能的取值范围,并创建新的返回矩阵,为了归一化特征值,我们必须使用当前值
减去最小值,然后除以取值范围,需要注意的是,特征值矩阵有1000*3个值,而minVals和ranges的
都为1*3,为了解决这个问题,我们使用NumPy库中tile()函数将变量内容复制成输入矩阵同样大小的矩阵
的矩阵,
:param dataSet:
:return:
"""
minVals = dataSet.min(0) # min(0)返回该矩阵中每一列的最小值,min(1)返回该矩阵中每一行的最小值
maxVals = dataSet.max(0) # max(0)返回该矩阵中每一列的最大值,max(1)返回该矩阵中每一行的最大值
ranges = maxVals - minVals
zeros(shape(dataSet)) # shape(dataSet)返回dataSet矩阵的类型(1000×3), zeros返回零矩阵
m = dataSet.shape[0] # 返回数据的行值
normDataSet = dataSet - tile(minVals, (m, 1))
normDataSet = normDataSet / tile(ranges, (m, 1))
return normDataSet, ranges, minVals
def datingClassTest():
"""
首先使用file2matrix和autoNorm函数从文件中读取数据并将其转换为归一化特征值
接着计算测试向量的数量,此步决定了哪些数据用于测试,哪些数据用于分类器的训练样本
然后将这两部分数据输入到原始分类器函数classify0,最后,函数计算错误率并输出结果
此外我们使用原始分类器
:return:
"""
hoRatio = 0.10
# 读取数据,转为矩阵形式
datingDataMat, datingLabels = file2matrix("data/datingTestSet2.txt")
# 将数据转换为归一化特征值
normMat, ranges, minVals = autoNorm(datingDataMat)
m = normMat.shape[0]
numTestVecs = int(m * hoRatio) # 选取90%作为训练集,10%作为测试集
errorCount = 0.0
for i in range(numTestVecs):
classifierResult = classify0(normMat[i, :], normMat[numTestVecs:m, :], datingLabels[numTestVecs:m], 3)
print("the classifierResult 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)))
if __name__ == '__main__':
datingClassTest()
k-近邻算法在约会网站上的使用
最新推荐文章于 2020-03-30 12:47:23 发布