先解釋幾個概念
機器學習主要分為:監督學習和無監督學習。
· 監督學習:從已知類別的數據集中學習出一個函數,這個函數可以對新的數據集進行預測或分類,數據集包括特征值和目標值,即有標准答案;常見算法類型可以分為:分類和回歸。
分類問題常見算法:K-近鄰(KNN)、朴素貝葉斯、決策樹、隨機森林、邏輯回歸、神經網絡 回歸常用於預測,比如房價,常見算法:線性回歸、嶺回歸
· 無監督學習:與監督學習的主要區別是,數據集中沒有人為標注的目標值,即沒有標准答案;常見算法有:聚類,生成對抗網絡。
K-近鄰算法
這是機器學習中最簡單的一個算法,先看定義
定義:如果一個樣本與特征空間中的K個樣本距離最近,這K個樣本中的大多數屬於A類別,那么該樣本也屬於A類別。
通俗說就是通過你最近的K個鄰居來求出你的類別; 比如現在要求你所在的區域,A在朝陽區,B在海淀區,C在海淀區,D在房山區,你與ABC的距離分別是:20,28,23,35;K值取3,那么這三個離你最近的鄰居是A、B、C,這三個中有兩個屬於海淀區,按照K-近鄰算法,你所在的區域就是海淀區;如果K取1,就是朝陽區; 由此也說明了K近鄰算法的結果很大程度上受K取值的影響,通常K值取不大於20的整數。
K-近鄰中的距離如何計算?
這里的距離一般使用歐式距離,公式如下:

比如有兩個樣本:A (a1,a2,a3) ,B (b1,b2,b3)這兩個樣本的距離計算為:
從公式中可以看出,如果特征a1是體重,a2是身高,那么這兩個特征的單位不同,而且a2的數值較大,對於結果的影響也較大,所以使用K-近鄰算法之前需要對數據進行標准化(所有涉及到距離運算的算法都需要進行標准化),標准化的概念介紹在這里:
K-近鄰的優缺點及應用場景
-
優點:易實現,無需估計參數,無需訓練,對異常值不敏感
-
缺點:計算量大,耗內存,對K值依賴較大
-
適合數值型的小數據場景
scikit-learn中K-近鄰的API是:sklearn.neighbors.KNeighborsClassifier
下面結合scikit-learn中的內置數據集(鳶尾花數據集),介紹scikit-learn中K-近鄰的簡單使用:
# scikit-learn中的內置數據集都在datasets這個模塊中,導入鳶尾花數據集 from sklearn.datasets import load_iris # 導入K-近鄰的API from sklearn.neighbors import KNeighborsClassifier # 導入標准化API from sklearn.preprocessing import StandardScaler # 導入切分數據集的API from sklearn.model_selection import train_test_split # 加載數據 iris = load_iris() # 切分數據集,參數含義下面詳解 x_train,x_test,y_train,y_test=train_test_split(iris.data,iris.target,test_size=0.25,random_state=None)
train_testsplit用於將數據集切分為訓練集和測試集,訓練集用於模型的訓練,測試集用於模型的驗證; 第一個參數是特征值,第二個參數是目標值; test_size用於設置測試集,如果是float類型,表示測試集的比例,一般取值為0.25,如果是int類型,表示測試集的個數;返回值分別是:訓練集特征值,測試集特征值,訓練集目標值,測試集目標值,這里用x表示特征值,y表示目標值; random_state是隨機狀態,默認為None,即沒有固定的狀態,會隨機打散數據,每次運行返回的測試集和訓練集都不同,如果是int類型,就代表該組隨機數的編號,例如每次運行都設置為1,那么得出的數據集是相同的;
# 對訓練集和測試集的特征值進行標准化 std = StandardScaler() x_train = std.fit_transform(x_train) x_test = std.transform(x_test) # 實例化K近鄰算法,算法實例化時需要手動指定的參數稱為超參數,n_neighbors就是上面說的K值 knn = KNeighborsClassifier(n_neighbors=3) # 將訓練集放入模型進行訓練 knn.fit(x_train,y_train) # 使用測試集的特征值進行預測,返回預測的目標值 y_predict = knn.predict(x_test) # 輸入測試集的特征值和目標值進行評估 print('准確率為:') knn.score(x_test,y_test)
knn.score用於評估模型的准確率
輸出結果:
准確率為: 0.9473684210526315
到這里已經介紹了scikit-learn中KNN的使用,但是上面構建的模型很有局限性,上面說過KNN的結果受K值影響,以上例子只進行了一次測試,並不知道此K值是不是最合適的,而且數據集只進行了一次切分,通常K-近鄰需要搭配(K-折)交叉驗證與網格搜索一起使用
什么是K-折交叉驗證?
初始采樣分割成K個子樣本,一個單獨的子樣本被保留作為驗證模型的數據,其他K-1個樣本用來訓練。交叉驗證重復K次,每個子樣本驗證一次,平均K次的結果或者使用其它結合方式,最終得到一個單一估測。這個方法的優勢在於,同時重復運用隨機產生的子樣本進行訓練和驗證,每次的結果驗證一次,10折交叉驗證是最常用的。

例如5折交叉驗證,全部可用數據集分成五個集合,每次迭代都選其中的1個集合數據作為驗證集,另外4個集合作為訓練集,經過5組的迭代過程。交叉驗證的好處在於,可以保證所有數據都有被訓練和驗證的機會,也盡最大可能讓優化的模型性能表現的更加可信,避免過擬合。
什么是網格搜索?
通過遍歷給定的參數組合,選出最優的參數建立模型。
網格搜索的API是:sklearn.model_selection.GridSearchCV,里面實現了交叉驗證
將以上例子結合網格搜索優化如下:
from sklearn.datasets import load_iris from sklearn.model_selection import train_test_split,GridSearchCV from sklearn.neighbors import KNeighborsClassifier from sklearn.preprocessing import StandardScaler # 加載數據 iris = load_iris() # 數據集切分 x_train,x_test,y_train,y_test=train_test_split(iris.data,iris.target,test_size=0.25,random_state=None) # 標准化處理 std = StandardScaler() x_train = std.fit_transform(x_train) x_test = std.transform(x_test) knn = KNeighborsClassifier() # 構造一些參數的值進行搜索 param_grid = {"n_neighbors": [3, 5, 10]} # 進行網格搜索 gc = GridSearchCV(knn,param_grid=param_grid,cv=2)
GridSearchCV的第一個參數是估計器對象;param_grid是估計器參數;cv指幾折交叉驗證,這里使用2折
# 訓練模型 gc.fit(x_train,y_train) print("選擇最好的模型是:", gc.best_estimator_) print("在測試集上准確率:", gc.score(x_test, y_test))
輸出結果:
選擇最好的模型是: KNeighborsClassifier(algorithm='auto', leaf_size=30, metric='minkowski', metric_params=None, n_jobs=None, n_neighbors=5, p=2, weights='uniform') 在測試集上准確率: 0.9473684210526315
從輸出結果最好的模型可以看出,n_neighbors的值為5,模型最優。
總結,主要介紹了:
1、K-近鄰算法的思想及其中的距離運算;
2、模型調優:網格搜索與交叉驗證;