1、基本概念
K近鄰法(K-nearest neighbors,KNN)既可以分類(lèi),也可以回歸。
KNN做回歸和分類(lèi)的區(qū)別在于最后預(yù)測(cè)時(shí)的決策方式。
KNN做分類(lèi)時(shí),一般用多數(shù)表決法
KNN做回歸時(shí),一般用平均法。
基本概念如下:對(duì)待測(cè)實(shí)例,在訓(xùn)練數(shù)據(jù)集中找到與該實(shí)例最鄰近的K個(gè)實(shí)例(也就是上面所說(shuō)的K個(gè)鄰居), 這K個(gè)實(shí)例的多數(shù)屬于某個(gè)類(lèi),就把該輸入實(shí)例分類(lèi)到這個(gè)類(lèi)中
2. KNN算法三要素
KNN算法主要考慮:k值的選取,距離度量方式,分類(lèi)決策規(guī)則。
1) k值的選取。在應(yīng)用中,k值一般選擇一個(gè)比較小的值,一般選用交叉驗(yàn)證來(lái)取最優(yōu)的k值
當(dāng)K值較小,訓(xùn)練誤差減小,泛化誤差增大,模型復(fù)雜容易過(guò)擬合;
當(dāng)K值較大,泛化誤差減小,訓(xùn)練誤差增大,模型簡(jiǎn)單使預(yù)測(cè)發(fā)生錯(cuò)誤(一個(gè)極端,K等于樣本數(shù)m,則完全沒(méi)有分類(lèi),此時(shí)無(wú)論測(cè)試集是什么,結(jié)果都屬于訓(xùn)練集中最多的類(lèi))
2)距離度量。Lp距離:誤差絕對(duì)值p次方求和再求p次根。歐式距離:p=2的Lp距離。曼哈頓距離:p=1的Lp距離。p為無(wú)窮大時(shí),Lp距離為各個(gè)維度上距離的最大值
3)分類(lèi)決策規(guī)則。也就是如何根據(jù)k個(gè)最近鄰決定待測(cè)對(duì)象的分類(lèi)。k最近鄰的分類(lèi)決策規(guī)則一般選用多數(shù)表決
3. KNN基本執(zhí)行步驟
1)計(jì)算待測(cè)對(duì)象和訓(xùn)練集中每個(gè)樣本點(diǎn)的歐式距離
2)對(duì)上面的所有距離值排序
3)選出k個(gè)最小距離的樣本作為“選民”
4)根據(jù)“選民”預(yù)測(cè)待測(cè)樣本的分類(lèi)或值
4. KNN特點(diǎn)
1)原理簡(jiǎn)單
2)保存模型需要保存所有樣本集
3)訓(xùn)練過(guò)程很快,預(yù)測(cè)速度很慢
· 優(yōu)點(diǎn):
精度高、對(duì)異常值不敏感
可用于數(shù)值型數(shù)據(jù)和離散型數(shù)據(jù)(既可以用來(lái)估值,又可以用來(lái)分類(lèi))
· 缺點(diǎn):
時(shí)間復(fù)雜性高;空間復(fù)雜性高;需要大量的內(nèi)存
樣本不平衡問(wèn)題(即有些類(lèi)別的樣本數(shù)量很多,而其它樣本的數(shù)量很少);
一般數(shù)值很大的時(shí)候不用這個(gè),計(jì)算量太大。但是單個(gè)樣本又不能太少,否則容易發(fā)生誤分。
最大的缺點(diǎn)是無(wú)法給出數(shù)據(jù)的內(nèi)在含義。
需要思考的問(wèn)題:
樣本屬性如何選擇?如何計(jì)算兩個(gè)對(duì)象間距離?當(dāng)樣本各屬性的類(lèi)型和尺度不同時(shí)如何處理?各屬性不同重要程度如何處理?模型的好壞如何評(píng)估?
5.代碼實(shí)現(xiàn)
K近鄰算法的一般流程:準(zhǔn)備數(shù)據(jù)- 分析數(shù)據(jù)- 測(cè)試算法- 使用算法
5.1 sklearn包實(shí)現(xiàn)
關(guān)于sklearn的詳細(xì)介紹,請(qǐng)見(jiàn)之前的博客 //www.jb51.net/article/204984.htm
5.1.1 sklearn實(shí)現(xiàn)k-近鄰算法簡(jiǎn)介 官方文檔
5.1.2 KNeighborsClassifier函數(shù)8個(gè)參數(shù)
- - n_neighbors:k值,選取最近的k個(gè)點(diǎn),默認(rèn)為5;k值不同分類(lèi)結(jié)果也會(huì)不同
- - weights:默認(rèn)是uniform,參數(shù)可以是uniform(均等權(quán)重)、distance(按距離分配權(quán)重),也可以是用戶(hù)自己定義的函數(shù)。uniform是均等的權(quán)重,就說(shuō)所有的鄰近點(diǎn)的權(quán)重都是相等的。
- - algorithm:快速k近鄰搜索算法,默認(rèn)參數(shù)為auto。除此之外,用戶(hù)也可以自己指定搜索算法ball_tree、kd_tree、brute方法進(jìn)行搜索。
- - leaf_size:默認(rèn)是30,這個(gè)是構(gòu)造的kd樹(shù)和ball樹(shù)的大小。這個(gè)值的設(shè)置會(huì)影響樹(shù)構(gòu)建的速度和搜索速度,同樣也影響著存儲(chǔ)樹(shù)所需的內(nèi)存大小。需要根據(jù)問(wèn)題的性質(zhì)選擇最優(yōu)的大小。
- - metric:用于距離度量,默認(rèn)度量是minkowski,也就是p=2的歐氏距離(歐幾里德度量)。
- - p:距離度量公式。歐氏距離和曼哈頓距離。這個(gè)參數(shù)默認(rèn)為2,也可以設(shè)置為1。
- - metric_params:距離公式的其他關(guān)鍵參數(shù),這個(gè)可以不管,使用默認(rèn)的None即可。
- - n_jobs:并行處理設(shè)置。默認(rèn)為1,臨近點(diǎn)搜索并行工作數(shù)。如果為-1,那么CPU的所有cores都用于并行工作。
注意:樣本數(shù)據(jù) - 特征數(shù)據(jù) feature 必須是數(shù)字類(lèi)型,要進(jìn)行運(yùn)算的!
5.1.3 實(shí)例
(1)對(duì)電影進(jìn)行分類(lèi)
import pandas as pd
import numpy as np
from sklearn.neighbors import KNeighborsClassifier
# 讀取數(shù)據(jù)
df = pd.read_excel(../../myfile.excel)
#1、實(shí)例模型對(duì)象
knn = KNeighborsClassifier(n_neighbors=3)
#2、拿到樣本數(shù)據(jù)和分類(lèi)結(jié)果數(shù)據(jù): 截取目標(biāo)列,樣本數(shù)據(jù)要二維
feature = df[['Action Lean','Love Lean']]
target = feature['target']
#3、訓(xùn)練模型
knn.fit(feature,target)
#4、測(cè)試結(jié)果
movie = np.array([13,21])
res = knn.predict(movie) #5、評(píng)分:分?jǐn)?shù)越高悅準(zhǔn)確knn.score(feature,target)
(2)預(yù)測(cè)年收入是否大于50K美元
# 讀取adult.txt文件,最后一列是年收入,并使用KNN算法訓(xùn)練模型,然后使用模型預(yù)測(cè)一個(gè)人的年收入是否大于50
# 1. 讀取數(shù)據(jù)
data = pd.read_csv('../data/adults.txt')
data.head()
# 2. 獲取年齡、教育程度、職位、每周工作時(shí)間作為機(jī)器學(xué)習(xí)數(shù)據(jù) 獲取薪水作為對(duì)應(yīng)結(jié)果
feature = data[['age','education_num','occupation'
,'hours_per_week']]
target = data['salary']
# 3. knn中特征數(shù)據(jù)是需要參與運(yùn)算的,所以要保證特征數(shù)據(jù)必須為數(shù)值型的數(shù)據(jù)
# 數(shù)據(jù)轉(zhuǎn)換,將String類(lèi)型數(shù)據(jù)轉(zhuǎn)換為int
#### map方法,進(jìn)行數(shù)據(jù)轉(zhuǎn)換
dic = {}# unique()方法保證數(shù)據(jù)唯一
occ_arr = feature['occupation'].unique()
# 生成 字符對(duì)應(yīng)數(shù)字的 關(guān)系表
for i in range(occ_arr.size):
dic[occ_arr[i]] = i
# 數(shù)值替換字符串
feature['occupation'] = feature['occupation'].map(dic)
# 4. 切片:訓(xùn)練數(shù)據(jù)和預(yù)測(cè)數(shù)據(jù)
# 查看數(shù)據(jù)的形狀 (訓(xùn)練的數(shù)據(jù)必須是二維數(shù)據(jù))
feature.shape
#訓(xùn)練數(shù)據(jù)
x_train = feature[:32500]
y_train = target[:32500]
#測(cè)試數(shù)據(jù)
x_test = feature[32500:]
y_test = target[32500:]
# 5. 生成算法
from sklearn.neighbors import KNeighborsClassifier
# 實(shí)例化一個(gè) knn對(duì)象,
# 參數(shù):n_neighbors可調(diào),調(diào)到最終預(yù)測(cè)的是最好的結(jié)果.
knn = KNeighborsClassifier(n_neighbors=10)
# fit() 訓(xùn)練函數(shù), (訓(xùn)練數(shù)據(jù),訓(xùn)練數(shù)據(jù)的結(jié)果)
knn.fit(x_train,y_train)
# 對(duì)訓(xùn)練的模型進(jìn)行評(píng)分 (測(cè)試數(shù)據(jù),測(cè)試數(shù)據(jù)的結(jié)果)
knn.score(x_test,y_test)
# 6.預(yù)測(cè)數(shù)據(jù)
print('真實(shí)的分類(lèi)結(jié)果:',np.array(y_test))
print('模型的分類(lèi)結(jié)果:',knn.predict(x_test))
(3)實(shí)例:基于sklearn實(shí)現(xiàn)手寫(xiě)數(shù)字識(shí)別系統(tǒng)
pylot 讀取圖片:img_arr.shape 查看形狀
import pandas as pd
import numpy as np
from sklearn.neighbors import KNeighborsClassifier
# 1、樣本數(shù)據(jù)提?。好繌垐D片對(duì)應(yīng)的numpy數(shù)組:0,1,2,3,4,5,6,7,8,9
feature =[]
target =[]
for i in range(10):#0-9 文件夾名稱(chēng)
for j in range(1,501): #1-500圖片名稱(chēng)
imgpath = './data/'+str(i)+'/'+str(i)+'_'+str(j)+'.bmp' #圖片路徑
img_arr = pld.imread(imgpath)
feature.append(img_arr)
target.append(i)
# 2、把列表轉(zhuǎn)成numpy數(shù)組;feature 必須為二維數(shù)組;
feature = np.array(feature) #這個(gè)feature 里有多個(gè)二維數(shù)組,
target = np.array(target)
feature.shape
(5000,28,28) #里面有5000個(gè)28*28的二維數(shù)組
# 擴(kuò)展:feature是三維數(shù)組;多個(gè)二維數(shù)組組成的數(shù)組是三維數(shù)組,多個(gè)一維數(shù)組組成的數(shù)組是二維數(shù)組!
# 3、feature變形為二維數(shù)組
feature.shape(5000,784)
#4、對(duì)樣本數(shù)據(jù)和目標(biāo)數(shù)據(jù)進(jìn)行同步打亂
np.random.seed(10)
np.random.shuffle(feature)
np.random.seed(10)
np.random.shuffle(target)
# 5、對(duì)樣本數(shù)據(jù)進(jìn)行拆分:訓(xùn)練數(shù)據(jù)和測(cè)試數(shù)據(jù)
x_train = feature[:4950]
y_train = target[:4950]
x_test = feature[4950:]
y_test = target[4950:]
# 6、對(duì)模型進(jìn)行訓(xùn)練:參數(shù):n_neighbors可調(diào),調(diào)到最終預(yù)測(cè)的評(píng)分最好的結(jié)果.
from sklearn.neighbors import KNeighborsClassifier
knn = KNeighborsClassifier(n_neighbors=8)
knn.fit(x_train,y_train) # (訓(xùn)練數(shù)據(jù),訓(xùn)練數(shù)據(jù)的結(jié)果)
# 7、對(duì)訓(xùn)練的模型進(jìn)行評(píng)分 (測(cè)試數(shù)據(jù),測(cè)試數(shù)據(jù)的結(jié)果)
knn.score(x_test,y_test)
# 8、對(duì)模型進(jìn)行測(cè)試
print('真實(shí)的結(jié)果',y_test)
print('模型分類(lèi)的結(jié)果',knn.predict(x_test))
#9、保存訓(xùn)練號(hào)的模型
from sklearn.externals import joblib
joblib.dump(knn,'./knn.m')
#10、讀取訓(xùn)練好的模型
knn = joblib.load('./knn.m')
#-------------------------------------------------------------------------------------------------
# 11、將外部圖片帶入模型進(jìn)行測(cè)試
# 注意:外部圖片的樣本數(shù)據(jù)要轉(zhuǎn)成和訓(xùn)練模型時(shí)候使用的樣本圖片一樣的維度數(shù)組
# ?。?!模型只可以測(cè)試類(lèi)似于測(cè)試數(shù)據(jù)中的特征數(shù)據(jù) ?。?!
img_arr = plt.imgread('./數(shù)字.jpg')
eight_arr = img_arr[170:260,80:70] # 截取圖片的部分
plt.imshow(eight_arr) #查看截取的數(shù)字圖片
# 變形為測(cè)試數(shù)據(jù)中的特征數(shù)據(jù):feature.shape(5000,784) 每一行是一個(gè)一維的784個(gè)元素的數(shù)組;像素要變?yōu)橐粯?
# 12、將eight_arr 對(duì)應(yīng)的圖片降維(三維變?yōu)槎S):將(65,50,3)變?yōu)?28,28)
eight_arr.mean(axis=2 ) # axis=2 表示去除第三個(gè)維度,保留(65,50)保證圖片不能變!
# 13、將圖片像素進(jìn)行等比例壓縮
import scipy.ndimage as ndimage
data_pre_test = ndimage.zoom(eight_arr,zoom=(28/65,28/50))
eight_arr.shape #(28,28)
# 14、將壓縮好的圖片由二維(28,28)變?yōu)橐痪S(1,784)
eight_arr = eight_arr(1,784)
# 15、識(shí)別外部進(jìn)行壓縮和降維的圖片
knn.predict(eight_arr)
array([8])
# -*- coding: UTF-8 -*-
import numpy as np
import operator
from os import listdir
from sklearn.neighbors import KNeighborsClassifier as kNN
"""
函數(shù)說(shuō)明:將32x32的二進(jìn)制圖像轉(zhuǎn)換為1x1024向量。
Parameters:
filename - 文件名
Returns:
returnVect - 返回的二進(jìn)制圖像的1x1024向量
"""
def img2vector(filename):
#創(chuàng)建1x1024零向量
returnVect = np.zeros((1, 1024))
#打開(kāi)文件
fr = open(filename)
#按行讀取
for i in range(32):
#讀一行數(shù)據(jù)
lineStr = fr.readline()
#每一行的前32個(gè)元素依次添加到returnVect中
for j in range(32):
returnVect[0, 32*i+j] = int(lineStr[j])
#返回轉(zhuǎn)換后的1x1024向量
return returnVect
"""
函數(shù)說(shuō)明:手寫(xiě)數(shù)字分類(lèi)測(cè)試
Parameters:
無(wú)
Returns:
無(wú)
"""
def handwritingClassTest():
#測(cè)試集的Labels
hwLabels = []
#返回trainingDigits目錄下的文件名
trainingFileList = listdir('trainingDigits')
#返回文件夾下文件的個(gè)數(shù)
m = len(trainingFileList)
#初始化訓(xùn)練的Mat矩陣,測(cè)試集
trainingMat = np.zeros((m, 1024))
#從文件名中解析出訓(xùn)練集的類(lèi)別
for i in range(m):
#獲得文件的名字
fileNameStr = trainingFileList[i]
#獲得分類(lèi)的數(shù)字
classNumber = int(fileNameStr.split('_')[0])
#將獲得的類(lèi)別添加到hwLabels中
hwLabels.append(classNumber)
#將每一個(gè)文件的1x1024數(shù)據(jù)存儲(chǔ)到trainingMat矩陣中
trainingMat[i,:] = img2vector('trainingDigits/%s' % (fileNameStr))
#構(gòu)建kNN分類(lèi)器
neigh = kNN(n_neighbors = 3, algorithm = 'auto')
#擬合模型, trainingMat為訓(xùn)練矩陣,hwLabels為對(duì)應(yīng)的標(biāo)簽
neigh.fit(trainingMat, hwLabels)
#返回testDigits目錄下的文件列表
testFileList = listdir('testDigits')
#錯(cuò)誤檢測(cè)計(jì)數(shù)
errorCount = 0.0
#測(cè)試數(shù)據(jù)的數(shù)量
mTest = len(testFileList)
#從文件中解析出測(cè)試集的類(lèi)別并進(jìn)行分類(lèi)測(cè)試
for i in range(mTest):
#獲得文件的名字
fileNameStr = testFileList[i]
#獲得分類(lèi)的數(shù)字
classNumber = int(fileNameStr.split('_')[0])
#獲得測(cè)試集的1x1024向量,用于訓(xùn)練
vectorUnderTest = img2vector('testDigits/%s' % (fileNameStr))
#獲得預(yù)測(cè)結(jié)果
# classifierResult = classify0(vectorUnderTest, trainingMat, hwLabels, 3)
classifierResult = neigh.predict(vectorUnderTest)
print("分類(lèi)返回結(jié)果為%d\t真實(shí)結(jié)果為%d" % (classifierResult, classNumber))
if(classifierResult != classNumber):
errorCount += 1.0
print("總共錯(cuò)了%d個(gè)數(shù)據(jù)\n錯(cuò)誤率為%f%%" % (errorCount, errorCount/mTest * 100))
"""
函數(shù)說(shuō)明:main函數(shù)
Parameters:
無(wú)
Returns:
無(wú)
"""
if __name__ == '__main__':
handwritingClassTest()
可以嘗試更改這些參數(shù)的設(shè)置,加深對(duì)其函數(shù)的理解。
以上就是K近鄰法(KNN)相關(guān)知識(shí)總結(jié)以及如何用python實(shí)現(xiàn)的詳細(xì)內(nèi)容,更多關(guān)于python實(shí)現(xiàn)K近鄰法(KNN)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
您可能感興趣的文章:- python實(shí)現(xiàn)KNN近鄰算法
- Python圖像識(shí)別+KNN求解數(shù)獨(dú)的實(shí)現(xiàn)
- 原生python實(shí)現(xiàn)knn分類(lèi)算法
- 使用python實(shí)現(xiàn)kNN分類(lèi)算法
- python可視化實(shí)現(xiàn)KNN算法
- python實(shí)現(xiàn)KNN分類(lèi)算法
- Python實(shí)現(xiàn)KNN(K-近鄰)算法的示例代碼
- 基于python實(shí)現(xiàn)KNN分類(lèi)算法
- Python機(jī)器學(xué)習(xí)之scikit-learn庫(kù)中KNN算法的封裝與使用方法
- 在python中利用KNN實(shí)現(xiàn)對(duì)iris進(jìn)行分類(lèi)的方法
- Python機(jī)器學(xué)習(xí)之KNN近鄰算法