本次讀書筆記在于延續上一篇部落格的工程,做出微小的改動,即使用Matplotlib建立散點圖(散點圖使用DataMat矩陣的第一、第二列資料)。
首先還是介紹一個相關知識點,友善代碼浏覽。
知識點一:
1、在使用Matplotlib生成圖表時,預設不支援漢字,所有漢字都會顯示成框框。
解決方法:代碼中指定中文字型
# -*- coding:utf-8 -*-
importmatplotlib.pyplot as plt
import matplotlib
zhfont1 =matplotlib.font_manager.FontProperties(fname='C:/Windows/Fonts/simsun.ttc')
plt.xlabel(u"橫坐标xlabel",fontproperties=zhfont1)
到C:\Windows\Fonts\中找到新宋體對應的字型檔案simsun.ttf(Window 8和Windows10系統是simsun.ttc,也可以使用其他字型)
下面貼出代碼:
from numpy import *
import knn1
def file2matrix(filename):
"""該函數将約會檔案内容轉換成資料處理格式,傳回一個測試特征集(格式二維數組),和測試集類别集(格式清單)
"""
fr = open(filename)
arrayOnLines = fr.readlines()
numberOfLines = len(arrayOnLines) #擷取 n=樣本的行數
returnMat = zeros((numberOfLines, 3)) #建立一個2維矩陣用于存放訓練樣本資料,一共有n行,每一行存放3個資料
classLabel = [] #建立一個1維數組用于存放訓練樣本标簽。
for i in range(numberOfLines):
line = arrayOnLines[i]
line = line.strip() # 把回車符号給去掉
listFromLine = line.split('\t') # 把每一行資料用\t分割
returnMat[i, :] = listFromLine[0:3] # 把分割好的資料放至資料集,其中i是該樣本資料的下标,就是放到第幾行
classLabel.append(int(listFromLine[-1])) # 把該樣本對應的标簽放至标簽集,順序與樣本集對應。
return returnMat, classLabel
def autoNorm(dataSet):
"""
該函數将資料集的是以特征歸一化,傳回歸一化後的特征集(格式為數組),特征集最小值(格式為一維數組),特征集範圍(格式為一維數組)
"""
# 擷取資料集中每一列的最小數值
# 以createDataSet()中的資料為例,group.min(0)=[0,0]
minVals = dataSet.min(axis=0)
# 擷取資料集中每一列的最大數值
# group.max(0)=[1, 1.1]
maxVals = dataSet.max(axis=0)
# 最大值與最小的內插補點
ranges = maxVals - minVals
# 建立一個與dataSet同shape的全0矩陣,用于存放歸一化後的資料
normDataSet = zeros(shape(dataSet))
dataSize = dataSet.shape[0]
# 把最小值擴充為與dataSet同shape,然後作差,具體tile請翻看 第三節 代碼中的tile
normDataSet = dataSet - tile(minVals, (dataSize, 1))
# 把最大最小內插補點擴充為dataSet同shape,然後作商,是指對應元素進行除法運算,而不是矩陣除法。
# 矩陣除法在numpy中要用linalg.solve(A,B)
normDataSet = normDataSet / tile(ranges, (dataSize, 1))
return normDataSet, minVals, ranges
def dateClassTest(filename, k):
"""
測試KNN算法對于約會資料的錯誤率
"""
# 将資料集中10%的資料留作測試用,其餘的90%用于訓練
ratio = 0.10
dataSet, labels = file2matrix(filename)
normDateSet, minVals, ranges = autoNorm(dataSet)
dataSize = dataSet.shape[0]
numTestVecs = int(dataSize * ratio)
errorcount = 0.0
print("m : %d" % dataSize)
for i in range(numTestVecs):
#分别對應前面的 classify(int X, dataSet, labels, k)
#normDateSet[i, :]對應資料中随機的1000*0.1=100行的資料,normDateSet[numTestVecs:dataSize, :]對應剩下的900行資料
classifyResult = knn1.classify0(normDateSet[i, :], normDateSet[numTestVecs:dataSize, :], \
labels[numTestVecs:dataSize], k)
if classifyResult != labels[i]:
errorcount += 1
print("the real answer is: %d, the classify answer is: %d" % (labels[i], classifyResult))
print("the total error ratio is %f" % (errorcount / float(numTestVecs)))
if __name__ == '__main__':
filename = '/Users/Administrator/Desktop/machine learning inaction/Ch02/datingTestSet2.txt'
dateClassTest(filename, 3)
datingDataMat, datingLabels = file2matrix(filename)
import matplotlib
import matplotlib.pyplot as plt
from matplotlib.font_manager import FontProperties
zhfont = FontProperties(fname='C:/Windows/Fonts/simsun.ttc', size=12)
# 建立畫闆
fig = plt.figure()
# 畫圖之前首先設定figure對象,此函數相當于設定一塊自定義大小的畫布,使得後面的圖形輸出在這塊規定了大小的畫布上,
# 其中參數figsize設定畫布大小
plt.figure(figsize=(8, 5), dpi=80)
# 例子:plt.subplot(221)将figure設定的畫布大小分成幾個部分,參數‘221’表示2(row)x2(colu),即将畫布分成2x2,兩行兩列的4塊區域,
# 1表示選擇圖形輸出的區域在第一塊,圖形輸出區域參數必須在“行x列”範圍,此處必須在1和2之間選擇
# 如果參數設定為subplot(111),則表示畫布整個輸出,不分割成小塊區域,圖形直接輸出在整塊畫布上
ax = plt.subplot(111)
datingLabels = array(datingLabels)
idx_1 = where(datingLabels == 1)
p1 = ax.scatter(datingDataMat[idx_1, 0], datingDataMat[idx_1, 1], marker='*', color='r', label='1', s=10)
idx_2 = where(datingLabels == 2)
p2 = ax.scatter(datingDataMat[idx_2, 0], datingDataMat[idx_2, 1], marker='o', color='g', label='2', s=20)
idx_3 = where(datingLabels == 3)
p3 = ax.scatter(datingDataMat[idx_3, 0], datingDataMat[idx_3, 1], marker='+', color='b', label='3', s=30)
plt.xlabel(u'每年擷取的飛行裡程數', fontproperties=zhfont)
plt.ylabel(u'玩視訊遊戲所消耗的事件百分比', fontproperties=zhfont)
#loc(設定圖例顯示的位置),'upper left' : 2
ax.legend((p1, p2, p3), (u'不喜歡', u'魅力一般', u'極具魅力'), loc=2, prop=zhfont)
plt.show() #顯示
然後貼出結果圖: