分類算法之K最近鄰算法(KNN)的python實現(xiàn)

分類算法之K最近鄰算法(KNN)的Python實現(xiàn)

KNN的定義

所謂K近鄰算法,即是給定一個訓練數(shù)據(jù)集轮蜕,對新的輸入實例昨悼,在訓練數(shù)據(jù)集中找到與該實例最鄰近的K個實例,這K個實例的多數(shù)屬于某個類肠虽,就把該輸入實例分類到這個類中幔戏。

介紹

如下圖所示,有兩類不同的樣本數(shù)據(jù)税课,分別用藍色的小正方形和紅色的小三角形表示闲延,而圖正中間的那個綠色的圓所標示的數(shù)據(jù)則是待分類的數(shù)據(jù)。也就是說韩玩,現(xiàn)在垒玲, 我們不知道中間那個綠色的數(shù)據(jù)是從屬于哪一類(藍色小正方形or紅色小三角形),下面找颓,我們就要解決這個問題:給這個綠色的圓分類合愈。

shili

我們常說,物以類聚,人以群分佛析,判別一個人是一個什么樣品質(zhì)特征的人益老,常常可以從他/她身邊的朋友入手寸莫,所謂觀其友捺萌,而識其人。我們不是要判別上圖中那個綠色的圓是屬于哪一類數(shù)據(jù)么膘茎,好說桃纯,從它的鄰居下手。但一次性看多少個鄰居呢披坏?從上圖中态坦,你還能看到:

  • 如果K=3,綠色圓點的最近的3個鄰居是2個紅色小三角形和1個藍色小正方形棒拂,少數(shù)從屬于多數(shù)伞梯,基于統(tǒng)計的方法,判定綠色的這個待分類點屬于紅色的三角形一類着茸。

  • 如果K=5壮锻,綠色圓點的最近的5個鄰居是2個紅色三角形和3個藍色的正方形,還是少數(shù)從屬于多數(shù)涮阔,基于統(tǒng)計的方法猜绣,判定綠色的這個待分類點屬于藍色的正方形一類。

于此我們看到敬特,當無法判定當前待分類點是從屬于已知分類中的哪一類時掰邢,我們可以依據(jù)統(tǒng)計學的理論看它所處的位置特征,衡量它周圍鄰居的權(quán)重伟阔,而把它歸為(或分配)到權(quán)重更大的那一類辣之。這就是K近鄰算法的核心思想。

KNN 算法本身簡單有效皱炉,它是一種 lazy-learning 算法怀估,分類器不需要使用訓練集進行訓練,訓練時間復雜度為0合搅。KNN 分類的計算復雜度和訓練集中的文檔數(shù)目成正比多搀,也就是說,如果訓練集中文檔總數(shù)為 n灾部,那么 KNN 的分類時間復雜度為O(n)康铭。

K 近鄰算法使用的模型實際上對應于對特征空間的劃分。K 值的選擇赌髓,距離度量和分類決策是該算法的三個基本要素:

  1. K 值的選擇會對算法的結(jié)果產(chǎn)生重大影響从藤。K值較小意味著只有與輸入實例較近的訓練實例才會對預測結(jié)果起作用催跪,但容易發(fā)生過擬合;如果 K 值較大夷野,優(yōu)點是可以減少學習的估計誤差懊蒸,但缺點是學習的近似誤差增大,這時與輸入實例較遠的訓練實例也會對預測起作用悯搔,使預測發(fā)生錯誤榛鼎。在實際應用中,K 值一般選擇一個較小的數(shù)值鳖孤,通常采用交叉驗證的方法來選擇最優(yōu)的 K 值。隨著訓練實例數(shù)目趨向于無窮和 K=1 時抡笼,誤差率不會超過貝葉斯誤差率的2倍苏揣,如果K也趨向于無窮,則誤差率趨向于貝葉斯誤差率推姻。

  2. 該算法中的分類決策規(guī)則往往是多數(shù)表決平匈,即由輸入實例的 K 個最臨近的訓練實例中的多數(shù)類決定輸入實例的類別。

  3. 距離度量一般采用 Lp 距離藏古,當p=2時增炭,即為歐氏距離,在度量之前拧晕,應該將每個屬性的值規(guī)范化隙姿,這樣有助于防止具有較大初始值域的屬性比具有較小初始值域的屬性的權(quán)重過大。

在KNN中厂捞,通過計算對象間距離來作為各個對象之間的非相似性指標输玷,避免了對象之間的匹配問題,在這里距離一般使用歐氏距離或曼哈頓距離(其中x,y為2個樣本靡馁,n為維度欲鹏,x(k),y(k)為x,y第k個維度上的特征值臭墨。):

juli

算法描述

計算步驟:

  1. 算距離:給定測試對象赔嚎,計算它與訓練集中的每個對象的距離
  2. 找鄰居:圈定距離最近的k個訓練對象,作為測試對象的近鄰
  3. 做分類:根據(jù)這k個近鄰歸屬的主要類別胧弛,來對測試對象分類

算法實現(xiàn)(python)

#coding:utf-8
import numpy

def classify(inX,dataSet,labels,k):
    """
    :param inX: example
    :param dataSet:  dataSet 2D List
    :param labels:  1D List
    :param k the number of neighbor
    :return: The label of the example as classify result.
    """
    if len(dataSet) != len(labels):
        raise ValueError("DataSet or labels was too less!"
                     "The length of DataSet is %s"
                     "But the length of labels is %s"%(len(dataSet),len(labels)))

    dArrays = numpy.array(dataSet)
    inArray = numpy.array(inX)
    result = (((dArrays-inArray)**2).sum(axis=1))**0.5
    index_list = result.argsort() #argsort函數(shù)返回的是數(shù)組值從小到大的索引值
    classCount = dict()
    for i in range(k):
        label = labels[index_list[i]]
        classCount[label] = classCount.get(label,0) + 1
    return sorted(classCount,key=lambda x:classCount[x],reverse=True)[0]

案例演示

電影分類數(shù)據(jù)集:

電影名稱 搞笑鏡頭 kiss鏡頭 打斗鏡頭 標簽
美人魚 45 2 9 喜劇片
功夫熊貓3 39 0 31 喜劇片
諜影重重 5 2 57 動作片
葉問3 3 2 65 動作片
怦然心動 7 46 4 愛情片
泰坦尼克號 9 39 8 愛情片
  1. 我們構(gòu)建一個已分好類的數(shù)據(jù)集

     movie_data = {"美人魚":[45,2,9,"喜劇片"],
    
                     "功夫熊貓3":[39,0,1,"喜劇片"],
    
                     "諜影重重":[5,2,57,"動作片"],
    
                     "葉問3":[3,2,65,"動作片"],
    
                     "怦然心動":[7,46,4,"愛情片"],
    
                     "泰坦尼克號":[9,39,8,"愛情片"]}
    
  2. 計算一個新樣本與數(shù)據(jù)集中所有數(shù)據(jù)的距離

    這里的新樣本就是:"唐人街探案": [23, 3, 17, "尤误?"]。使用歐氏距離來計算叶圃。

    x為:"唐人街探案": [23, 3, 17, "袄膏?"],y為:"諜影重重": [5, 2, 57, "動作片"]掺冠,則兩者之間的距離為:

    d = ((23-5)**2+(3-2)**2+(17-57)**2)**0.5

    代碼實現(xiàn):

     x = [23, 3, 17]  
     KNN = []  
     for k,v in movie_data.items():  
         d = math.sqrt((x[0] - v[0]) ** 2 + (x[1] - v[1]) ** 2 + (x[2] - v[2]) ** 2)  
         KNN.append([k,round(d,2)])  #round為取精度沉馆,兩位小數(shù)码党。
     return KNN
     #output
     [["葉問3",52.01],["功夫熊貓3",22.83],["泰坦尼克號",39.66],["美人魚",23.43],["諜影重重",43.87],["怦然心動",47.69]]
    
  3. 按照距離大小進行遞增排序

     KNN.sort(key=lambda dis: dis[1])
     #output
     [["功夫熊貓3",22.83],["美人魚",23.43],["泰坦尼克號",39.66],["諜影重重",43.87],["怦然心動",47.69],["葉問3",52.01]]
    
  4. 選取距離最小的k個樣本
    KNN=KNN[:3] #取前3個,K=3
    #output
    [["功夫熊貓3",22.83],["美人魚",23.43],["泰坦尼克號",39.66]]

  5. 確定前k個樣本所在類別出現(xiàn)的頻率斥黑,并輸出出現(xiàn)頻率最高的類別

     labels = {"喜劇片":0,"動作片":0,"愛情片":0}  
     for s in KNN:  
         label = movie_data[s[0]]  
         labels[label[3]] += 1  
     labels =sorted(labels.items(),key=lambda l: l[1],reverse=True)  
     return labels
     #output
     {"喜劇片":2,"愛情片":1,"動作片":0} 
     所以可以把"唐人街探案"這部電影打上喜劇片的標簽
    

算法評估

  1. KNN算法不僅可以用于分類揖盘,還可以用于回歸。通過找出一個樣本的k個最近鄰居锌奴,將這些鄰居的屬性的平均值賦給該樣本兽狭,就可以得到該樣本的屬性。
  2. 該算法在分類時有個主要的不足是鹿蜀,當樣本不平衡時箕慧,如一個類的樣本容量很大,而其他類樣本容量很小時茴恰,有可能導致當輸入一個新樣本時颠焦,該樣本的K個鄰居中大容量類的樣本占多數(shù)。 該算法只計算“最近的”鄰居樣本往枣,某一類的樣本數(shù)量很大伐庭,那么或者這類樣本并不接近目標樣本,或者這類樣本很靠近目標樣本分冈。無論怎樣圾另,數(shù)量并不能影響運行結(jié)果〉癯粒可以采用權(quán)值的方法(和該樣本距離小的鄰居權(quán)值大)來改進集乔。
  3. 該方法的另一個不足之處是計算量較大,因為對每一個待分類的文本都要計算它到全體已知樣本的距離蘑秽,才能求得它的K個最近鄰點饺著。目前常用的解決方法是事先對已知樣本點進行剪輯,事先去除對分類作用不大的樣本肠牲。該算法比較適用于樣本容量比較大的類域的自動分類幼衰,而那些樣本容量較小的類域采用這種算法比較容易產(chǎn)生誤分。

行業(yè)應用

字符識別缀雳、文本分類渡嚣、圖像識別

客戶流失預測、欺詐偵測等(更適合于稀有事件的分類問題)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末肥印,一起剝皮案震驚了整個濱河市识椰,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌深碱,老刑警劉巖腹鹉,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異敷硅,居然都是意外死亡功咒,警方通過查閱死者的電腦和手機愉阎,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來力奋,“玉大人榜旦,你說我怎么就攤上這事【耙螅” “怎么了溅呢?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀的道長猿挚。 經(jīng)常有香客問我咐旧,道長,這世上最難降的妖魔是什么绩蜻? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任休偶,我火速辦了婚禮,結(jié)果婚禮上辜羊,老公的妹妹穿的比我還像新娘。我一直安慰自己词顾,他們只是感情好八秃,可當我...
    茶點故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著肉盹,像睡著了一般昔驱。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上上忍,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天骤肛,我揣著相機與錄音,去河邊找鬼窍蓝。 笑死腋颠,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的吓笙。 我是一名探鬼主播淑玫,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼面睛!你這毒婦竟也來了絮蒿?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤叁鉴,失蹤者是張志新(化名)和其女友劉穎土涝,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體幌墓,經(jīng)...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡但壮,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年冀泻,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片茵肃。...
    茶點故事閱讀 38,018評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡腔长,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出验残,到底是詐尸還是另有隱情捞附,我是刑警寧澤,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布您没,位于F島的核電站鸟召,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏氨鹏。R本人自食惡果不足惜欧募,卻給世界環(huán)境...
    茶點故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望仆抵。 院中可真熱鬧跟继,春花似錦、人聲如沸镣丑。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽莺匠。三九已至金吗,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間趣竣,已是汗流浹背摇庙。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留遥缕,地道東北人卫袒。 一個月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓,卻偏偏與公主長得像单匣,于是被迫代替她去往敵國和親玛臂。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,762評論 2 345

推薦閱讀更多精彩內(nèi)容