機器學習作業KNN(下)——字元分類
阿新 • • 發佈:2018-12-20
-
作業背景: 今天機器學習實驗課,老師給了個很小的資料集,是劃分英文字母B和M,讓我們用KNN做,看看分類效果嗎,正好我上個實驗也用的KNN,所以把上次的程式稍微修改一下即可(偷懶狂魔)。
-
資料預處理: 大致看了下資料集,是這個樣子的: 2.1 特徵選取: 所以,老規矩,先看看哪些特徵是沒有用的,很明顯id對分類不產生影響,將其剔除。剩下的特徵都有用,將其留下。 2.2 歸一化的問題:發現有些特徵都是過百的,而有些特徵在0~1之間徘徊,很明顯,過大的資料產生的影響會蓋過小值對分類的效用,所以要進行資料集的歸一化。 2.3 選取訓練集,資料集: 首先先打亂資料集,選取亂序後的資料集的前10行作為測試集,剩下的作為訓練集,訓練模型
-
資料視覺化: 由於是不是二維的,所以沒直接在座標上視覺化,所以我選區了幾個特徵進行了視覺化,如下圖所示: 資料質量還是客觀的,可以用於訓練,下面是程式碼塊>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
-
程式碼塊(程式碼改的的有點醜,不要介意)
import numpy as np
import matplotlib.pyplot as plt
import operator
import pandas as pd
#################讀取檔案(資料預處理)#########################
def filematrix(filename):
array0Lines = np.matrix(pd.read_csv(filename)) ##讀取檔案,選取前20行資料作為訓練集,最後三行資料作為測試集。
returnMat = array0Lines[:, 2:33] ##訓練集
number0Lines = array0Lines.shape[0] ##讀取檔案行數
classLabelVector = [] ##訓練集分類標籤向量
for line in array0Lines: #遍歷資料集,獲取分類標籤資訊
if line[:,1]=='B':
classLabelVector.append('B')
elif line[:,1]=='M':
classLabelVector.append('M')
return returnMat,np.matrix(classLabelVector).T ##返回訓練集和標籤向量
def showdatas(datingDataMat,datingLabels):
"""
函式說明:視覺化資料
Parameters:
datingDataMat - 特徵矩陣
datingLabels - 分類Label
Returns:
無
"""
#不同型別資料的顏色
LabelsColors = [] ##存放資料顏色的陣列
for i in datingLabels:
if i == 'B':
LabelsColors.append('blue')
elif i == 'M':
LabelsColors.append('red')
fig,axs = plt.subplots(nrows=2,ncols=2,figsize=(10,6))
#畫圖時要注意把matrix格式換成list格式,否則不能畫圖
###由於特徵有點多,所以畫圖時,我只選擇了其中幾個特徵看看分佈
axs[0][0].scatter(datingDataMat[:,2].tolist(),datingDataMat[:,3].tolist(),color=LabelsColors,s=15,alpha=.5)
axs[0][1].scatter(datingDataMat[:,4].tolist(), datingDataMat[:, 5].tolist(), color=LabelsColors, s=15, alpha=.5)
axs[1][0].scatter(datingDataMat[:, 6].tolist(), datingDataMat[:, 7].tolist(), color=LabelsColors, s=15, alpha=.5)
axs[1][1].scatter(datingDataMat[:, 8].tolist(), datingDataMat[:, 9].tolist(), color=LabelsColors, s=15, alpha=.5)
"""
###設定圖列legend
'0' = mlines.Line2D([], [], color='black', marker='.',markersize=6, label='0')
'1' = mlines.Line2D([], [], color='orange', marker='.',markersize=6, label='1')
'2' = mlines.Line2D([], [], color='red', marker='.',markersize=6, label='2')
plt.legend(handles=[0,1,2])
"""
plt.show()
def autoNorm(dataSet):
"""
函式說明:對資料進行歸一化
Parameters:
dataSet - 特徵矩陣
Returns:
normDataSet - 歸一化後的特徵矩陣
ranges - 資料範圍
minVals - 資料最小值
"""
#meanVals = dataSet.mean(0) #資料平均值
#stdVals = dataSet.std(0)
minVals = dataSet.min(0) #資料最小值
maxVals = dataSet.max(0) #資料最大值
ranges = maxVals - minVals #最大值和最小值的差距
normDataSet = np.zeros(np.shape(dataSet)) #用於存放歸一化後的資料集
m= dataSet.shape[0] #返回資料集的行數
###歸一化過程
#normDataSet = dataSet-meanVals
#normDataSet = normDataSet/stdVals
normDataSet = dataSet - np.tile(minVals,(m,1)) #原始資料減去最小資料
normDataSet = normDataSet/np.tile(ranges,(m,1)) #所得之差除以最大值最小值得差,得到歸一化資料
return normDataSet,ranges,minVals #返回歸一化資料結果,資料範圍,最小值
def classify(inX,dataSet,labels,k):
dataSetSize = dataSet.shape[0] #返回dataSet的行數
diffMat = np.tile(inX,(dataSetSize,1)) - dataSet #測試矩陣-資料集
sqDiffMat = np.multiply(diffMat,diffMat)
sqDistances = sqDiffMat.sum(axis=1).tolist() #沿著列的方向相加
#sqDistances = sqDistances.tolist() #這一步是為了把matrix格式,轉化成ndarray格式,否則下一行的操作會報錯
distances = np.sqrt(np.ravel(sqDistances)) #先展開成一維,再開平方歐式距離
sortedDisIndices = distances.argsort() #返回distances中元素從小到大排序後的索引值
classCount = {} #空字典,用來記錄類別次數
for i in range(k): #遍歷
voteIlabel = labels[sortedDisIndices[i]] #取出最近的K個點
classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1 #存放出現的類別次數
#根據字典的值進行降序排序
sortedClassCount = sorted(classCount.items(),key=operator.itemgetter(1),reverse=True)
return sortedClassCount[0][0] #返回次數最多的類別
def datingClassTest():
filename = "G:/shiyan2/Ex2.1_KNN.csv"
datingDataMat, datingLabels = filematrix(filename)
normMat, ranges, minVals = autoNorm(datingDataMat)
###打亂資料集,並取前20個作為訓練集
index = np.arange(50)
np.random.shuffle(index)
dataSet = normMat[index]
test = normMat[0:11, :] # 測試集
numTestVecs = len(test) #測試集個數
m = np.shape(normMat)[0] #獲得normMat的行數
errorCount = 0.0 #分類錯誤計數
for i in range (numTestVecs-1):
classifierResult = classify(test[i,:],normMat[numTestVecs:m,:],np.ravel(datingLabels)[numTestVecs:m],5) ##前numTestVecs 作為測試集,後m-numTestVecs作為訓練集,這邊注意要是list格式,否則不能迭代的
print("分類結果:%s\t真實類別:%s"%(classifierResult,datingLabels[i]))
if classifierResult!=datingLabels[i]:
errorCount+=1.0
print("錯誤率:%f%%"%(errorCount/float(numTestVecs)*100))
showdatas(datingDataMat,datingLabels)
if __name__ =='__main__':
datingClassTest()
分類結果:B 真實類別:[['B']]
分類結果:B 真實類別:[['B']]
分類結果:B 真實類別:[['B']]
分類結果:B 真實類別:[['B']]
分類結果:B 真實類別:[['B']]
分類結果:B 真實類別:[['B']]
分類結果:M 真實類別:[['B']]
分類結果:M 真實類別:[['M']]
分類結果:B 真實類別:[['B']]
分類結果:B 真實類別:[['B']]
錯誤率:9.090909%
<Figure size 1000x600 with 4 Axes>