最近在看《機器學習實戰》這本書,由於本身自己很想深刻的瞭解機器學習算法,加之想學python,就在朋友的推薦之下選擇了這本書進行學習。 python
一 . K-近鄰算法(KNN)概述 算法
最簡單最初級的分類器是將所有的訓練數據所對應的類別都記錄下來,當測試對象的屬性和某個訓練對象的屬性徹底匹配時,即可以對其進行分類。可是怎麼可能全部測試對象都會找到與之徹底匹配的訓練對象呢,其次就是存在一個測試對象同時與多個訓練對象匹配,致使一個訓練對象被分到了多個類的問題,基於這些問題呢,就產生了KNN。編程
KNN是經過測量不一樣特徵值之間的距離進行分類。它的思路是:若是一個樣本在特徵空間中的k個最類似(即特徵空間中最鄰近)的樣本中的大多數屬於某一個類別,則該樣本也屬於這個類別,其中K一般是不大於20的整數。KNN算法中,所選擇的鄰居都是已經正確分類的對象。該方法在定類決策上只依據最鄰近的一個或者幾個樣本的類別來決定待分樣本所屬的類別。小程序
下面經過一個簡單的例子說明一下:以下圖,綠色圓要被決定賦予哪一個類,是紅色三角形仍是藍色四方形?若是K=3,因爲紅色三角形所佔比例爲2/3,綠色圓將被賦予紅色三角形那個類,若是K=5,因爲藍色四方形比例爲3/5,所以綠色圓被賦予藍色四方形類。app
由此也說明了KNN算法的結果很大程度取決於K的選擇。機器學習
在KNN中,經過計算對象間距離來做爲各個對象之間的非類似性指標,避免了對象之間的匹配問題,在這裏距離通常使用歐氏距離或曼哈頓距離:函數式編程
同時,KNN經過依據k個對象中佔優的類別進行決策,而不是單一的對象類別決策。這兩點就是KNN算法的優點。函數
接下來對KNN算法的思想總結一下:就是在訓練集中數據和標籤已知的狀況下,輸入測試數據,將測試數據的特徵與訓練集中對應的特徵進行相互比較,找到訓練集中與之最爲類似的前K個數據,則該測試數據對應的類別就是K個數據中出現次數最多的那個分類,其算法的描述爲:學習
1)計算測試數據與各個訓練數據之間的距離;測試
2)按照距離的遞增關係進行排序;
3)選取距離最小的K個點;
4)肯定前K個點所在類別的出現頻率;
5)返回前K個點中出現頻率最高的類別做爲測試數據的預測分類。
二 .python實現
首先呢,須要說明的是我用的是python3.4.3,裏面有一些用法與2.7仍是有些出入。
創建一個KNN.py文件對算法的可行性進行驗證,以下:
#coding:utf-8
from numpy import *
import operator ##給出訓練數據以及對應的類別
def createDataSet(): group = array([[1.0,2.0],[1.2,0.1],[0.1,1.4],[0.3,3.5]]) labels = ['A','A','B','B'] return group,labels ###經過KNN進行分類
def classify(input,dataSe t,label,k): dataSize = dataSet.shape[0] ####計算歐式距離
diff = tile(input,(dataSize,1)) - dataSet sqdiff = diff ** 2 squareDist = sum(sqdiff,axis = 1)###行向量分別相加,從而獲得新的一個行向量
dist = squareDist ** 0.5
##對距離進行排序
sortedDistIndex = argsort(dist)##argsort()根據元素的值從大到小對元素進行排序,返回下標
classCount={} for i in range(k): voteLabel = label[sortedDistIndex[i]] ###對選取的K個樣本所屬的類別個數進行統計
classCount[voteLabel] = classCount.get(voteLabel,0) + 1
###選取出現的類別次數最多的類別
maxCount = 0 for key,value in classCount.items(): if value > maxCount: maxCount = value classes = key return classes
接下來,在命令行窗口輸入以下代碼:
#-*-coding:utf-8 -*-
import sys sys.path.append("...文件路徑...") import KNN from numpy import * dataSet,labels = KNN.createDataSet() input = array([1.1,0.3]) K = 3 output = KNN.classify(input,dataSet,labels,K) print("測試數據爲:",input,"分類結果爲:",output)
回車以後的結果爲:
測試數據爲: [ 1.1 0.3] 分類爲: A
答案符合咱們的預期,要證實算法的準確性,勢必還須要經過處理複雜問題進行驗證,以後另行說明。
這是第一次用python編的一個小程序,勢必會遇到各類問題,在這次編程調試過程當中遇到了以下問題:
1 導入.py文件路徑有問題,所以須要在最開始加以下代碼:
sys.path.append("文件路徑"),這樣就不會存在路徑有誤的問題了;
2 在python提示代碼存在問題時,必定要及時改正,改正以後保存以後再執行命令行,這一點跟MATLAB是不同的,因此在python中最好是敲代碼的同時在命令行中一段一段的驗證;
3 在調用文件時函數名必定要寫正確,不然會出現:'module' object has no attribute 'creatDataSet';
4 'int' object has no attribute 'kclassify',這個問題出現的緣由是以前我講文件保存名爲k.py,在執行
output = K.classify(input,dataSet,labels,K)這一句就會出錯。根據函數式編程的思想,每一個函數均可以看爲是一個變量而將K賦值後,調用k.py時就會出現問題。
三 MATLAB實現
以前一直在用MATLAB作聚類算法的一些優化,其次就是數模的一些經常使用算法,對於別的算法,還真是沒有上手編過,基礎還在,思想還在,固然要動手編一下,也是不但願在學python的同時對MATLAB逐漸陌生吧,走走停停,停很重要。
首先,創建KNN.m文件,以下:
%% KNN clear all clc %% data trainData = [1.0,2.0;1.2,0.1;0.1,1.4;0.3,3.5]; trainClass = [1,1,2,2]; testData = [0.5,2.3]; k = 3; %% distance row = size(trainData,1); col = size(trainData,2); test = repmat(testData,row,1); dis = zeros(1,row); for i = 1:row diff = 0; for j = 1:col diff = diff + (test(i,j) - trainData(i,j)).^2; end dis(1,i) = diff.^0.5; end %% sort jointDis = [dis;trainClass]; sortDis= sortrows(jointDis');
sortDisClass = sortDis';
%% find class = sort(2:1:k); member = unique(class); num = size(member); max = 0; for i = 1:num count = find(class == member(i)); if count > max max = count; label = member(i); end end disp('最終的分類結果爲:'); fprintf('%d\n',label)
運行以後的結果是,最終的分類結果爲:2。和預期結果同樣。
三 實戰
以前,對KNN進行了一個簡單的驗證,今天咱們使用KNN改進約會網站的效果,我的理解,這個問題也能夠轉化爲其它的好比各個網站迎合客戶的喜愛所做出的推薦之類的,固然,今天的這個例子功能也實在有限。
在這裏根據一我的收集的約會數據,根據主要的樣本特徵以及獲得的分類,對一些未知類別的數據進行分類,大體就是這樣。
我使用的是python 3.4.3,首先創建一個文件,例如date.py,具體的代碼以下:
#coding:utf-8
from numpy import *
import operator
from collections import Counter
import matplotlib
import matplotlib.pyplot as plt
###導入特徵數據
def file2matrix(filename):
fr = open(filename)
contain = fr.readlines()###讀取文件的全部內容
count = len(contain)
returnMat = zeros((count,3))
classLabelVector = []
index = 0
for line in contain:
line = line.strip() ###截取全部的回車字符
listFromLine = line.split('\t')
returnMat[index,:] = listFromLine[0:3]###選取前三個元素,存儲在特徵矩陣中
classLabelVector.append(listFromLine[-1])###將列表的最後一列存儲到向量classLabelVector中
index += 1
##將列表的最後一列由字符串轉化爲數字,便於之後的計算
dictClassLabel = Counter(classLabelVector)
classLabel = []
kind = list(dictClassLabel)
for item in classLabelVector:
if item == kind[0]:
item = 1
elif item == kind[1]:
item = 2
else:
item = 3
classLabel.append(item)
return returnMat,classLabel#####將文本中的數據導入到列表
##繪圖(能夠直觀的表示出各特徵對分類結果的影響程度)
datingDataMat,datingLabels = file2matrix('D:\python\Mechine learing in Action\KNN\datingTestSet.txt')
fig = plt.figure()
ax = fig.add_subplot(111)
ax.scatter(datingDataMat[:,0],datingDataMat[:,1],15.0*array(datingLabels),15.0*array(datingLabels))
plt.show()
## 歸一化數據,保證特徵等權重
def autoNorm(dataSet):
minVals = dataSet.min(0)
maxVals = dataSet.max(0)
ranges = maxVals - minVals
normDataSet = zeros(shape(dataSet))##創建與dataSet結構同樣的矩陣
m = dataSet.shape[0]
for i in range(1,m):
normDataSet[i,:] = (dataSet[i,:] - minVals) / ranges
return normDataSet,ranges,minVals
##KNN算法
def classify(input,dataSet,label,k):
dataSize = dataSet.shape[0]
####計算歐式距離
diff = tile(input,(dataSize,1)) - dataSet
sqdiff = diff ** 2
squareDist = sum(sqdiff,axis = 1)###行向量分別相加,從而獲得新的一個行向量
dist = squareDist ** 0.5
##對距離進行排序
sortedDistIndex = argsort(dist)##argsort()根據元素的值從大到小對元素進行排序,返回下標
classCount={}
for i in range(k):
voteLabel = label[sortedDistIndex[i]]
###對選取的K個樣本所屬的類別個數進行統計
classCount[voteLabel] = classCount.get(voteLabel,0) + 1
###選取出現的類別次數最多的類別
maxCount = 0
for key,value in classCount.items():
if value > maxCount:
maxCount = value
classes = key
return classes
##測試(選取10%測試)
def datingTest():
rate = 0.10
datingDataMat,datingLabels = file2matrix('D:\python\Mechine learing in Action\KNN\datingTestSet.txt')
normMat,ranges,minVals = autoNorm(datingDataMat)
m = normMat.shape[0]
testNum = int(m * rate)
errorCount = 0.0
for i in range(1,testNum):
classifyResult = classify(normMat[i,:],normMat[testNum:m,:],datingLabels[testNum:m],3)
print("分類後的結果爲:,", classifyResult)
print("原結果爲:",datingLabels[i])
if(classifyResult != datingLabels[i]):
errorCount += 1.0
print("誤分率爲:",(errorCount/float(testNum)))
###預測函數
def classifyPerson():
resultList = ['一點也不喜歡','有一丟丟喜歡','灰常喜歡']
percentTats = float(input("玩視頻所佔的時間比?"))
miles = float(input("每一年得到的飛行常客里程數?"))
iceCream = float(input("每週所消費的冰淇淋公升數?"))
datingDataMat,datingLabels = file2matrix('D:\python\Mechine learing in Action\KNN\datingTestSet2.txt')
normMat,ranges,minVals = autoNorm(datingDataMat)
inArr = array([miles,percentTats,iceCream])
classifierResult = classify((inArr-minVals)/ranges,normMat,datingLabels,3)
print("你對這我的的喜歡程度:",resultList[classifierResult - 1])
新建test.py文件瞭解程序的運行結果,代碼:
#coding:utf-8
from numpy import *
import operator
from collections import Counter
import matplotlib
import matplotlib.pyplot as plt
import sys
sys.path.append("D:\python\Mechine learing in Action\KNN")
import date
date.classifyPerson()
運行結果以下圖:
以上,是對本次算法的整理和總結。