报错1:No module named ‘kNN’
解决:
转而在Spyder中,先保存在自己的学习目录中,然后在命令提示符完成操作,保证目录要一致,也就是下面图中打马赛克的4个。
报错: name ‘reload’ is not defined
解决:
先调用imp标准库模块中可用的reload函数, 再模块重载
报错:ValueError: invalid literal for int() with base 10: 'largeDoses'
解决:
将datingClassTest()函数中第二行代码,打开的文件名改为datingTestSet2.txt即可。
原因:
比较datingTestSet.txt和datingTestSet2.txt,主要的区别是最后的标签,datingTestSet.txt中使用字符串‘veryLike’作为标签,但是Python转换会出现ValueError: invalid literal for int() with base 10: 'largeDoses'的错误。后面datingTestSet2.txt中直接用1 2 3 代表not like, general like, very like,所以可以正常解析。
最终成功执行结果:
附完整代码:
# -*- coding: utf-8 -*-
"""
Created on Mon Feb 25 11:32:55 2019
@author: Administrator
"""
# 导入科学计算包Numpy
import numpy as np
# 导入运算符模块,k-近邻算法执行排序操作时将使用这个模块提供的函数
import operator
'''
为了确保输入相同的数据集,kNN模块中定义了函数createDataSet
'''
def createDataSet():
group = np.array([[1.0 , 1.1], [1.0, 1.0], [0, 0], [0, 0.1]])
labels = ['A', 'A', 'B', 'B'] # 包含了每个数据点的标签信息
return group, labels
'''
classify0有四个输入变量,用于分类的输入向量是inX,输入的样本集是dataSet,
标签向量为labels,k是用于选择最近的邻居数目,其中标签向量的元素数目和矩阵
dataSet的行数相同。
'''
def classify0(inX, dataSet, labels, k):
dataSetSize = dataSet.shape[0] #返回矩阵的行数,即有多少组数据
diffMat = np.tile(inX, (dataSetSize, 1)) - dataSet #tile函数的作用是让某个数组以某种方式重复,构造出新的数组
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]]
#get(voteIlabel, 0):返回指定键的值,若不在字典中就返回0
classCount[voteIlabel] = classCount.get(voteIlabel, 0) + 1
#按照第二个元素的次序对元组进行从大到小的排序
sortedClassCount = sorted(classCount.items(), key = operator.itemgetter(1), reverse = True)
return sortedClassCount[0][0] #返回发生频率最高的元素标签
'''
处理输入的格式问题
'''
def file2matrix(filename):
fr = open(filename) #打开文件
arrayOLines = fr.readlines() #返回列表,包含所有的行
numberOfLines = len(arrayOLines) #得到文件的行数
returnMat = np.zeros((numberOfLines, 3)) #创建返回的Numpy矩阵
classLabelVector = []
index = 0
for line in arrayOLines:
line = line.strip() #截取掉所有的回车符
listFromLine = line.split('\t') #将整行数据分割成一个元素列表
returnMat[index, :] = listFromLine[0: 3] #选取前三个元素,将它们存储到特征矩阵中t
classLabelVector.append(int(listFromLine[-1])) #将列表中的最后一列存储到向量中
index += 1
return returnMat, classLabelVector #输出为训练样本矩阵和类标签向量
'''
归一化特征值,将数字特征值转化为0~1的区间
'''
def autoNorm(dataSet):
minVals = dataSet.min(0) #参数0使得函数可以从列中选取最小值,而不是选取当前行的最小值
maxVals = dataSet.max(0) #选取列的最大值
ranges = maxVals - minVals #返回矩阵的规模
normDataSet = np.zeros(np.shape(dataSet))
m = dataSet.shape[0] #返回数据集中矩阵的行数
# minVals与ranges都是1*3的矩阵,通过tile函数被扩展为m*3的矩阵,这就是tile函数的作用
normDataSet = dataSet - np.tile(minVals, (m,1))
normDataSet = normDataSet / np.tile(ranges, (m,1)) #特征值相除
return normDataSet, ranges, minVals
'''
分类器针对约会网站的测试代码
'''
def datingClassTest():
hoRatio = 0.10 #取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):
#normMat[i,:]是指用于分类的测试数据;normMat[numTestVecs:m,:]是指其他90%的训练数据;datingLabels[numTestVecs:m]是指训练数据对应的标签;k=3
classifierResult = classify0(normMat[i,:], normMat[numTestVecs:m,:], datingLabels[numTestVecs:m], 3)
#datingLabels[i]是指测试数据在原数据集中的真实标签
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('datingTestSet2.txt') #解析文本文件
normMat, ranges, minVals = autoNorm(datingDataMat) #归一化数据
inArr = np.array([ffMiles, percentTats, iceCream])
#classify0的三个输入数据分别是:用于分类的输入向量,输入的数据集,标签向量,最近的邻居数目
classifierResult = classify0((inArr-minVals) / ranges, normMat, datingLabels, 3)
print("You will probably like this person: ", resultList[classifierResult - 1])
'''
数据可视化
'''
import matplotlib.pyplot as plt
datingDataMat,datingLabels = file2matrix("datingTestSet2.txt")
#获取figure对象
fig = plt.figure()
#指定图像所在的子视图位置,add_subplot(nmi),意思为在fig视图被划分为n*m个子视图,i指定接下来的图像放在哪一个位置
ax = fig.add_subplot(111)
#画出散点图,坐标分别为datingDataMat的第一列数据与第二列数据,利用15*datingLabels的1、2、3作为不同点的颜色和尺寸
ax.scatter(datingDataMat[:,1], datingDataMat[:,2], 15.0*np.array(datingLabels), 15.0*np.array(datingLabels))
plt.show()
'''
测试
'''
classifyPerson()