[TOC] 更新、更全的《機器學習》的更新網站,更有python、go、數據結構與算法、爬蟲、人工智能教學等着你:http://www.javashuo.com/article/p-vozphyqp-cm.htmlhtml
k近鄰算法(k-nearest neighbors,KNN)是一種基本的分類和迴歸方法,本文只探討分類問題中的k近鄰算法,迴歸問題一般是得出最近的$k$個實例的標記值,而後取這$k$實例標記值的平均數或中位數。python
k近鄰算法常常被人們應用於生活當中,好比傅玄曾說過「近朱者赤近墨者黑」,還有人曾說過「若是要判斷一我的的品性,只須要看看他身邊朋友的品性便可」,這些都是用了k近鄰算法的思想。算法
本文主要介紹k近鄰算法的基本理論以及k近鄰的擴展——限定半徑最近鄰算法和最近質心算法,以後會使用k近鄰算法對鳶尾花數據進行分類,並講解scikit-learn庫中k近鄰算法各個參數的使用。爲了解決k近鄰算法須要大量計算的問題在這以後會講解kd樹(KDTree)。數據結構
不知道同窗們在看電影的時候有沒有思考過你是如何判斷一部電影是愛情片仍是動做片的,你能夠停下來想一想這個問題再往下看看個人想法。機器學習
我說說我是如何判斷一部電影是愛情片仍是動做片的,首先絕對不是靠那些預告片,畢竟預告片過短了,愛情片的預告多是動做片,動做片的預告多是愛情片也說不定。學習
相比較預告片我用了一個很愚蠢很繁瑣但頗有效的方法。首先我用一部電影的接吻鏡頭的次數做爲$x$軸,打鬥的場景次數做爲$y$軸生成了一個二維空間,即平面圖,以下圖所示。(注:如下電影的接吻鏡頭次數和打鬥場景次數都是假設的)測試
# k近鄰算法引入圖例 import matplotlib.pyplot as plt from matplotlib.font_manager import FontProperties %matplotlib inline font = FontProperties(fname='/Library/Fonts/Heiti.ttc') # 動做片 plt.scatter(2, 10, marker='o', c='r', s=50) plt.text(2, 9, s='《戰狼2》(2,10)', fontproperties=font, ha='center') plt.scatter(4, 12, marker='o', c='r', s=50) plt.text(4, 11, s='《復仇者聯盟2》(4,12)', fontproperties=font, ha='center') plt.scatter(2, 15, marker='o', c='r', s=50) plt.text(2, 14, s='《猩球崛起》(2,15)', fontproperties=font, ha='center') # 愛情片 plt.scatter(10, 4, marker='x', c='g', s=50) plt.text(10, 3, s='《泰坦尼克號》(10,4)', fontproperties=font, ha='center') plt.scatter(12, 2, marker='x', c='g', s=50) plt.text(12, 1, s='《致咱們終將逝去的青春》(12,2)', fontproperties=font, ha='center') plt.scatter(15, 5, marker='x', c='g', s=50) plt.text(15, 4, s='《誰的青春不迷茫》(15,5)', fontproperties=font, ha='center') # 測試點 plt.scatter(5, 6, marker='s', c='k', s=50) plt.text(5, 5, s='《未知類型的電影》(5,6)', fontproperties=font, ha='center') plt.xlim(0, 18) plt.ylim(0, 18) plt.xlabel('接吻鏡頭(次)', fontproperties=font) plt.ylabel('打鬥場景(次)', fontproperties=font) plt.title('k近鄰算法引入圖例', fontproperties=font, fontsize=20) plt.show()
網站
經過上圖咱們能夠發現動做片《戰狼2》的打鬥場景次數明顯多於接吻鏡頭,而愛情片《泰坦尼克號》的接吻鏡頭明顯多於打鬥場景,而且其餘的動做片和愛情片都有這樣的規律,所以我作了一個總結:愛情片的接吻鏡頭次數會明顯比打鬥的場景次數多,而動做片反之。人工智能
經過上述的總結,若是我再去看一部新電影的時候,我會在內心默數這部電影的接吻鏡頭的次數和打鬥場景,而後再去判斷。這種方法看起來無懈可擊,可是若是碰到了上述黑點《未知類型的電影》所在的位置,即當接吻鏡頭次數和打鬥場景次數差很少的時候,每每很難判斷它是愛情片仍是動做片。spa
這個時候咱們的主角k近鄰算法就應該出場了,由於使用k近鄰算法能夠很好的解決《未知類型的電影》這種尷尬的情形。
上述整個過程其實就是k近鄰算法實現的一個過程,接下來將從理論層面抽象的講解k近鄰算法。
k近鄰算法簡而言之就是給定一個有$m$個實例的數據集$T={(x_1,y_1),(x_2,y_2),\cdots,(x_m,y_m)}$,計算出將來新樣本到每一個實例的距離,而後找到與將來新數據最近的$k$個實例,這$k$個實例哪一個類別的實例多,則將來新樣本屬於哪一個類別,基於這個解釋能夠給出k近鄰算法的三個基本要素。
k近鄰算法的三個基本要素分別是$k$值的選擇、距離度量的方式和分類決策的規則,只要這三點肯定了,則k近鄰算法也就肯定了。
k近鄰算法對於$k$值的選擇,通常沒有一個固定的選擇,對於不一樣的問題一般可能有不一樣的$k$值。可是須要注意的是若是$k$值取的越大,則離將來新樣本的實例會愈來愈多,即較遠的實例也會對結果形成影響,從而使得模型欠擬合,可是模型會變得簡單;反之只有較少的實例會對結果形成影響,模型會變得複雜,同時會使得模型容易發生過擬合現象。而且須要注意的是$k$值通常小於20。
例如當$k$值取$m$的時候,模型會簡單到不管將來新樣本輸入什麼,預測結果都是訓練集中實例最多的類。
當$k=1$的時候,稱爲最近鄰算法,即對於將來新樣本,最近鄰算法將訓練集中與將來新樣本最鄰近點的類別做爲將來新樣本的類別。
k近鄰算法對於距離度量的方式,有不少種方法能夠選擇,通常選擇咱們電影分類例子中講到的歐幾里得距離,也稱做歐氏距離。同時還可能會使用曼哈頓距離或閔可夫斯基距離,這裏統一給出它們的公式。
假設$n$維空間中有兩個點$x_i$和$x_j$,其中$x_i = (x_i^{(1)},x_i^{(2)},\cdots,x_i^{(n)})$,\(x_j = (x_j^{(1)},x_j^{(2)},\cdots,x_j^{(n)})\)。
歐氏距離爲
曼哈頓距離爲
閔可夫斯基距離爲
其中曼哈頓距離是閔可夫斯基距離$p=2$時的特例,而歐氏距離是閔可夫斯基距離$p=1$時的特例。
k近鄰算法對於分類決策規則,通常選擇電影分類例子中講到的多數表決法,即$k$個實例中擁有最多實例的類別即爲將來新樣本的類別。例如假設獲得距離《未知類型的電影》最近的$10$部電影中,有$3$部屬於$c_1$類;有$3$部屬於$c_2$類;有$4$部是$c_3$類,則能夠判斷《未知類型的電影》屬於$c_3$類。
值得注意的是使用k近鄰算法解決迴歸問題時,分類決策的規則一般是對$k$個實例的標記值取平均值或中位數。例如距離將來新樣本的最近的$3$個實例的標記值分別爲${2.3,2.7,1.0}\(,則能夠獲得將來新樣本的標記值爲\){\frac{2.3+2.7+1.0}{3}}=2$。
維數詛咒的意思是:當訓練集特徵維度愈來愈大的時候,特徵空間愈來愈稀疏,經過距離度量的方式能夠發現即便是最近的鄰居在高維空間的距離也很遠,以致於很難估計樣本之間的距離。
通常狀況下可使用特徵選擇和降維等方法避免維數詛咒。
限定半徑k近鄰算法顧名思義就是限定一個距離範圍搜索$k$個近鄰,經過限定距離範圍能夠解決數據集中實例太少甚至少於$k$的問題,這樣就不會把距離目標點較遠的實例也劃入$k$個實例當中。
最近質心算法是將全部實例按照類別歸類,歸類後對$c_k$類的全部實例的$n$維特徵的每一維特徵求平均值,而後由每一維特徵的平均值造成一個質心點,對於樣本中的全部類別都會對應得到一個質心點。
每當將來新樣本被輸入時,則計算將來新樣本到每個類別對應質心點的距離,距離最近的則爲該將來新樣本的類別。
有$m$個實例$n$維特徵的數據集
其中$x_i$是實例的特徵向量即$({(1)},{(2)},\cdots,^{(n)})$,$y_i$是實例的類別,數據集有${c_1,c_2,\cdots,c_j}$共$j$個類別。
將來新樣本$(x_i,y_i), \quad (i=1,2,\cdots,m)$的類別$c_l, \quad (l=1,2,\cdots,j)$。
除了咱們講的第一個古老的機器學習算法感知機,k近鄰算法應該是目前工業上還會使用最爲簡單的算法,而且使用起來也很簡單、方便,可是有個前提是數據量不能過大,更不能使用有維數詛咒的數據集。
k近鄰遇到數據量大的數據集計算量是一個很難解決的問題,那麼有沒有什麼好的方法能稍微減輕這個問題呢?有是必定有的,即下一篇——kd樹。