目錄
k-nearest neighbors (k-NN),k 近鄰法,用於分類和回歸。
KNN做回歸和分類的主要區別在於最後做預測時候的決策方式不同,KNN做分類預測時,一般是使用多數表決法;KNN做回歸時,一般是使用平均法,即最近的K個樣本的樣本輸出的平均值作為回歸預測值。本文以分類算法展開介紹。
k-近鄰法沒有顯示的學習過程,是一種lazy learning algorithm。
k-近鄰法的輸入:實例的特徵向量,對應於特徵空間的點,輸出:實例的類別。
k-近鄰法:利用訓練數據集對特徵向量空間進行劃分,並作為其分類的「模型」。分類時,對於新實例,根據其 k 個最近鄰的訓練實例的類別,通過多數表決等方式進行預測。
k-近鄰模型的三要素:k值的選擇、距離度量(作為"最鄰近"的衡量標準)、分類決策規則(例如」多數表決「)
knn算法可總結為3個步驟:
1.Choose the number of k and a distance metric.2.Find the k-nearest neighbors of the sample that we want to classify.3.Assign the class label by majority vote.2. k 近鄰法模型k近鄰法使用的模型,實際上對應於特徵空間的劃分。
模型三要素:k值的選擇、距離度量(作為"最鄰近"的衡量標準)、分類決策規則(例如」多數表決「)
2.1 k值的選擇k值的選擇會對k近鄰法的結果產生重大影響。應用中,k值一般去 較小 的數值,通常可使用 交叉驗證法 來取得最優的k值。
k值過小,近似誤差會減小,但估計誤差會增大。劃分粒度變細,模型越複雜,容易發生過擬合。對鄰近點非常敏感。k值過大,估計誤差減小,但近似誤差會增大,模型變得過於簡單(考慮極端情況k等於訓練樣本數,預測就只是簡單的為類別最多的那一類),與輸入實例相距較遠(不相似)的訓練實例也會對其產生影響。k 值的選擇反映了對近似誤差和估計誤差之間的權衡。
近似誤差,可以理解為對現有訓練集的訓練誤差。更關注於「訓練」。
估計誤差:可以理解為對測試集的測試誤差。更關注於「測試」、「泛化」。
2.2 距離度量特徵空間中2個實例點的距離,是2個實例點 相似程度 的反映。
不同的距離度量所確定的最近鄰點是不同的。
設特徵空間
2.3 分類決策規則多數表決法,多數表決規則等價於經驗風險最小化(經驗風險:模型關於訓練集的平均損失)。
3. k 近鄰法實現:kd(k-dimension)樹k近鄰法,主要考慮的問題:如何對訓練數據進行快速k近鄰搜索。尤其是特徵空間維數大以及訓練數據量大時,尤為重要。
簡單實現:線性掃描。需要計算輸入實例與每個訓練實例的距離。訓練集很大時,計算非常耗時,不可取。
kd樹實現,提高k鄰近搜索效率,以特殊的結構(例如kd tree,還有很多其他方法)存儲訓練數據,減少了計算距離的次數。
【注意】:kd 樹中的k 是指樣本特徵的維度,KNN中的k是指k個最近的樣本實例。
3.1 構造kd樹kd 樹是一種對 k 維空間的實例點進行存儲以便對其進行快速檢索的樹形數據結構。kd 樹是二叉樹,表示對 k 維空間的一個劃分。kd 樹的每個結點對應一個 k 維的超矩形區域。
通常,依次選擇坐標軸對空間切分(或者分別計算n個特徵的取值的方差,然後取方差最大的第k維特徵n_k對應的坐標軸來對空間進行切分(改進方法))。選擇切分點時 為訓練實例點在對應坐標軸上(投影)的中位數,這樣得到的kd 樹是平衡的。注意:平衡的kd 樹搜索時的效率未必是最優的。
kd 樹的本質其實就是 二叉搜索樹 。
構造平衡二叉樹3.2 搜索kd樹利用kd 樹,搜索可以限制在空間的局部區域上,可以省去對大部分數據點的搜索,從而減少搜索的計算量(主要是由於很多樣本點由於所在的超矩形區域和超球體不相交,根本不需要計算距離)。
搜索kd樹kd 樹搜索的平均計算複雜度是 O(logN),N為訓練實例數。kd 數適合於 N >> k 的情況,當 N ~ k 接近時,效率尋找下降,幾乎接近 線性掃描。
3.3 kd 樹預測kd樹的預測:在kd樹搜索最近鄰的基礎上,我們選擇到了第一個最近鄰樣本,就把它置為已選。在第二輪中,我們忽略置為已選的樣本,重新選擇最近鄰,這樣跑k次,就得到了目標的K個最近鄰,然後根據多數表決法,如果是KNN分類,預測為K個最近鄰裡面有最多類別數的類別。如果是KNN回歸,用K個最近鄰樣本輸出的平均值作為回歸預測值。
4. 代碼示例可用於分類和回歸任務,下面的示例:使用KNN完成鳶尾花分類任務。
引入包和加載數據:
from matplotlib import pyplot as plt
from matplotlib.colors import ListedColormap
from sklearn import datasets
from sklearn.model_selection import train_test_split
import numpy as np
from sklearn.neighbors import KNeighborsClassifier
iris = datasets.load_iris()
print(iris['data'].shape, iris['target'].shape) # (150, 4) (150,)
X = iris.data[:,[2,3]]
y = iris.target
print('Class labels:', np.unique(y))
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=1, stratify=y)
print(X_train.shape, y_train.shape)輸出:
(150, 4) (150,)
Class labels: [0 1 2]
(105, 2) (105,)繪製決策邊界函數:
# 訓練,並繪製分類決策邊界:
def plot_decision_regions(X, y, classifier, test_idx=None, resolution=0.02):
# setup marker generator and color map
markers = ('s', 'x', 'o', '^', 'v')
colors = ('red', 'blue', 'lightgreen', 'gray', 'cyan')
cmap = ListedColormap(colors[:len(np.unique(y))])
# plot the decision surface
x1_min, x1_max = X[:, 0].min() - 1, X[:, 0].max() + 1
x2_min, x2_max = X[:, 1].min() - 1, X[:, 1].max() + 1
xx1, xx2 = np.meshgrid(np.arange(x1_min, x1_max, resolution),
np.arange(x2_min, x2_max, resolution))
Z = classifier.predict(np.array([xx1.ravel(), xx2.ravel()]).T)
Z = Z.reshape(xx1.shape)
plt.contourf(xx1, xx2, Z, alpha=0.3, cmap=cmap)
plt.xlim(xx1.min(), xx1.max())
plt.ylim(xx2.min(), xx2.max())
for idx, cl in enumerate(np.unique(y)):
plt.scatter(x=X[y == cl, 0], y=X[y == cl, 1],
alpha=0.8, c=colors[idx],
marker=markers[idx], label=cl,
edgecolor='black')
# highlight test samples
if test_idx:
# plot all samples
X_test, y_test = X[test_idx, :], y[test_idx]
plt.scatter(X_test[:, 0], X_test[:, 1],
c='', edgecolor='black', alpha=1.0,
linewidth=1, marker='o',
s=100, label='test set')訓練:
# 標準化數據
from sklearn.preprocessing import StandardScaler
sc = StandardScaler()
sc.fit(X_train)
X_train_std = sc.transform(X_train)
X_test_std = sc.transform(X_test)
X_combined_std = np.vstack((X_train_std, X_test_std))
y_combined = np.hstack((y_train, y_test))
# 訓練,k=5, 距離度量為
knn = KNeighborsClassifier(n_neighbors=5, p=2, metric='minkowski')
knn.fit(X_train_std, y_train)
print('Training accuracy:', knn.score(X_train_std, y_train))
print('Testing accuracy:', knn.score(X_test_std, y_test))輸出:
Training accuracy: 0.9619047619047619
Testing accuracy: 1.0繪製決策邊界:
# 繪製決策邊界
plot_decision_regions(X_combined_std, y_combined, classifier=knn, test_idx=range(105,150))
plt.xlabel('petal length [standardized]')
plt.ylabel('petal width [standardized]')
plt.legend(loc='upper left')
plt.show()
分類決策邊界5. 模型評價模型評價參考自劉建平老師的K近鄰法(KNN)原理小結。
KNN簡單、直觀,其主要優點有:
1) 理論成熟,思想簡單,既可以用來做分類也可以用來做回歸3) 訓練時間複雜度比支持向量機之類的算法低,僅為O(n) (建樹的過程)4) 和樸素貝葉斯之類的算法比,對數據沒有假設,準確度高,對異常點不敏感5) 由於KNN方法主要靠周圍有限的鄰近的樣本,而不是靠判別類域的方法來確定所屬類別的,因此對於類域的交叉或重疊較多的待分樣本集來說,KNN方法較其他方法更為適合6)該算法比較適用於樣本容量比較大的類域的自動分類,而那些樣本容量較小的類域採用這種算法比較容易產生誤分KNN的主要缺點有:
4)使用懶散學習方法(a lazy learning algorithm),基本上不學習,導致預測時速度比起邏輯回歸之類的算法慢完整代碼地址完整代碼請移步至我的github:https://github.com/qingyujean/Magic-NLPer,求贊求星求鼓勵~~~
最後:如果本文中出現任何錯誤,請您一定要幫忙指正,感激~
參考[1] 統計學習方法(第2版) 李航
[2] K近鄰法(KNN)原理小結 劉建平https://www.cnblogs.com/pinard/p/6061661.html
[3] Python_Machine_Learning_2nd_Edition