簡(jiǎn)單來(lái)說(shuō),K-近鄰算法采用測(cè)量不同特征值之間的距離方法進(jìn)行分類
優(yōu)點(diǎn):精度高、對(duì)異常值不敏感、無(wú)數(shù)據(jù)輸入假定
缺點(diǎn):計(jì)算復(fù)雜度高、空間復(fù)雜度高
適用數(shù)據(jù)范圍:數(shù)值型和標(biāo)稱2型
工作原理:存在一個(gè)樣本數(shù)據(jù)集合,也稱為訓(xùn)練樣本集,并且樣本集中每個(gè)數(shù)據(jù)都存在標(biāo)簽,即我們知道樣本集中每一個(gè)數(shù)據(jù)與所屬分類的對(duì)應(yīng)關(guān)系(訓(xùn)練集)。輸入沒(méi)有標(biāo)簽的新數(shù)據(jù)之后,將新數(shù)據(jù)的每個(gè)特征與樣本集中數(shù)據(jù)對(duì)應(yīng)的特征進(jìn)行比較,然后算法提取樣本集中特征最相似數(shù)據(jù)(最近鄰)的分類標(biāo)簽(測(cè)試集)。一般來(lái)說(shuō),我們只選擇樣本數(shù)據(jù)集中前k個(gè)最相似的數(shù)據(jù),這就是k-近鄰算法中k的出處。(通常k不大于20)
我們先寫(xiě)入一段代碼
from numpy import * # 導(dǎo)入numpy模塊 import operator # 導(dǎo)入operator模塊 def createDataSet(): # 創(chuàng)建數(shù)據(jù)集函數(shù) # 構(gòu)建一個(gè)數(shù)組存放特征值 group = array( [[1.0, 1.1], [1.0, 1.0], [0, 0], [0, 0.1]] ) # 構(gòu)建一個(gè)數(shù)組存放目標(biāo)值 labels = ['A', 'A', 'B', 'B'] return group, labels
此處稍微介紹一下numpy這個(gè)包吧
NumPy的主要對(duì)象是同種元素的多維數(shù)組。這是一個(gè)所有的元素都是一種類型、通過(guò)一個(gè)正整數(shù)元組索引的元素表格(通常是元素是數(shù)字)。
在NumPy中維度(dimensions)叫做軸(axes),軸的個(gè)數(shù)叫做秩(rank,但是和線性代數(shù)中的秩不是一樣的,在用python求線代中的秩中,我們用numpy包中的linalg.matrix_rank方法計(jì)算矩陣的秩
線性代數(shù)中秩的定義:設(shè)在矩陣A中有一個(gè)不等于0的r階子式D,且所有r+1階子式(如果存在的話)全等于0,那末D稱為矩陣A的最高階非零子式,數(shù)r稱為矩陣A的秩,記作R(A)。
依照KNN算法,我們依次來(lái)
先準(zhǔn)備好四個(gè)需要的數(shù)據(jù)
使用歐式距離:
# 返回矩陣的行數(shù) dataSetSize = dataSet.shape[0] # 列數(shù)不變,行數(shù)變成dataSetSize列 diffMat = tile(inX, (dataSetSize, 1)) - dataSet sqDiffMat = diffMat ** 2 sqDistances = sqDiffMat.sum(axis=1) distances = sqDistances**0.5
第一行
# 返回矩陣的行數(shù) dataSetSize = dataSet.shape[0] # 以第一步的數(shù)據(jù)為例 answer:4 # 4行
第二行
inX = [1. , 0.] # 列數(shù)不變,行數(shù)變成dataSetSize列 diffMat = tile(inX, (dataSetSize, 1)) - dataSet # tile(inX, (dataSetSize, 1)) inX = [ [1. , 0.], [1. , 0.], [1. , 0.], [1. , 0.] ] # inX - dataSet兩個(gè)矩陣相減(行列相等相加相減才有意義) dataSet = [ [1. , 1.1], [1. , 1. ], [0. , 0. ], [0. , 0.1] ] diffMat = [ [0. , -1.1], [0. , -1.], [1. , 0.], [1. , -0.1] ]
第三行
# 求平方差 sqDiffMat = diffMat * 2
第四行
# 計(jì)算矩陣中每一行元素之和 # 此時(shí)會(huì)形成一個(gè)多行1列的矩陣 sqDistances = sqDiffMat.sum(axis=1)
第五行
# 開(kāi)根號(hào) distances = sqDistances**0.5
按照距離遞增次序排序
# 對(duì)數(shù)組進(jìn)行排序 sortedDistIndicies = distances.argsort()
選擇與當(dāng)前點(diǎn)距離最小的k個(gè)點(diǎn)
classCount = {} # 新建一個(gè)字典 # 確定前k個(gè)距離最小元素所在的主要分類 for i in range(k): # voteIlabel的取值是labels中sortedDistIndicies[i]的位置 voteIlabel = labels[sortedDistIndicies[i]] classCount[voteIlabel] = classCount.get(voteIlabel, 0) + 1
確定前k個(gè)點(diǎn)所在類別的出現(xiàn)概率
# 排序 sortedClassCount = sorted(classCount.iteritems(), key=operator.itemgetter(1), reverse=True)
###11# 返回前k個(gè)點(diǎn)出現(xiàn)頻率最高的類別作為當(dāng)前點(diǎn)的預(yù)測(cè)分類
return sortedClassCount[0][0]
剛剛試一試C++的版本…小心,救命
#include iostream> #include vector> #include algorithm> #include cmath> #include map> int sum_vector(std::vectorint> v) { int sum = 0; for (int i = 0; i v.size(); ++i) { sum = v[i] + sum; } return sum; } int knn(int k) { using std::cout; using std::endl; using std::vector; vectorvectorint>> x; vectorint> x_sample = {2, 3, 4}; for (int i = 0; i 4; ++i) { x.push_back(x_sample); } vectorint> y = {1, 1, 1, 1}; int dataSetSize = x.size(); vectorint> x_test = {4, 3, 4}; vectorvectorint>> x_test_matrix; for (int i = 0; i dataSetSize; ++i) { x_test_matrix.push_back(x_test); } vectorint> v_total; for (int i = 0; i dataSetSize; ++i) { for (int j = 0; j x_test_matrix[i].size(); ++j) { x_test_matrix[i][j] = x_test_matrix[i][j] - x[i][j]; x_test_matrix[i][j] = x_test_matrix[i][j] * 2; } int sum_vec = sum_vector(x_test_matrix[i]); v_total.push_back(sqrt(sum_vec)); } sort(v_total.begin(), v_total.end()); std::mapint, int> mp; for (int i = 0; i k; ++i) { int label = y[v_total[i]]; mp[label] += 1; } int max_end_result = 0; for (std::mapint, int>::iterator it = mp.begin(); it != mp.end(); it++) { if (it->first > max_end_result) { max_end_result = it->first; } } return max_end_result; } int main() { int k = 12; int value = knn(k); std::cout "result:\n" std::endl; return 0; }
處理excel和txt數(shù)據(jù)
excel數(shù)據(jù)是矩陣數(shù)據(jù),可直接使用,在此不做處理。
文本txt數(shù)據(jù)需要一些數(shù)據(jù)處理
def file2matrix(filename): fr = open(filename) # 讀取行數(shù)據(jù)直到尾部 arrayOLines = fr.readlines() # 獲取行數(shù) numberOfLines = len(arrayOLines) # 創(chuàng)建返回shape為(numberOfLines, 3)numpy矩陣 returnMat = zeros((numberOfLines, 3)) classLabelVector = [] index = 0 for line in arrayOLines: # 去除首尾的回車符 line = line.strip() # 以tab字符'\t'為符號(hào)進(jìn)行分割字符串 listFromLine = line.split('\t') # 選取前3個(gè)元素,把他們存儲(chǔ)到特征矩陣中 returnMat[index, :] = listFromLine[0: 3] # 把目標(biāo)變量放到目標(biāo)數(shù)組中 classLabelVector.append(int(listFromLine[-1])) index += 1 return returnMat, classLabelVector
數(shù)據(jù)歸一化和標(biāo)準(zhǔn)化
在數(shù)值當(dāng)中,會(huì)有一些數(shù)據(jù)大小參差不齊,嚴(yán)重影響數(shù)據(jù)的真實(shí)性,因此,對(duì)數(shù)據(jù)進(jìn)行歸一化和標(biāo)準(zhǔn)化是使得數(shù)據(jù)取值在一定的區(qū)間,具有更好的擬合度。
例如歸一化就是將數(shù)據(jù)取值范圍處理為0到1或者-1到1之間
# max:最大特征值 # min:最小特征值 newValue = (oldValue - min)/(max-min)
寫(xiě)個(gè)函數(shù)
def autoNorm(dataSet): # min(0)返回該矩陣中每一列的最小值 minVals = dataSet.min(0) # max(0)返回該矩陣中每一列的最大值 maxVals = dataSet.max(0) # 求出極值 ranges = maxVals - minVals # 創(chuàng)建一個(gè)相同行列的0矩陣 normDataSet = zeros(shape(dataSet)) # 得到行數(shù) m = dataSet.shape[0] # 得到一個(gè)原矩陣減去m倍行1倍列的minVals normDataSet = dataSet - tile(minVlas, (m,1)) # 特征值相除 normDataSet = normDataSet/tile(ranges, (m, 1)) return normDataSet, ranges, minVals
歸一化的缺點(diǎn):如果異常值就是最大值或者最小值,那么歸一化也就沒(méi)有了保證(穩(wěn)定性較差,只適合傳統(tǒng)精確小數(shù)據(jù)場(chǎng)景)
標(biāo)準(zhǔn)化可查
既然已經(jīng)了解其內(nèi)置的算法了,那么便調(diào)庫(kù)來(lái)寫(xiě)一個(gè)吧
from sklearn.datasets import load_iris # 導(dǎo)入內(nèi)置數(shù)據(jù)集 from sklearn.model_selection import train_test_split # 提供數(shù)據(jù)集分類方法 from sklearn.preprocessing import StandardScaler # 標(biāo)準(zhǔn)化 from sklearn.neighbors import KNeighborsClassifier # KNN def knn_iris(): # 獲得鳶尾花數(shù)據(jù)集 iris = load_iris() # 獲取數(shù)據(jù)集 # random_state為隨機(jī)數(shù)種子,一個(gè)數(shù)據(jù)集中相等的行不能大于6 x_train, x_test, y_train, y_test = train_test_split(iris.data, iris.target, random_state=6) # 特征工程:標(biāo)準(zhǔn)化 transfer = StandardScaler() # 訓(xùn)練集標(biāo)準(zhǔn)化 x_train = transfer.fit_transform(x_train) # 測(cè)試集標(biāo)準(zhǔn)化 x_test = transfer.transform(x_test) # 設(shè)置近鄰個(gè)數(shù) estimator = KNeighborsClassifier(n_neighbors=3) # 訓(xùn)練集測(cè)試形成模型 estimator.fit(x_train, y_train) # 模型預(yù)估 # 根據(jù)預(yù)測(cè)特征值得出預(yù)測(cè)目標(biāo)值 y_predict = estimator.predict(x_test) print("y_predict: \n", y_predict) # 得出預(yù)測(cè)目標(biāo)值和真實(shí)目標(biāo)值之間是否相等 print("直接比對(duì)真實(shí)值和預(yù)測(cè)值:\n", y_test == y_predict) # 計(jì)算準(zhǔn)確率 score = estimator.score(x_test, y_test) print("準(zhǔn)確率為:\n", score) def main(): knn_iris() if __name__ == '__main__': main()
到此這篇關(guān)于Python機(jī)器學(xué)習(xí)之KNN近鄰算法的文章就介紹到這了,更多相關(guān)Python近鄰算法內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
標(biāo)簽:益陽(yáng) 鷹潭 黔西 上海 常德 惠州 黑龍江 四川
巨人網(wǎng)絡(luò)通訊聲明:本文標(biāo)題《Python機(jī)器學(xué)習(xí)之KNN近鄰算法》,本文關(guān)鍵詞 Python,機(jī)器,學(xué),習(xí)之,KNN,近鄰,;如發(fā)現(xiàn)本文內(nèi)容存在版權(quán)問(wèn)題,煩請(qǐng)?zhí)峁┫嚓P(guān)信息告之我們,我們將及時(shí)溝通與處理。本站內(nèi)容系統(tǒng)采集于網(wǎng)絡(luò),涉及言論、版權(quán)與本站無(wú)關(guān)。