01-kNN演算法實戰-(機器學習實戰)
最近在看機器學習實戰這本書。剛開始看kNN演算法,並寫了些程式,分享下一些感悟和細節。
什麼是kNN
kNN中文又稱為k-近鄰演算法,其基本思想是通過計算輸入樣本點 和 訓練集樣本點之前的這兩個向量之前的距離,距離越近的話,說明其特徵越靠近,通過取出其k個距離最近的樣本點,然後計算這k個樣本點中類別佔比最大的類比以此來預測輸入樣本點(被測樣本點)的類別。
kNN的優勢
- kNN是ML裡最簡單,最基本的演算法。
- kNN不會受到差別特別大的樣本中的特徵元素的影響(對異常值不敏感)。因為採用了歸一化技術
- kNN的精度高
kNN的劣勢
- kNN演算法時間複雜度較高,需要計算被測樣本點和訓練集中所有樣本點的距離
kNN演算法的實現
from numpy import *
import operator
# 該分類器模型,只需要輸入向量, 訓練資料集矩陣dataSet,每一行是一個樣本。labels(每一行的樣本標籤)。k取前幾個
def classify0(inX, dataSet, labels, k):
dataSetSize = dataSet.shape[0]
diffMat = tile(inX, (dataSetSize,1)) - dataSet
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]]
classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1
sortedClassCount = sorted(classCount.iteritems(), key=operator.itemgetter(1), reverse=True)
return sortedClassCount[0][0]
- 這裡的dataSet是numpy模組裡的陣列(也可以看成矩陣),不是python中內建的陣列,shape屬性會返回這個陣列的緯度.(比如是2 * 3的二維陣列,則會返回(2, 3)表示這是一個2緯陣列,每個緯度的大小分別是2,3)
- tile函式用來建立矩陣,其中(dataSetSize, 1)表示沿著inX向量的行方向(inX是一個行向量),賦值dataSetSize次,沿著列方向複製1次(既列不變)。
- diffMat矩陣計算出了各個向量之前的距離的平方值。其中2表示平方,0.5表示開平方
使用kNN來改進婚戀網站的匹配
這裡的資料集如下
datingTestSet.txt存放了該網站關於個人資訊的集合。每一行代表一個人,一共有三個特徵屬性,和一個標籤屬性用來標識是哪一類人。
datingTestSet2.txt 存放的是處理過的datingTestSet資料,將類別標籤處理成數字
- 三個特徵屬性分別是: 每年航班的行程公里數,玩遊戲的時間所佔的時間百分比,每週消費的冰淇淋公升數
- 人一共分為三類(不喜歡的、魅力一般、極具魅力)
兩個檔案的內容如下
目的
現在的需求是,我們必須根據提供的資料,來準確的劃分出這三類人。才能精確的從資料中挑選出的人是使用者感興趣的。
分析
- 根據之前總結的kNN分類器模型,我們需要將資料進行處理。分別分離出訓練資料集、測試資料集、資料集對應的標籤。其實最重要的是準本和分析資料集,然後進行建模,但是由於這裡資料集已經是現有的,直接用就行。
- 接著我們編寫測試程式,將測試資料集、訓練資料集、標籤丟入改模型進行計算
- 統計識別的錯誤率,如果錯誤率很低。那基本上可以使用。如果錯誤率高,那就要改進資料集,進行其他特徵點的抽取。
步驟
處理資料(提取資料,歸一化)
改函式用來讀取訓練集資料將其轉化為矩陣,並提取出標籤集合。具體程式碼看下面
from numpy import *
def file2matrix(filename):
file = open(filename)
arrayOfLines = file.readlines()
numberOfLines = len(arrayOfLines)
returnMat = zeros((numberOfLines,3))
classLabelVector = []
index = 0
for line in arrayOfLines:
line = line.strip()
listFromLine = line.split('\t')
returnMat[index,:] = listFromLine[0:3]
classLabelVector.append(int(listFromLine[-1])) # 這邊要十分小心,必須強制轉換為整形,不然編譯器會當做字串處理
index += 1
return returnMat, classLabelVector
將特徵資料都歸一化
因為航程特徵的數字太大,對其他兩個影響太大,但是又不能忽略,為了減少這種影響。將資料進行歸一行,既處理層0到1之前的小數。利用瞭如下原理
newValue = oldValue - minValue/(maxValue - minValue)
# 資料歸一化 newValue = oldValue - minValue/(maxValue - minValue)
def autoNorm(dataSet):
minVals = dataSet.min(0)
maxVals = dataSet.max(0)
ranges = maxVals - minVals
normaMat = zeros(shape(dataSet))
m = dataSet.shape[0]
normaMat = dataSet - tile(minVals, (m, 1))
normaMat = normaMat / tile(ranges, (m, 1))
return normaMat, ranges, minVals
通過圖形分析資料
- (x軸為遊戲時間佔比,y軸為每週吃冰淇淋的公斤數)
# 列2和列1的比較
datingDataMat,datingDataLabels = file2matrix('/Users/sixleaves/Dropbox/DeepLearning/machinelearninginaction/Ch02/datingTestSet2.txt')
print datingDataLabels
import matplotlib
import matplotlib.pyplot as plt
from numpy import *
fig = plt.figure()
ax = fig.add_subplot(111)
ax.scatter(datingDataMat[:, 1], datingDataMat[:, 2], 15.0 * array(datingDataLabels), 15.0 * array(datingDataLabels))
plt.show()
- (x軸為航班佔比,y軸為遊戲時間耗時佔比)
# 列2和列1的比較
datingDataMat,datingDataLabels = file2matrix('/Users/sixleaves/Dropbox/DeepLearning/machinelearninginaction/Ch02/datingTestSet2.txt')
print datingDataLabels
import matplotlib
import matplotlib.pyplot as plt
from numpy import *
fig = plt.figure()
ax = fig.add_subplot(111)
ax.scatter(datingDataMat[:, 0], datingDataMat[:, 1], 15.0 * array(datingDataLabels), 15.0 * array(datingDataLabels))
plt.show()
通過上面的分析,可以很明顯的發現,使用前兩個特徵,我們就可以將這三類人比較精確的分離出來。但如果只使用第二個和第三個特徵難以分離出該三類。
編寫測試用例,測試kNN分類器的效果
# 針對約會網站的測試程式碼,測試分類器的效果
def datingClassTest():
hoRatio = 0.10
datingDataMat, datingDataLabels = file2matrix('/Users/sixleaves/Dropbox/DeepLearning/machinelearninginaction/Ch02/datingTestSet2.txt')
normMat, ranges, minVals = autoNorm(datingDataMat)
m = normMat.shape[0] # 獲取訓練集行數
numTestVecs = int(m * hoRatio) # 取10%的行數作為測試集
errorCount = 0.0
for i in range(numTestVecs):
classifierResult = classify0(normMat[i,:], normMat[numTestVecs:m,], datingDataLabels[numTestVecs:m], 3) # 取從小到的前三個
print "分類的結果是: %d, 目標結果是: %d" % (int(classifierResult), int(datingDataLabels[i]))
if (classifierResult != datingDataLabels[i]): errorCount += 1.0
print "總的錯誤率為: %f%%" %(errorCount / float(numTestVecs) * 100.0)
執行datingClassTest()方法我們可以看到如下結果(其中1,2,3分別代表三類人的標籤對映。),改分類器的錯誤率為5%,也就是說95%的情況下匹配都是準確的,算是還不錯的分類器。
使用KNN實現識別手寫數字
具體思路和上面的例子一樣。這邊有個比較不一樣的步驟是我們需要對圖片進行處理,這裡我們統一對圖片做了以下處理。
- 將圖片的大小處理層一樣的黑白圖。
-
對於每張圖片,我們使用 正確的對應數字_樣本索引.txt來命名。(之所以處理成文字是為了在這裡比較直觀)
分析
1.為了使用kNN模型,我們需要將圖片轉化為一個行向量。由於圖片大小事32*32,我們需要一個1024大小的行向量即可儲存。
from numpy import *
def img2vector(filename):
fr = open(filename)
returnVect = zeros((1, 1024))
for i in range(32):
lineStr = fr.readline()
for j in range(32):
returnVec[0, 32 * i + j] = int(lineStr[j])
return returnVect
2.使用kNN模型進行測試
from os import listdir
from numpy import *
def handwritingClassTest():
# 遍歷訓練資料集,將資料集裝載進矩陣。
trainingFilesPath = "/Users/sixleaves/Dropbox/DeepLearning/machinelearninginaction/Ch02/digits/trainingDigits/"
arrayOfTrainingFiles = listdir(trainingFilesPath)
m = len(arrayOfTrainingFiles)
trainingMat = zeros((m, 1024))
classLabels = []
for i in range(m):
fileNameStr = arrayOfTrainingFiles[i]
fileStr = fileNameStr.split('.')[0]
classNum = int(fileStr.split('_')[0])
classLabels.append(classNum)
trainingMat[i,:] = img2vector(trainingFilesPath + fileNameStr)
testFilePath = "/Users/sixleaves/Dropbox/DeepLearning/machinelearninginaction/Ch02/digits/testDigits/"
arrayOfTestFiles = listdir(testFilePath)
mTest = len(arrayOfTestFiles)
errorCount = 0.0;
for j in range(mTest):
testFileNameStr = arrayOfTestFiles[j]
testFile = testFileNameStr.split('.')[0]
testNum = testFile.split('_')[0]
testImageVec = img2vector(testFilePath + testFileNameStr)
classifierResult = classify0(testImageVec, trainingMat, classLabels, 3)
print "識別結果為: %d, 正確結果為: %d" % (int(classifierResult), int(testNum))
if classifierResult != int(testNum): errorCount += 1.0
print "識別錯誤個數為: %d" % (int(errorCount))
print "識別錯誤率為: %f%%" % (errorCount / float(mTest) * 100.0)
效果還是相當不錯,基本達到了99%識別效率
總結:
- 一般機器學習解決問題需要以下步驟(準備資料,分析資料,訓練演算法(kNN不適用,kNN無需訓練),測試演算法,使用演算法)。
- 對於kNN演算法模型來說,分析資料過程由於重要,只有有價值的資料使用kNN才能有精確的結果。
- kNN演算法比較簡單,穩定。但是效率低。其思想主要是計算相似度(通過計算向量距離),並使用概率來得出分類結果。
by sixleaves 20170726 FuZhou
相關文章
- 機器學習實戰6(SMO演算法)機器學習演算法
- 機器學習實戰ByMatlab(2):PCA演算法機器學習MatlabPCA演算法
- 機器學習實戰ByMatlab(1):KNN演算法機器學習MatlabKNN演算法
- k近鄰演算法python實現 -- 《機器學習實戰》演算法Python機器學習
- 機器學習實戰筆記-k近鄰演算法機器學習筆記演算法
- python機器學習實戰(二)Python機器學習
- 機器學習實戰之開篇機器學習
- Spark機器學習實戰 (十一) - 文字情感分類專案實戰Spark機器學習
- 《機器學習實戰》kMeans演算法(K均值聚類演算法)機器學習演算法聚類
- 機器學習30天進階實戰機器學習
- 機器學習入門實戰疑問機器學習
- 《機器學習實戰》學習大綱機器學習
- 寫在《機器學習實戰》上市之前機器學習
- 機器學習實戰ByMatlab(3):K-means演算法機器學習Matlab演算法
- 樸素貝葉斯演算法的python實現 -- 機器學習實戰演算法Python機器學習
- 決策樹ID3演算法python實現 -- 《機器學習實戰》演算法Python機器學習
- Python機器學習實踐與Kaggle實戰Python機器學習
- 《機器學習實戰》決策樹(ID3演算法)的分析與實現機器學習演算法
- 機器學習實戰----k值近鄰演算法(Python語言)機器學習演算法Python
- 9.1.6 DBSCAN聚類演算法————機器學習實戰第二版聚類演算法機器學習
- 機器學習實戰(一)—— 線性迴歸機器學習
- 基於Sklearn機器學習程式碼實戰機器學習
- 《scikit-learn機器學習實戰》簡介機器學習
- 機器學習實戰 | SKLearn最全應用指南機器學習
- 機器學習實戰之Logistic迴歸機器學習
- 《機器學習實戰》中的splitDataSet函式機器學習函式
- 《機器學習實戰》第一章 機器學習基礎機器學習
- 機器學習實戰-SVM模型實現人臉識別機器學習模型
- 《機器學習實戰》k最近鄰演算法(K-Nearest Neighbor,Python實現)機器學習演算法RESTPython
- 回顧·機器學習/深度學習工程實戰機器學習深度學習
- 初學者的機器學習入門實戰教程!機器學習
- 機器學習PAI快速入門與業務實戰機器學習AI
- 機器學習實戰(三)--樸素貝葉斯機器學習
- 機器學習實戰ByMatlab(5):Logistic Regression機器學習Matlab
- 觀遠AI實戰 | 機器學習系統的工程實踐AI機器學習
- 機器學習實戰ByMatlab(4):二分K-means演算法機器學習Matlab演算法
- Swift 演算法實戰之路(一)Swift演算法
- Swift 演算法實戰之路(二)Swift演算法