《機器學習實戰》——KNN演算法實戰篇
阿新 • • 發佈:2019-02-12
#-*-coding:utf-8-*- from numpy import * import operator from os import listdir """ KNN演算法的原理: 存在一個樣本資料集合,也稱作訓練樣本集,並且樣本集中每個資料都存在標籤,即我們知道樣本集中每一資料 與所屬分類的對應關係。輸人沒有標籤的新資料後,將新資料的每個特徵與樣本集中資料對應的特徵進行比較, 然後演算法提取樣本集中特徵最相似資料(最近鄰)的分類標籤。一般來說,我們只選擇樣本資料集中前k個最 相似的資料,這就是 k 近鄰演算法中k的出處 , 通常k是不大於 20 的整數。最後,選擇 k個最相似資料中 出現次數最多的分類,作為新資料的分類。 構造資料集 -> 歸一化特徵值 -> 分類 -> 測試錯誤率(調整k值) -> 投入使用 """ #構造資料集 def createDataSet(): group = array([[1.0,1.1],[1.0,1.0],[0,0],[0,0.1]]) labels = ['A','A','B','B'] return group,labels #-------------------------------------------使用k近鄰演算法改進約會網站的配對效果----------------------------------------------- """ ------calssify0()------ ------inX: 用於分類的輸入向量 ------dataSet: 輸入的訓練樣本集 ------labels: 標籤向量(標籤向量的元素數目==dataSet的行數) ------k: 用於選擇最近鄰居的數目 """ #用KNN進行預測 def classify0(inX,dataSet,labels,k): # array.shape返回一個元組(行數,列數),shape[0]表示的是行數 dataSetSize = dataSet.shape[0] #計算距離,使用的是歐氏距離公式 """ ----------------tile()-------------------- 函式格式tile(A,reps) A和reps都是array_like A的型別眾多,幾乎所有型別都可以:array, list, tuple, dict, matrix以及基本資料型別int, string, float以及bool型別。 reps的型別也很多,可以是tuple,list, dict, array, int, bool.但不可以是float, string, matrix型別。 例如: >>> b=[1,3,5] >>> tile(b,[2,3]) array([[1, 3, 5, 1, 3, 5, 1, 3, 5], [1, 3, 5, 1, 3, 5, 1, 3, 5]]) """ diffMat = tile(inX,(dataSetSize,1)) - dataSet sqDiffMat = diffMat ** 2 """ ----------------mat.sum()-------------------- a1=mat([[1,1],[2,3],[4,2]]); a2=a1.sum(axis=0);//列和,這裡得到的是1*2的矩陣 a3=a1.sum(axis=1);//行和,這裡得到的是3*1的矩陣 a4=sum(a1[1,:]);//計算第一行所有列的和,這裡得到的是一個數值 """ sqDistances = sqDiffMat.sum(axis = 1) #行和,這裡得到的是4*1的矩陣 distances = sqDistances ** 0.5 #選擇距離最小的k個點 """ ----------------array.argsort()-------------------- argsort函式返回的是陣列值從小到大的索引值 >>> x = np.array([3, 1, 2]) >>> np.argsort(x) array([1, 2, 0]) """ sorteDistIndicies = distances.argsort() #定義一個字典 classCount = {} for i in range(k): voteIlabel = labels[sorteDistIndicies[i]] """ ----------------dict.get()-------------------- Python 字典 get() 方法和 setdefault() 方法類似,返回指定鍵的值,如果鍵不在字典中,返回一個指定值,預設為None。 key -- 字典中要查詢的鍵。 default -- 可選引數,如果指定鍵的值不存在時,返回該值,預設為 None。 """ classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1 #排序 """ ----------------sorted()-------------------- sorted(iterable[, cmp[, key[, reverse]]]) sorted() 函式對所有可迭代的物件進行排序操作。 sort 與 sorted 區別: sort 是應用在 list 上的方法,sorted 可以對所有可迭代的物件進行排序操作。 list 的 sort 方法返回的是對已經存在的列表進行操作,而內建函式 sorted 方法返回的是一個 新的 list,而不是在原來的基礎上進行的操作。 # sorted()可以利用引數reverse=True進行反向排序 >>>list=[3,4,2,6,1] >>>sorted(list) [1, 2, 3, 4, 6] >>>sorted(list, reverse=True) [6, 4, 3, 2, 1] """ """ ----------------dict.items()-------------------- 字典(Dictionary) items() 函式以列表返回可遍歷的(鍵, 值) 元組陣列。 返回可遍歷的(鍵, 值) 元組陣列。 """ """ ----------------operator.itemgetter()-------------------- operator模組提供的itemgetter函式用於獲取物件的哪些維的資料,引數為一些序號(即需要獲取的資料在物件中的序號),下面看例子。 a = [1,2,3] >>> b=operator.itemgetter(1) //定義函式b,獲取物件的第1個域的值 >>> b(a) 2 要注意,operator.itemgetter函式獲取的不是值,而是定義了一個函式,通過該函式作用到物件上才能獲取值。 """ sortedClassCount = sorted(classCount.items(), key = operator.itemgetter(1), reverse = True) #返回k個最近鄰居出現頻率最高的類別,作為當前inX的預測分類 return sortedClassCount[0][0] #將文字記錄轉換為Numpy的解析程式 def file2matrix(filename): fr = open(filename) arrayOLines = fr.readlines()#將每一行內容作為一個元素,共同組成一個列表 numberOfLines = len(arrayOLines)#列表長度,即列表成員個數 returnMat = zeros((numberOfLines,3))#用0填充一個(numberOfLines*3)的矩陣 classLabelVector = []#用於儲存每條資料所對應的類別 index = 0 for line in arrayOLines: """ ----------------str.strip()-------------------- Python strip() 方法用於移除字串頭尾指定的字元(預設為空格或換行符)。 語法:str.strip([chars]); """ line = line.strip() listFromLine = line.split('\t') returnMat[index,:] = listFromLine[0:3] classLabelVector.append(int(listFromLine[-1])) index += 1 return returnMat, classLabelVector # 歸一化特徵值 def autoNorm(dataSet): """ ----------------mat.min()-------------------- a = np.array([[1,5,3],[4,2,6]]) print(a.min()) #無參,所有中的最小值 print(a.min(0)) # axis=0; 每列的最小值 ,得到1*3的矩陣 print(a.min(1)) # axis=1;每行的最小值 ,得到2*1的矩陣 """ minVals = dataSet.min(0)#得到1*3的矩陣 maxVals = dataSet.max(0) ranges = maxVals - minVals normDataSet = zeros(shape(dataSet))#shape(矩陣),返回一個元組(行數,列數) m = dataSet.shape[0]#矩陣的行數 normDataSet = dataSet - tile(minVals,(m,1)) normDataSet = normDataSet/tile(ranges,(m,1)) return normDataSet, ranges, minVals ''' ----------------datingClassTest()------------------ 用於測試knn預測結果的錯誤率 首先把資料集datingDataMat分為兩部分:測試集(0-numTestVecs)和訓練集(numTestVecs-m) ''' def datingClassTest(): # hoRatio 是測試集佔資料集的比例 hoRatio = 0.1 datingDataMat,datingLabels = file2matrix('datingData.txt') normMat,ranges,minVals = autoNorm(datingDataMat) m = normMat.shape[0] numTestVecs = int(m*hoRatio) #測試集的資料項數目 errorCount = 0.0 for i in range(numTestVecs): classifierResult = classify0(normMat[i,:],\ normMat[numTestVecs:m,:],\ datingLabels[numTestVecs:m],\ 3) print('the classifier came back with: %d,the real answer is:%d'\ % (classifierResult, datingLabels[i])) if(classifierResult != datingLabels[i]): errorCount += 1.0 print('the total error rate is: %f' % (errorCount/float(numTestVecs))) #約會網站預測函式 """ 每年獲得的飛行常客里程數 玩視訊遊戲所耗時間百分比 每週消費的冰激凌公升數 分類 7-10 7-10 1-3 極具魅力的人 4-6 4-6 4-6 魅力一般的人 1-3 1-3 7-10 不喜歡 """ def classifyPerson(): resultList = ['in large doses','in small doses','not at all'] """ -----------------input()---------------------- python2.x 用的是 raw_input() python3.x 用的是 input() """ percentTats = float(input(\ 'percentage of time spent playing video games:')) ffMiles = float(input(\ 'frequent flier miles earned per years:')) iceCream = float(input(\ 'liters of ice cream consumed per year:')) datingDataMat,datingLabels = file2matrix('datingData.txt') normMatm,ranges,minVals = autoNorm(datingDataMat) inArr = array([ffMiles,percentTats,iceCream]) classifierResult = classify0((inArr-minVals)/ranges,\ normMatm,datingLabels,3) print('You will probably like this person:%s'\ % resultList[classifierResult - 1]) #----------------------------------------------------使用 k-近鄰演算法 識別手寫數字--------------------------------------------------- """ --------------------img2vector()------------------------- 該函式建立1×1024的NumPy陣列,然後開啟給定的檔案,迴圈讀出檔案的前32行, 並將每行的頭32個字元值儲存在NumPy陣列中,最後返回陣列 """ def img2vector(filename): returnVect = zeros((1,1024)) fr = open(filename) for i in range(32): lineStr = fr.readline() for j in range(32): returnVect[0,32*i+j] = int(lineStr[j]) return returnVect """ --------------------handwritingClassTest()------------------------- 手寫數字識別系統的測試程式碼 """ def handwritingClassTest(): hwLabels = [] trainingFileList = listdir('digits//trainingDigits') m = len(trainingFileList) trainingMat = zeros((m,1024)) for i in range(m): #該目錄下的檔案按照規則命名,如檔案9_45.txt的分類是9,它是數字9的第45個例項 fileNameStr = trainingFileList[i] fileStr = fileNameStr.split('.')[0] classNumStr = int(fileStr.split('_')[0]) hwLabels.append(classNumStr) trainingMat[i,:] = img2vector('digits//trainingDigits//%s' % fileNameStr) testFileList = listdir('digits//testDigits') errorCount = 0.0 mTest = len(testFileList) for i in range(mTest): fileNameStr = testFileList[i] fileStr = fileNameStr.split('.')[0] classNumStr = int(fileStr.split('_')[0]) vectorUnderTest = img2vector('digits//testDigits//%s' % fileNameStr) classifierResult = classify0(vectorUnderTest,\ trainingMat,hwLabels,3) print('the classifier came back with: %d,the real answer is:%d' \ % (classifierResult, classNumStr)) if (classifierResult != classNumStr): errorCount += 1.0 print('the total number of errors is: %d' % (errorCount)) print('the total error rate is: %f' % (errorCount / float(mTest)))