Python3代码实现《机器学习实战》k近邻算法改进约会网站配对效果中出现的问题

报错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()
    
    

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章