kNN原理與python應用

0. 原理

待更

1. 應用-Iris數據集

來源於《Python機器學習基礎教程》一書,機器學習之旅從鳶尾花開始~
注意:python中機器學習數據集結構:

feature target
X1,…,Xn y
data target
X y

scikit-learn 中的數據通常用大寫的X 表示,而標籤用小寫的y 表示。這是來源於f(x)=y ,其中x 是函數的輸入,y 是輸出。大寫的X是因爲數據是一個二維數組(矩陣),小寫的y 是因爲目標是一個一維數組(向量),這也是數學中的約定。

導入包並加載數據

import numpy as np
import pandas as pd
import seaborn as sns  # 美化繪圖
import sklearn
from sklearn.datasets import load_iris  # 導入數據集
iris_dataset = load_iris()  # 加載後的數據是Bunch對象,類似於字典

查看數據

print("Keys of iris_dataset:\n{}".format(iris_dataset.keys()))  

# 其中DESCR是數據集的說明
Keys of iris_dataset:
dict_keys(['data', 'target', 'target_names', 'DESCR', 'feature_names', 'filename'])
print(iris_dataset['DESCR'])  # print帶格式,直接輸出沒有格式

在這裏插入圖片描述

著名的鳶尾花數據集, 請注意,它與R中的相同,但與UCI中的不同
機器學習存儲庫,其中有兩個錯誤的數據點。

print(iris_dataset['target_names'])  # 類別名
print(iris_dataset['feature_names'])  # 特徵名
print(type(iris_dataset['data']))  # 數據結構
print(iris_dataset['data'].shape)  # 維度
print(iris_dataset['data'][:5])  # 數據前五行
print(type(iris_dataset['target']))  # target's type
print(iris_dataset['target'].shape)  # target's shape

在這裏插入圖片描述

iris_dataset['target']  # 0,1,2
iris_dataset['target_names']  
# array(['setosa', 'versicolor', 'virginica'], dtype='<U10'),對應0,1,2

數據拆分爲訓練集與測試集

scikit-learn 中的train_test_split 函數可以隨機打亂數據集並進行拆分。默認將75% 的行數據及對應標籤作爲訓練集,剩下25% 的數據及其標籤作爲測試集。使用25% 的數據作爲測試集是很好的經驗法則。

from sklearn.model_selection import train_test_split

X, y = iris_dataset['data'], iris_dataset['target']
X_train, X_test, y_train, y_test = train_test_split(X,y,random_state=0)

print(X_train.shape)  # (112, 4)
  • 爲什麼要打亂順序?如果只將後25%用於測試,則測試集都來自第3種花,不合理,確保test中含有所有類別的數據
  • 爲什麼指定隨機數種子?爲了確保多次運行同一函數能夠得到相同的輸出
# Split arrays or matrices into random train and test subsets
?train_test_split  

X_train, X_test, y_train, y_test = train_test_split(data_X,data_y,…) : 返回4個array

  1. test_size : if float,between 0.0 and 1.0,測試集應占的比例,默認0.25;if int,表示測試集中的樣本數
  2. random_state : If int, random_state is the seed used by the random number generator;隨機數種子
  3. shuffle :(default=True):在拆分前是否隨機打亂數據順序
    注:詳情與示例見docstring

觀察數據-可視化

散點圖,將一個特徵作爲x 軸,另一個特徵作爲y 軸,將每一個數據點繪製爲圖上的一個點,一次只能繪製兩個特徵,對多於3 個特徵的數據集作圖,繪製散點圖矩陣。
散點圖矩陣無法同時顯示所有特徵之間的關係,只能兩兩查看,所以這種可視化方法可能無法展示數據的某些有趣內容。
建議使用seaborn繪製

# 先轉換爲dataframe,然後使用pandas.scatter_matrix(),對角線是每個特徵的直方圖或密度圖
df = pd.DataFrame(X_train,columns=iris_dataset['feature_names'])

# 創建散點圖矩陣,按y_train着色(一列標籤)。因爲X_train和y_train一一對應
grr = pd.plotting.scatter_matrix(df,c=y_train,figsize=(10,10),marker='.',hist_kwds={'bins':20},s=60,alpha=0.8)

pandas自帶繪圖函數pd.plotting.scatter_matrix(frame)
可選參數:(詳見docstring)

  1. diagonal:必須且只能在{‘hist’, ‘kde’}中選擇1個,’hist’表示直方圖,’kde’表示核密度估計(Kernel Density Estimation),該參數是scatter_matrix函數的關鍵參數。
  2. hist_kwds:與hist相關的字典參數
  3. c:顏色

對於散點圖矩陣,seaborn包畫圖更美觀。
sns繪製散點圖矩陣所需的數據結構是X與y在一起的一個df。
使用詳情參見docstring。

y_train_se = pd.Series(y_train)  # se可以自動變換類型,array不可以
y_train_se[y_train_se == 0] = 'setosa'  # 方便圖例生成
y_train_se[y_train_se == 1] = 'versicolor'
y_train_se[y_train_se == 2] = 'virginica'
df['class'] = y_train_se  # sns繪製散點圖矩陣所需的數據結構是X與y在一起的一個df

sns.pairplot(df,plot_kws={'alpha':0.8},hue='class')  # hue爲df中一列的列名,爲不同的點標記顏色,該列的值爲圖例,按類別標籤着色

在這裏插入圖片描述
參考:
https://blog.csdn.net/zyb228/article/details/101940096/
https://www.jianshu.com/p/6e18d21a4cad

kNN-model

  1. k近鄰分類器:構建此模型只需要保存訓練集即可。要對一個新的數據點做出預測,算法會在訓練集中尋找與這個新數據點距離最近的數據點,然後將找到的數據點的標籤賦值給這個新數據點。
  2. k的含義是,我們可以考慮訓練集中與新數據點最近的任意k個鄰居,用這些鄰居中數量最多的類別做出預測。
  3. scikit-learn 中所有的機器學習模型都在各自的類中實現。k 近鄰分類算法是在neighbors 模塊的KNeighborsClassifier 類中實現的。需要將這個類實例化爲一個對象,然後才能使用這個模型。這時我們需要設置模型的參數。
  4. KNeighborsClassifier 最重要的參數就是鄰居的數目

docstring的示例:

?KNeighborsClassifier

Examples
--------
>>> X = [[0], [1], [2], [3]]
>>> y = [0, 0, 1, 1]
>>> from sklearn.neighbors import KNeighborsClassifier
>>> neigh = KNeighborsClassifier(n_neighbors=3)
>>> neigh.fit(X, y) # doctest: +ELLIPSIS
KNeighborsClassifier(...)
>>> print(neigh.predict([[1.1]]))
[0]
>>> print(neigh.predict_proba([[0.9]]))
[[0.66666667 0.33333333]]

應用:

from sklearn.neighbors import KNeighborsClassifier  # knn也可用於迴歸,是KNeighborsRegression

knn = KNeighborsClassifier(n_neighbors=1)  # 設置具體參數來實例化

knn 對象對算法進行了封裝,既包括用訓練數據構建模型的算法,也包括對新數據點進行預測的算法。它還包括算法從訓練數據中提取的信息。
對KNeighborsClassifier 來說,裏面只保存了訓練集。

想要基於訓練集來構建模型,需要調用knn 對象的fit 方法,輸入參數爲X_train 和y_train,二者都是NumPy 數組,前者包含訓練數據,後者包含相應的訓練標籤:

knn.fit(X_train,y_train) # fit 方法返回的是knn 對象本身並做原處修改,因此得到分類器的字符串表示。從中可以看出構建模型時用到的參數。
# 模型都有很多參數,但多用於速度優化或非常特殊的用途。

在這裏插入圖片描述

評估模型-使用測試集,進行結果對比

可以通過計算精度(accuracy)來衡量模型的優劣,精度就是品種預測正確的花所佔的比例:

# 得到測試集的預測值
y_pred = knn.predict(X_test)
y_pred  # array([2, 1, 0, 2, 0, 2, 0, 1, 1, 1, 2, 1, 1, 1, 1, 0, 1, 1, 0, 0, 2, 1,0, 0, 2, 0, 0, 1, 1, 0, 2, 1, 0, 2, 2, 1, 0, 2])

# 與測試集的真實值比較得到精度
np.mean(y_pred == y_test)  # 0,1之間算1的比例就是所有的平均值,等價於
knn.score(X_test,y_test)   # 0.9736842105263158

?knn.score
Returns the mean accuracy on the given test data and labels.

進行預測

X_new = np.array([[5,2.9,1,0.2]])  # 一條新數據
print(X_new.shape)  # (1, 4),二維數組的一行,因爲scikit-learn的輸入數據必須是二維數組。
prediction = knn.predict(X_new)  # 預測
prediction  # array([0]) ,類別是0
iris_dataset['target_names'][prediction]  # array(['setosa'], dtype='<U10')

2. 模型複雜度和泛化能力之間的關係-乳腺癌數據集

from sklearn.datasets import load_breast_cancer
import sklearn
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
import matplotlib.pyplot as plt

cancer = load_breast_cancer()
cancer.keys()
print(cancer.DESCR)
# 拆分訓練集與測試集
X_train,X_test,y_train,y_test = train_test_split(cancer.data,cancer.target,stratify=cancer.target,random_state=66)

strtigy : array-like, 數據以分層方式拆分,並將其用作類標籤。按不同類別所佔比例拆分?並轉換爲0,1標籤?

## 記錄訓練集精度和測試集精度
n_max = 10
n_range = range(1,n_max+1)   # 鄰居範圍
train_acc = np.zeros(n_max)
test_acc = np.zeros(n_max)

for i,n in enumerate(n_range):
    knn = KNeighborsClassifier(n_neighbors=n)
    knn.fit(X_train,y_train)
    train_acc[i] = knn.score(X_train,y_train)
    test_acc[i] = knn.score(X_test,y_test)
## 畫圖
plt.plot(n_range,train_acc,label='train acc')
plt.plot(n_range,test_acc,label='test_acc',linestyle='--')
plt.xlabel('n neighbors')
plt.ylabel('Accuracy')
plt.legend()

在這裏插入圖片描述
可以看出,更少的鄰居對應更復雜的模型,訓練集精度高,測試集精度低,最近鄰是過擬合。
泛化最佳性能在n=6時,測試集精度最高。
最差的性能約爲88% 的精度,這個結果仍然可以接受。

3. kNN迴歸

  1. 在使用多個近鄰進行時,預測結果爲這些鄰居的平均值。
  2. 評估模型:score 方法,對於迴歸問題,返回R2,即決定係數,是迴歸模型預測的優度度量,等於1 對應完美預測,等於0 對應常數模型,即總是預測訓練集響應(y_train)的平均值。R2越大擬合越好
from sklearn.neighbors import KNeighborsRegressor  # kNN迴歸器

X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0)
# 模型實例化,並將鄰居個數設爲3
reg = KNeighborsRegressor(n_neighbors=3)
# 利用訓練數據和訓練目標值來擬合模型
reg.fit(X_train, y_train)
# 預測結果
reg.predict(X_test)
# 評估模型
reg.score(X_test, y_test)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章