K近鄰算法用作回歸的使用介紹(使用Python代碼)

介紹

在我遇到的所有機(jī)器學(xué)習(xí)算法中,KNN是最容易上手的。盡管它很簡單助琐,但事實(shí)上它其實(shí)在某些任務(wù)中非常有效(正如你將在本文中看到的那樣)。

甚至它可以做的更好面氓?它可以用于分類和回歸問題兵钮!然而,它其實(shí)更擅長用于分類問題舌界。我很少看到KNN在任何回歸任務(wù)上實(shí)現(xiàn)掘譬。 我在這里的目的是說明并強(qiáng)調(diào),當(dāng)目標(biāo)變量本質(zhì)上是連續(xù)的時(shí)呻拌,KNN是如何有效的運(yùn)作的屁药。

image

在本文中,我們將首先了解KNN算法背后的思維柏锄,研究計(jì)算點(diǎn)與點(diǎn)之間距離的不同方法,然后最終在Big Mart Sales數(shù)據(jù)集上用Python實(shí)現(xiàn)該算法复亏。讓我們動起來吧

學(xué)習(xí)Python中的小伙伴趾娃,需要學(xué)習(xí)資料的話,可以到我的微信公眾號:Python學(xué)習(xí)知識圈缔御,后臺回復(fù):“01”抬闷,即可拿Python學(xué)習(xí)資料


1.用簡單的例子來理解KNN背后的邏輯

讓我們從一個(gè)簡單的例子開始。請考慮下表 - 它包含10人的身高耕突,年齡和體重(目標(biāo))值笤成。如你所見,缺少ID11的重量值眷茁。我們需要根據(jù)他們的身高和年齡來預(yù)測這個(gè)人的體重炕泳。

注意:此表中的數(shù)據(jù)不代表實(shí)際值。它僅用作一個(gè)例子來解釋這個(gè)概念上祈。

image

為了更清楚地了解這一點(diǎn)培遵,下面是上表中高度與年齡的關(guān)系圖:

image

在上圖中,y軸表示人的身高(以英尺為單位)登刺,x軸表示年齡(以年為單位)籽腕。這些點(diǎn)是根據(jù)ID值進(jìn)行編號。黃點(diǎn)(ID 11)是我們的測試點(diǎn)纸俭。

如果我要求你根據(jù)圖來確定ID11的重量皇耗,你的答案會是什么?你可能會說揍很,因?yàn)镮D11 更接近第5點(diǎn)和第1點(diǎn)郎楼,所以它必須具有與這些ID類似的重量万伤,可能在72-77千克之間(表中ID1和ID5的權(quán)重)。這實(shí)際上是有道理的箭启,但你認(rèn)為算法會如何預(yù)測這些值呢壕翩?讓我們在下邊進(jìn)行試驗(yàn)討論。

2. KNN算法是怎樣工作的

如上所述傅寡,KNN可用于分類和回歸問題放妈。該算法使用“ 特征相似性 ”來預(yù)測任何新數(shù)據(jù)點(diǎn)的值。這意味著新的點(diǎn)將根據(jù)其與訓(xùn)練集中的點(diǎn)的接近程度而進(jìn)行分配荐操。從我們的例子中芜抒,我們知道ID11的高度和年齡類似于ID1和ID5,因此重量也大致相同托启。

如果這是一個(gè)分類問題宅倒,我們會采用該模式作為最終預(yù)測。在這種情況下屯耸,我們有兩個(gè)重量值--72和77.猜猜最終值是如何計(jì)算的拐迁?是取兩個(gè)重量的平均值來作為最終的預(yù)測值。

以下是該算法的逐步說明:

  1. 首先疗绣,計(jì)算新的點(diǎn)與每個(gè)訓(xùn)練點(diǎn)之間的距離线召。
image
  1. 選擇最接近的k個(gè)數(shù)據(jù)點(diǎn)(基于距離)。在我們演示的例子中多矮,如果k的值為3缓淹,則將選擇點(diǎn)1,5,6。我們將在本文后面進(jìn)一步探索選擇正確的k值的方法塔逃。
image
  1. 這些數(shù)據(jù)點(diǎn)的平均值是新點(diǎn)的最終預(yù)測值讯壶。在這里,我們的ID11的重量為 =(77 + 72 + 60)/ 3 = 69.66千克湾盗。

在接下來的幾節(jié)中伏蚊,我們將詳細(xì)討論這三個(gè)步驟中的每一個(gè)。

3.點(diǎn)與點(diǎn)之間距離的計(jì)算方法

所述 第一步驟 是計(jì)算新點(diǎn)和每個(gè)訓(xùn)練點(diǎn)之間的距離淹仑。計(jì)算該距離有多種方法丙挽,其中最常見的方法是 - 歐幾里德,曼哈頓(用于連續(xù))和漢明距離(用于分類)匀借。

  1. 歐幾里德距離: 歐幾里德距離計(jì)算為新點(diǎn)(x)和現(xiàn)有點(diǎn)(y)之間的差的平方和的平方根颜阐。
  2. 曼哈頓距離 :這是實(shí)際向量之間的距離,使用它們的絕對差值之和表示吓肋。
image
  1. 漢明距離 :用于分類變量凳怨。如果值(x)和值(y)相同,則距離D將等于0。否則D = 1肤舞。
image

一旦一個(gè)新的觀測值與我們訓(xùn)練集中的點(diǎn)之間的距離被測量出來紫新,下一步就是要選擇最近的點(diǎn)。要考慮的點(diǎn)的數(shù)量由k的值定義李剖。

4.如何選擇k因子

第二個(gè)步驟是選擇k值芒率。這決定了我們在為任何新的觀察值賦值時(shí)所要考慮到的鄰居的數(shù)量。

在我們的示例中篙顺,k值 = 3偶芍,最近的點(diǎn)是ID1,ID5和ID6德玫。

image
image

ID11的重量預(yù)測將是:

ID11 =(77 + 72 + 60)/ 3

ID11 = 69.66千克

如果k的值 = 5的話匪蟀,那么距離最近的點(diǎn)將是ID1,ID4宰僧,ID5材彪,ID6,ID10琴儿。

image
image

那么ID11的預(yù)測將是:

ID 11 =(77 + 59 + 72 + 60 + 58)/ 5

ID 11 = 65.2千克

我們注意到段化,基于k值,最終結(jié)果將趨于變化造成。那我們怎樣才能找出k的最優(yōu)值呢穗泵?讓我們根據(jù)我們的訓(xùn)練集和驗(yàn)證集的誤差計(jì)算來決定它(畢竟,最小化誤差是我們的最終目標(biāo)C瞻獭)。

請看下面的圖表现诀,了解不同k值的訓(xùn)練誤差和驗(yàn)證誤差夷磕。

image
image

對于非常低的k值(假設(shè)k = 1),模型過度擬合訓(xùn)練數(shù)據(jù)仔沿,這導(dǎo)致驗(yàn)證集上的高錯(cuò)誤率坐桩。另一方面,對于k的高值封锉,該模型在訓(xùn)練集和驗(yàn)證集上都表現(xiàn)不佳绵跷。如果仔細(xì)觀察,驗(yàn)證誤差曲線在k = 9的值處達(dá)到最小值成福。那么該k值就是是模型的最佳K值(對于不同的數(shù)據(jù)集碾局,它將有所不同)。該曲線稱為“ 肘形曲線 ”(因?yàn)樗哂蓄愃浦獠康男螤睿┡ǔS糜诖_定k值净当。

你還可以使用網(wǎng)格搜索技術(shù)來查找最佳k值。我們將在下一節(jié)中實(shí)現(xiàn)這一點(diǎn)。

5.處理數(shù)據(jù)集(Python代碼)

到目前為止像啼,你應(yīng)該清楚的了解這個(gè)算法俘闯。我們現(xiàn)在將繼續(xù)在數(shù)據(jù)集上實(shí)現(xiàn)該算法。我使用Big Mart銷售數(shù)據(jù)集來進(jìn)行代碼實(shí)現(xiàn)忽冻,你可以從此 鏈接 下載它真朗,邀請碼為b543。

1.閱讀文件

import pandas as pd

df = pd.read_csv('train.csv')

df.head()

2.計(jì)算缺失值

df.isnull().sum()

輸入Item_weight和Outlet_size中缺少的值

mean = df['Item_Weight'].mean() #imputing item_weight with mean

df['Item_Weight'].fillna(mean, inplace =True)

mode = df['Outlet_Size'].mode() #imputing outlet size with mode

df['Outlet_Size'].fillna(mode[0], inplace =True)

3.處理分類變量并刪除id列

df.drop(['Item_Identifier', 'Outlet_Identifier'], axis=1, inplace=True)

df = pd.get_dummies(df)

4.創(chuàng)建訓(xùn)練集和測試集

from sklearn.model_selection import train_test_split

train , test = train_test_split(df, test_size = 0.3)

x_train = train.drop('Item_Outlet_Sales', axis=1)

y_train = train['Item_Outlet_Sales']

x_test = test.drop('Item_Outlet_Sales', axis = 1)

y_test = test['Item_Outlet_Sales']

5.預(yù)處理 - 擴(kuò)展功能

from sklearn.preprocessing import MinMaxScaler

scaler = MinMaxScaler(feature_range=(0, 1))

x_train_scaled = scaler.fit_transform(x_train)

x_train = pd.DataFrame(x_train_scaled)

x_test_scaled = scaler.fit_transform(x_test)

x_test = pd.DataFrame(x_test_scaled)

6.查看不同K值的錯(cuò)誤率

導(dǎo)入所需要的包

from sklearn import neighbors

from sklearn.metrics import mean_squared_error

from math import sqrt

import matplotlib.pyplot as plt

%matplotlib inline

rmse_val = [] #存儲不同K值的RMSE值

for K in range(20):

K = K+1

model = neighbors.KNeighborsRegressor(n_neighbors = K)

model.fit(x_train, y_train) #合適的模型

pred=model.predict(x_test) #對測試集進(jìn)行測試

error = sqrt(mean_squared_error(y_test,pred)) #計(jì)算RMSE值

rmse_val.append(error) #存儲RMSE值

print('RMSE value for k= ' , K , 'is:', error)

輸出:

RMSE value for k = 1 is: 1579.8352322344945

RMSE value for k = 2 is: 1362.7748806138618

RMSE value for k = 3 is: 1278.868577489459

RMSE value for k = 4 is: 1249.338516122638

RMSE value for k = 5 is: 1235.4514224035129

RMSE value for k = 6 is: 1233.2711649472913

RMSE value for k = 7 is: 1219.0633086651026

RMSE value for k = 8 is: 1222.244674933665

RMSE value for k = 9 is: 1219.5895059285074

RMSE value for k = 10 is: 1225.106137547365

RMSE value for k = 11 is: 1229.540283771085

RMSE value for k = 12 is: 1239.1504407152086

RMSE value for k = 13 is: 1242.3726040709887

RMSE value for k = 14 is: 1251.505810196545

RMSE value for k = 15 is: 1253.190119191363

RMSE value for k = 16 is: 1258.802262564038

RMSE value for k = 17 is: 1260.884931441893

RMSE value for k = 18 is: 1265.5133661294733

RMSE value for k = 19 is: 1269.619416217394

RMSE value for k = 20 is: 1272.10881411344

根據(jù)K值繪制RMSE值

curve = pd.DataFrame(rmse_val) #elbow curve

curve.plot()

image

正如我們所討論的僧诚,當(dāng)我們?nèi) = 1時(shí)遮婶,我們得到一個(gè)非常高的RMSE值。隨著我們增加k值振诬,RMSE值不斷減小蹭睡。在k = 7時(shí),RMSE約為1219.06赶么,并且隨著K值在進(jìn)一步增加肩豁,RMSE值會迅速上升。我們可以有把握地說辫呻,在這種情況下清钥,k = 7會給我們帶來最好的結(jié)果。

這些是使用我們的訓(xùn)練數(shù)據(jù)集進(jìn)行的預(yù)測》殴耄現(xiàn)在讓我們預(yù)測測試數(shù)據(jù)集的值并進(jìn)行提交祟昭。

7.對測試數(shù)據(jù)集的預(yù)測

閱讀測試和提交文件

test = pd.read_csv('test.csv')

submission = pd.read_csv('SampleSubmission.csv')

submission['Item_Identifier'] = test['Item_Identifier']

submission['Outlet_Identifier'] = test['Outlet_Identifier']

預(yù)處理測試數(shù)據(jù)集

test.drop(['Item_Identifier', 'Outlet_Identifier'], axis=1, inplace=True)

test['Item_Weight'].fillna(mean, inplace =True)

test = pd.get_dummies(test)

test_scaled = scaler.fit_transform(test)

test = pd.DataFrame(test_scaled)

預(yù)測測試集并創(chuàng)建提交文件

predict = model.predict(test)

submission['Item_Outlet_Sales'] = predict

submission.to_csv('submit_file.csv',index=False)

在提交此文件后,我得到的RMSE為1279.5159651297怖侦。

8.實(shí)現(xiàn)GridsearchCV

為了確定k的值篡悟,每次繪制肘部曲線是一個(gè)繁瑣且繁瑣的過程。 你只需使用gridsearch即可簡單的找到最佳值匾寝。

from sklearn.model_selection import GridSearchCV

params = {'n_neighbors':[2,3,4,5,6,7,8,9]}

knn = neighbors.KNeighborsRegressor()

model = GridSearchCV(knn, params, cv=5)

model.fit(x_train,y_train)

model.best_params_

輸出:

{'n_neighbors': 7}

6.結(jié)束語和其他資源

在本文中搬葬,我們介紹了KNN算法的工作原理及其在Python中的實(shí)現(xiàn)。它是最基本但最有效的機(jī)器學(xué)習(xí)技術(shù)之一艳悔。并且在本文中急凰,我們是直接調(diào)用了Sklearn庫中的KNN模型,如果你想更仔細(xì)的研究一下KNN的話猜年,我建議你可以手敲一下有關(guān)KNN的源代碼抡锈。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市乔外,隨后出現(xiàn)的幾起案子床三,更是在濱河造成了極大的恐慌,老刑警劉巖杨幼,帶你破解...
    沈念sama閱讀 222,183評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件勿璃,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)补疑,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,850評論 3 399
  • 文/潘曉璐 我一進(jìn)店門歧沪,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人莲组,你說我怎么就攤上這事诊胞。” “怎么了锹杈?”我有些...
    開封第一講書人閱讀 168,766評論 0 361
  • 文/不壞的土叔 我叫張陵撵孤,是天一觀的道長。 經(jīng)常有香客問我竭望,道長邪码,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,854評論 1 299
  • 正文 為了忘掉前任咬清,我火速辦了婚禮闭专,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘旧烧。我一直安慰自己影钉,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,871評論 6 398
  • 文/花漫 我一把揭開白布掘剪。 她就那樣靜靜地躺著平委,像睡著了一般。 火紅的嫁衣襯著肌膚如雪夺谁。 梳的紋絲不亂的頭發(fā)上廉赔,一...
    開封第一講書人閱讀 52,457評論 1 311
  • 那天,我揣著相機(jī)與錄音匾鸥,去河邊找鬼昂勉。 笑死,一個(gè)胖子當(dāng)著我的面吹牛扫腺,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播村象,決...
    沈念sama閱讀 40,999評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼笆环,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了厚者?” 一聲冷哼從身側(cè)響起躁劣,我...
    開封第一講書人閱讀 39,914評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎库菲,沒想到半個(gè)月后账忘,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,465評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,543評論 3 342
  • 正文 我和宋清朗相戀三年鳖擒,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了溉浙。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,675評論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡蒋荚,死狀恐怖戳稽,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情期升,我是刑警寧澤惊奇,帶...
    沈念sama閱讀 36,354評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站播赁,受9級特大地震影響颂郎,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜容为,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,029評論 3 335
  • 文/蒙蒙 一乓序、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧舟奠,春花似錦竭缝、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,514評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至耿戚,卻和暖如春湿故,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背膜蛔。 一陣腳步聲響...
    開封第一講書人閱讀 33,616評論 1 274
  • 我被黑心中介騙來泰國打工坛猪, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人皂股。 一個(gè)月前我還...
    沈念sama閱讀 49,091評論 3 378
  • 正文 我出身青樓墅茉,卻偏偏與公主長得像,于是被迫代替她去往敵國和親呜呐。 傳聞我的和親對象是個(gè)殘疾皇子就斤,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,685評論 2 360

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