Python高階--K-近鄰演算法(KNN)
K nearest neighbour
K-近鄰演算法採用測量不同特徵值之間的距離方法進行分類。
優點:精度高、對異常值不敏感、無資料輸入假定。
缺點:時間複雜度高、空間複雜度高。
適用資料範圍:數值型和標稱型。
一、K-近鄰演算法(KNN)舉例
1)工作原理
存在一個樣本資料集合,也稱作訓練樣本集,並且樣本集中每個資料都存在標籤,即我們知道樣本集中每一資料
與所屬分類的對應關係。輸人沒有標籤的新資料後,將新資料的每個特徵與樣本集中資料對應的
特徵進行比較,然後演算法提取樣本集中特徵最相似資料(最近鄰)的分類標籤。一般來說,我們
只選擇樣本資料集中前K個最相似的資料,這就是K-近鄰演算法中K的出處,通常*K是不大於20的整數。
最後 ,選擇K個最相似資料中出現次數最多的分類,作為新資料的分類*。
2)演算法例項
回到前面電影分類的例子,使用K-近鄰演算法分類愛情片和動作片。有人曾經統計過很多電影的打鬥鏡頭和接吻鏡頭,下圖顯示了6部電影的打鬥和接吻次數。假如有一部未看過的電影,如何確定它是愛情片還是動作片呢?我們可以使用K-近鄰演算法來解決這個問題。
首先我們需要知道這個未知電影存在多少個打鬥鏡頭和接吻鏡頭,上圖中問號位置是該未知電影出現的鏡頭數圖形化展示,具體數字參見下表。
即使不知道未知電影屬於哪種型別,我們也可以通過某種方法計算出來。首先計算未知電影與樣本集中其他電影的距離,如圖所示。
現在我們得到了樣本集中所有電影與未知電影的距離,按照距離遞增排序,可以找到K個距
離最近的電影。假定k=3,則三個最靠近的電影依次是California Man、He’s Not Really into Dudes、Beautiful Woman。K-近鄰演算法按照距離最近的三部電影的型別,決定未知電影的型別,而這三部電影全是愛情片,因此我們判定未知電影是愛情片。
3)歐幾里得距離(Euclidean Distance)
歐氏距離是最常見的距離度量,衡量的是多維空間中各個點之間的絕對距離。公式如下:
二、在scikit-learn庫中使用k-近鄰演算法
分類問題:from sklearn.neighbors import KNeighborsClassifier
迴歸問題:from sklearn.neighbors import KNeighborsRegressor
三、簡單示例(分類)
給出一組資料(身高、體重、鞋子尺碼)判斷性別
分析:這是一個使用K-臨近演算法(KNN)的分類問題
1)建立訓練資料(特徵和結果)
1.訓練樣本的特徵
注意:這裡的特徵需要和結果一一對應
'''
X_train:訓練樣本的特徵(一列值)
y_train:訓練樣本的結果(標籤)
'''
# 傳入訓練資料
# 身高,體重, 鞋碼
X_train = np.array([
[177,73,42],
[150,44,36],
[177,63,41],
[160,52,35],
[165,70,40],
[179,80,44],
[156,40,36],
[155,50,36]
])
# 一一傳入訓練資料的樣本結果
y_train = np.array(['male','female','male','female','male','male','female','female'])
2)建立 獲取分類的模型
KNeighborsClassifier(n_neighbors=5)
功能:實現k近鄰投票的分類器。
# n_neighbors:獲取最近的幾個 預設是5個
knn_c = KNeighborsClassifier(n_neighbors=5)
3)模型訓練
knn.fit(X, y)
功能:將訓練資料的特徵和結果傳入進行訓練
以X為訓練資料,y為目標值 擬合模型
'''
引數 X 是訓練資料的特徵
引數 y 是訓練資料的結果(標籤)
'''
knn_c.fit(X_train,y_train)
4)模型測試
knn.predict(X)
功能:通過訓練好的模型將測試資料傳入,返回測試結果
為提供的資料預測類標籤
knn_c.predict([
[190,100,45],
[150,35,32]
])
array(['male', 'female'], dtype='<U6')
5)得出結果
返回測試結果與實際資料符合實際情況,這就是K-近鄰演算法(KNN)處理分類問題
四、機器學習–鳶尾花(分類)
機器學習常用庫sklearn
scikit-learning 提供資料樣本,可以供我們研究機器學習模型
# 機器學習裡面包含的資料集
from sklearn import datasets
1)獲取訓練資料(特徵和結果)
使用load方法載入資料可以載入很多可供我們使用的資料
這裡我們使用鳶尾花資料
iris_data = datasets.load_iris()
iris_data
#這裡返回資料較多,我們拿出部分分析
# data:鳶尾花樣本,該樣本有四個特徵,表示 花萼長度 花萼寬度 花瓣長度 花瓣寬度
# target:表示鳶尾花的種類 0(setosa) 1(versicolor) 2(virginica)
{'data': array([[5.1, 3.5, 1.4, 0.2],
[4.9, 3. , 1.4, 0.2],
[4.7, 3.2, 1.3, 0.2],
[4.6, 3.1, 1.5, 0.2],
。。。
[6.5, 3. , 5.2, 2. ],
[6.2, 3.4, 5.4, 2.3],
[5.9, 3. , 5.1, 1.8]]),
'target': array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2]),}
#還有一些描述的資訊
我們獲取的iris_data
是一個字典型別的資料
1. 獲取訓練樣本特徵
data = iris_data.data #訓練樣本的值
feature = iris_data.feature_names #訓練樣本的值對應的名稱
2. 獲取訓練樣本結果
target = iris_data.target # 所有樣本的目標值
target_names = iris_data.target_names # 目標值對應的名稱
3. 將得到的資料繪製圖形
DataFrame(data).plot()
畫圖研究前兩個特徵和分類之間的關係
(二維散點圖只能展示兩個維度)
1、這裡擷取前兩個特徵來展示
X_train = data[:,0:2] # 訓練樣本的特徵
y_train = target # 訓練樣本的結果
#目前取得樣本特徵和結果依舊是一一對應的關係
2、展示特徵和結果之間的關係
花萼長度為x, 花萼寬度為y 對所有樣本進行定位
我們使用點的顏色對其進行分類,散點圖引數c可以傳入一個數組,陣列我們可以用樣本的值使傳入的x, y對應的點得顏色與值一一對應,這樣就將圖中的點分為三類區分開
plt.scatter(X_train[:,0],X_train[:,1],c=y_train)
plt.xlabel('sepal length') #設定x軸的標籤
plt.ylabel('sepal width') #設定y軸的標籤
2)建立 獲取分類的模型
建立分類模型
knn_c = KNeighborsClassifier(n_neighbors=5)
3)模型訓練
將訓練資料樣本特徵和結果放入模型訓練
knn_c.fit(X_train,y_train)
4)模型測試
將測試資料傳入訓練模型,返回訓練結果
knn_c.predict([
[4.5,4.0],
[7.5,3.0],
[5.25,2.25]
])
array([0, 2, 1])
4)測試結果分析
測試資料的預測結果與實際結果相同
5)創造測試資料,測試模型結果
1、創造測試資料
先取到x軸線的範圍和y軸的範圍取到
# 為了全面,將資料的範圍稍微擴大一點
xmin = X_train[:,0].min()-0.5
xmax = X_train[:,0].max()+0.5
ymin = X_train[:,1].min()-0.5
ymax = X_train[:,1].max()+0.5
將x軸的資料和y軸的資料每隔 0.01 取一份
# x軸範圍內要取遍
x = np.arange(xmin,xmax,0.01)
# y軸範圍內也要取遍
y = np.arange(ymin,ymax,0.01)
#我們拿到座標軸的資料之後,我們要拿到每個點的座標
拿到每個點對應的x,y座標
xx,yy = np.meshgrid(x,y) # 將畫布上所有的點取遍
xx.flatten(),yy.flatten() # 將矩陣扁平化
(array([3.8 , 3.81, 3.82, ..., 8.38, 8.39, 8.4 ]),
array([1.5, 1.5, 1.5, ..., 4.9, 4.9, 4.9]))
# 把對應位置的兩個內容取出來 變成新的列表
X_test = np.c_[xx.flatten(),yy.flatten()] # 將平面上所有的點取遍 並 用來作為測試資料
array([[3.8 , 1.5 ],
[3.81, 1.5 ],
[3.82, 1.5 ],
...,
[8.38, 4.9 ],
[8.39, 4.9 ],
[8.4 , 4.9 ]])
2、使用剛剛訓練好的模型進行預測
y_ = knn_c.predict(X_test) #預測後返回預測結果值
3、繪製測試結果圖形
根據特徵繪製樣本的兩個特徵 X_test[:,0],X_test[:,1]
根據模型預測的結果 y_
繪製樣本的顏色
plt.scatter(X_test[:,0],X_test[:,1],c=y_)
4、將訓練資料和自己建立的測試資料作比較
把真實的訓練資料也畫到圖上
plt.scatter(X_test[:,0],X_test[:,1],c=y_)
plt.scatter(X_train[:,0],X_train[:,1],c=y_train,cmap=cmap0) #這裡的cmap給color設定顏色
5、為影象制定顏色
需要匯入
from matplotlib.colors import ListedColormap
cmap0 = ListedColormap(['red','green','blue'])
# 將cmap0傳入上面的圖的效果
五、預測趨勢(迴歸)
導包
from sklearn.neighbors import KNeighborsRegressor
1)生成訓練樣本資料
1、種子生成器
功能:固定隨機數,多次執行,產生相同的隨機數
np.random.seed(0)
np.random.seed(0)
np.random.random()
nd = np.random.rand(40,1) # 樣本 40行1列
nd
2、對生成的訓練資料排序np.sort
np.sort() 預設對最內層的資料進行排序 現在要對每一行進行排序 讓樣本從小到大排列
設定 np.sort(nd,axis=0)
對nd進行排序 然後放大5倍數
X_train = 5*np.sort(nd,axis=0)
3、訓練資料值
結果集 是一個一維陣列,所以在這裡要將他改變
y_train = np.sin(X_train).flatten()
2)繪製訓練資料
plt.scatter(X_train,y_train)
3)新增噪聲
給y_train新增一些噪聲 讓x和y的關係不要那麼明確
我們的訓練資料為 40 行一列的資料,我們每隔4個給加一個隨機噪聲
1、製造噪聲
noise = np.random.random(size=10)/2
noise
array([0.2343256 , 0.48838054, 0.30242276, 0.36963179, 0.0195939 ,
0.14140348, 0.06009828, 0.1480701 , 0.05936386, 0.15899159])
2、新增噪聲
每隔4個加一個噪聲
y_train[::4] += noise
2、新增噪聲後的圖形
plt.scatter(X_train,y_train)
4)生成模型
from sklearn.neighbors import KNeighborsRegressor
# 獲取模型
knn = KNeighborsRegressor(n_neighbors=30)
5)訓練資料
把訓練資料傳入模型,
x:訓練樣本特徵
y:訓練樣本值
'''
# X_train是多行資料 有幾個樣本就有幾行 有幾個特徵就有幾列
# y_train 是一個一維的陣列 裡面直接裝著結果值
'''
knn.fit(X_train,y_train)
6)建立測試資料
把x範圍內的值取遍 然後用機器學習模型獲取y_
這裡的樣本資料為一列,所以繪圖時不用調整座標(相對於上面鳶尾花來說)。
xmin = X_train.min()
xmax = X_train.max()
X_test = np.arange(xmin,xmax,0.01)
7)測試樣本值
注意,有一個特徵,傳入的樣本值應該為n行1列
y_ = knn.predict(X_test.reshape(-1,1))
8)繪圖顯示資料
plt.plot(X_test,y_,color='green',label='predict') #設定顏色和圖示
plt.scatter(X_train,y_train,label='real',color='k')
plt.legend() #顯示圖示
六、人類動作識別
1) 資料儲存np.save(儲存路徑, 資料)
1)儲存*.npy資料檔案np.save
nd = np.array([1,2,3])
nd
# np.save方法可以把資料儲存到本地 引數 1.是路徑 2.是資料
np.save('./test',nd) #這裡可以不輸入檔案字尾
2)載入*.npy資料檔案np.load(”檔案路徑”)
np.load('./test.npy')
array([1, 2, 3])
2) 匯入訓練集和測試集
1、匯入資料
X_train = np.load('./data/x_train.npy')
y_train = np.load('./data/y_train.npy')
2、檢視資料資訊
X_train.shape
(7352, 561) #資料有 7352行,561列
y_train.size
7352
Series(y_train).unique()
array([5, 4, 6, 1, 3, 2], dtype=int64)
'''
這裡訓練結果集代表的運動型別
1:'walking', #走
2:'walking upstairs', #上樓
3:'walking downstairs', #下樓
4:'sitting', #坐著
5:'standing', #站著
6:'laying' #躺著
'''
3、畫圖檢視各個特徵的圖形
我們隨機抽查 第100,200,300,400,500,600個樣本檢視訓練樣本的結果
n = 100
y_train[n]
labels[y_train[n]]
'walking'
------------------------
n = 200
y_train[n]
labels[y_train[n]]
'standing'
------------------------
n = 300
y_train[n]
labels[y_train[n]]
'walking downstairs'
------------------------
n = 400
y_train[n]
labels[y_train[n]]
'sitting'
------------------------
n = 500
y_train[n]
labels[y_train[n]]
'walking upstairs'
------------------------
n = 600
y_train[n]
labels[y_train[n]]
'laying'
我們可以看出抽取的這 6 個數據將全部型別的取出來,我們將這6個訓練樣本繪圖展示觀察
plt.figure(figsize=(20,10)) #設定畫布大小
for i in [1,2,3,4,5,6]:
axes = plt.subplot(3,2,i) #建立子畫布
axes.plot(X_train[i*100],color=colors[i-1]) #在子畫布上畫圖
axes.set_title(labels[y_train[i*100]]) 設定子畫布的標題
3) 訓練模型
1、建立訓練模型
knn = KNeighborsClassifier(n_neighbors=5)
2、訓練資料
傳入訓練資料與訓練結果
knn.fit(X_train,y_train)
3、
4、
4) 模型預測
y_ = knn.predict(X_test)
array([5, 5, 5, ..., 2, 2, 1], dtype=int64)
5) 預測準確率
1、自己計算
將預測值與測試值相等,得出預測正確的個數
y_ == y_test # 獲取的是布林值的序列 相等的是True 不想等是False
array([ True, True, True, ..., True, True, False])
測試結果個數與預測結果個數
(y_ == y_test).sum()
2657
y_test.size
2947
兩者相乘
(y_ == y_test).sum() / y_test.size
0.9066847641669494
2、KNN自帶方法
機器學習模型 給我們提供了 打分的方法
# 引數 1.是測試集的特徵資料 2.是測試集的真實結果
# 把測試集的特徵資料傳入後 機器學習模型 會 計算得到預測結果y_
# 然後和傳入的真是結果 y_test 對比 返回準確率
knn.score(X_test,y_test)