報錯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()