Task03-K近鄰(k-nearest neighbors)-算法實踐(天池機器學習訓練營D9)

本筆記為參加阿里云“天池龍珠計劃 機器學習訓練營”所做的學習記錄贼陶,代碼及知識內(nèi)容均來源于訓練營刃泡,本人稍作擴充。
具體活動內(nèi)容請移步阿里云天池龍珠計劃碉怔。

2.4.3 模擬數(shù)據(jù)集--kNN回歸

Step1: 庫函數(shù)導入

#Demo來自sklearn官網(wǎng)
import numpy as np
import matplotlib.pyplot as plt
from sklearn.neighbors import KNeighborsRegressor

Step2: 數(shù)據(jù)導入&分析

np.random.seed(0)
# 隨機生成40個(0, 1)之前的數(shù)烘贴,乘以5,再進行升序
X = np.sort(5 * np.random.rand(40, 1), axis=0)
# 創(chuàng)建[0, 5]之間的500個數(shù)的等差數(shù)列, 作為測試數(shù)據(jù)
T = np.linspace(0, 5, 500)[:, np.newaxis]
# 使用sin函數(shù)得到y(tǒng)值撮胧,并拉伸到一維
y = np.sin(X).ravel()
# Add noise to targets[y值增加噪聲]
y[::5] += 1 * (0.5 - np.random.rand(8))

Step3: 模型訓練&預測可視化

# Fit regression model
# 設置多個k近鄰進行比較
n_neighbors = [1, 3, 5, 8, 10, 40]
# 設置圖片大小
plt.figure(figsize=(10,20))
for i, k in enumerate(n_neighbors):
    # 默認使用加權平均進行計算predictor
    clf = KNeighborsRegressor(n_neighbors=k, p=2, metric="minkowski")
    # 訓練
    clf.fit(X, y)
    # 預測
    y_ = clf.predict(T)
    plt.subplot(6, 1, i + 1)
    plt.scatter(X, y, color='red', label='data')
    plt.plot(T, y_, color='navy', label='prediction')
    plt.axis('tight')
    plt.legend()
    plt.title("KNeighborsRegressor (k = %i)" % (k))

plt.tight_layout()
plt.show()
knnfigA.jpg

Step4:模型分析

當k=1時桨踪,預測的結(jié)果只和最近的一個訓練樣本相關,從預測曲線中可以看出當k很小時候很容易發(fā)生過擬合芹啥。
當k=40時锻离,預測的結(jié)果和最近的40個樣本相關,因為我們只有40個樣本墓怀,此時是所有樣本的平均值汽纠,此時所有預測值都是均值,很容易發(fā)生欠擬合傀履。
一般情況下虱朵,使用knn的時候,根據(jù)數(shù)據(jù)規(guī)模我們會從[3, 20]之間進行嘗試,選擇最好的k碴犬,例如上圖中的[3, 10]相對1和40都是還不錯的選擇絮宁。

2.4.4 馬絞痛數(shù)據(jù)--kNN數(shù)據(jù)預處理+kNN分類pipeline
# 下載需要用到的數(shù)據(jù)集
!wget https://tianchi-media.oss-cn-beijing.aliyuncs.com/DSW/3K/horse-colic.csv

# 下載數(shù)據(jù)集介紹
!wget https://tianchi-media.oss-cn-beijing.aliyuncs.com/DSW/3K/horse-colic.names

Step1: 庫函數(shù)導入

import numpy as np
import pandas as pd
# kNN分類器
from sklearn.neighbors import KNeighborsClassifier
# kNN數(shù)據(jù)空值填充
from sklearn.impute import KNNImputer
# 計算帶有空值的歐式距離
from sklearn.metrics.pairwise import nan_euclidean_distances
# 交叉驗證
from sklearn.model_selection import cross_val_score
# KFlod的函數(shù)
from sklearn.model_selection import RepeatedStratifiedKFold
from sklearn.pipeline import Pipeline
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split

Step2: 數(shù)據(jù)導入&分析

2,1,530101,38.50,66,28,3,3,?,2,5,4,4,?,?,?,3,5,45.00,8.40,?,?,2,2,11300,00000,00000,2
1,1,534817,39.2,88,20,?,?,4,1,3,4,2,?,?,?,4,2,50,85,2,2,3,2,02208,00000,00000,2
2,1,530334,38.30,40,24,1,1,3,1,3,3,1,?,?,?,1,1,33.00,6.70,?,?,1,2,00000,00000,00000,1
1,9,5290409,39.10,164,84,4,1,6,2,2,4,4,1,2,5.00,3,?,48.00,7.20,3,5.30,2,1,02208,00000,00000,1
2,1,530255,37.30,104,35,?,?,6,2,?,?,?,?,?,?,?,?,74.00,7.40,?,?,2,2,04300,00000,00000,2
......

數(shù)據(jù)集介紹:horse-colic.names
數(shù)據(jù)中的'?'表示空值,如果我們使用KNN分類器翅敌,'?'不能數(shù)值羞福,不能進行計算惕蹄,因此我們需要進行數(shù)據(jù)預處理對空值進行填充蚯涮。
這里我們使用KNNImputer進行空值填充,KNNImputer填充的原來很簡單卖陵,計算每個樣本最近的k個樣本遭顶,進行空值填充。
我們先來看下KNNImputer的運行原理:

Step3: KNNImputer空值填充--使用和原理介紹

X = [[1, 2, np.nan], [3, 4, 3], [np.nan, 6, 5], [8, 8, 7]]
imputer = KNNImputer(n_neighbors=2, metric='nan_euclidean')
imputer.fit_transform(X)

# Output:
# array([[1. , 2. , 4. ],
#        [3. , 4. , 3. ],
#        [5.5, 6. , 5. ],
#        [8. , 8. , 7. ]])

帶有空值的歐式距離計算公式:

nan_euclidean_distances([[np.nan, 6, 5], [3, 4, 3]], [[3, 4, 3], [1, 2, np.nan], [8, 8, 7]])

# Output:
# array([[3.46410162, 6.92820323, 3.46410162],
#        [0.        , 3.46410162, 7.54983444]])

Step4: KNNImputer空值填充--歐式距離的計算
樣本[1, 2, np.nan] 最近的2個樣本是: [3, 4, 3] [np.nan, 6, 5], 計算距離的時候使用歐式距離泪蔫,只關注非空樣本棒旗。 [1, 2, np.nan] 填充之后得到 [1, 2, (3 + 5) / 2] = [1, 2, 4]

正常的歐式距離:


knnfigB.jpg

帶有空值的歐式聚類:


knnfigC.jpg

只計算所有非空的值,對所有空加權到非空值的計算上撩荣,上例中铣揉,我們看到一個有3維,只有第二維全部非空餐曹, 將第一維和第三維的計算加到第二維上逛拱,所有需要乘以3。

表格中距離度量使用的是帶有空值歐式距離計算相似度台猴,使用簡單的加權平均進行填充朽合。


knnfigD.jpg
# load dataset, 將?變成空值
input_file = './horse-colic.csv'
df_data = pd.read_csv(input_file, header=None, na_values='?')

# 得到訓練數(shù)據(jù)和label, 第23列表示是否發(fā)生病變, 1: 表示Yes; 2: 表示No. 
data = df_data.values
ix = [i for i in range(data.shape[1]) if i != 23]
X, y = data[:, ix], data[:, 23]

# 查看所有特征的缺失值個數(shù)和缺失率
for i in range(df_data.shape[1]):
    n_miss = df_data[[i]].isnull().sum()
    perc = n_miss / df_data.shape[0] * 100
    if n_miss.values[0] > 0:
        print('>Feat: %d, Missing: %d, Missing ratio: (%.2f%%)' % (i, n_miss, perc))

# 查看總的空值個數(shù)
print('KNNImputer before Missing: %d' % sum(np.isnan(X).flatten()))
# 定義 knnimputer
imputer = KNNImputer()
# 填充數(shù)據(jù)集中的空值
imputer.fit(X)
# 轉(zhuǎn)換數(shù)據(jù)集
Xtrans = imputer.transform(X)
# 打印轉(zhuǎn)化后的數(shù)據(jù)集的空值
print('KNNImputer after Missing: %d' % sum(np.isnan(Xtrans).flatten()))

# Output:
# >Feat: 0, Missing: 1, Missing ratio: (0.33%)
# >Feat: 3, Missing: 60, Missing ratio: (20.00%)
# >Feat: 4, Missing: 24, Missing ratio: (8.00%)
# >Feat: 5, Missing: 58, Missing ratio: (19.33%)
# >Feat: 6, Missing: 56, Missing ratio: (18.67%)
# >Feat: 7, Missing: 69, Missing ratio: (23.00%)
# >Feat: 8, Missing: 47, Missing ratio: (15.67%)
# >Feat: 9, Missing: 32, Missing ratio: (10.67%)
# >Feat: 10, Missing: 55, Missing ratio: (18.33%)
# >Feat: 11, Missing: 44, Missing ratio: (14.67%)
# >Feat: 12, Missing: 56, Missing ratio: (18.67%)
# >Feat: 13, Missing: 104, Missing ratio: (34.67%)
# >Feat: 14, Missing: 106, Missing ratio: (35.33%)
# >Feat: 15, Missing: 247, Missing ratio: (82.33%)
# >Feat: 16, Missing: 102, Missing ratio: (34.00%)
# >Feat: 17, Missing: 118, Missing ratio: (39.33%)
# >Feat: 18, Missing: 29, Missing ratio: (9.67%)
# >Feat: 19, Missing: 33, Missing ratio: (11.00%)
# >Feat: 20, Missing: 165, Missing ratio: (55.00%)
# >Feat: 21, Missing: 198, Missing ratio: (66.00%)
# >Feat: 22, Missing: 1, Missing ratio: (0.33%)
# KNNImputer before Missing: 1605
# KNNImputer after Missing: 0

Step5: 基于pipeline模型訓練&可視化

什么是Pipeline, 我這里直接翻譯成數(shù)據(jù)管道。任何有序的操作有可以看做pipeline饱狂,例如工廠流水線曹步,對于機器學習模型來說,這就是數(shù)據(jù)流水線休讳。 是指數(shù)據(jù)通過管道中的每一個節(jié)點讲婚,結(jié)果除了之后,繼續(xù)流向下游俊柔。對于我們這個例子筹麸,數(shù)據(jù)是有空值,我們會有一個KNNImputer節(jié)點用來填充空值婆咸, 之后繼續(xù)流向下一個kNN分類節(jié)點竹捉,最后輸出模型。

knnfigE.jpg
results = list()
strategies = [str(i) for i in [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 16, 18, 20, 21]]
for s in strategies:
    # create the modeling pipeline
    pipe = Pipeline(steps=[('imputer', KNNImputer(n_neighbors=int(s))), ('model', KNeighborsClassifier())])
    # 數(shù)據(jù)多次隨機劃分取平均得分
    scores = []
    for k in range(20):
        # 得到訓練集合和驗證集合, 8: 2
        X_train, X_test, y_train, y_test = train_test_split(Xtrans, y, test_size=0.2)
        pipe.fit(X_train, y_train)
        # 驗證model
        score = pipe.score(X_test, y_test)
        scores.append(score)
    # 保存results
    results.append(np.array(scores))
    print('>k: %s, Acc Mean: %.3f, Std: %.3f' % (s, np.mean(scores), np.std(scores)))
# print(results)
# plot model performance for comparison
plt.boxplot(results, labels=strategies, showmeans=True)
plt.show()

# Output:
# >k: 1, Acc Mean: 0.800, Std: 0.031
# >k: 2, Acc Mean: 0.821, Std: 0.041
# >k: 3, Acc Mean: 0.833, Std: 0.053
# >k: 4, Acc Mean: 0.824, Std: 0.037
# >k: 5, Acc Mean: 0.802, Std: 0.038
# >k: 6, Acc Mean: 0.811, Std: 0.030
# >k: 7, Acc Mean: 0.797, Std: 0.056
# >k: 8, Acc Mean: 0.819, Std: 0.044
# >k: 9, Acc Mean: 0.820, Std: 0.032
# >k: 10, Acc Mean: 0.815, Std: 0.046
# >k: 15, Acc Mean: 0.818, Std: 0.037
# >k: 16, Acc Mean: 0.811, Std: 0.048
# >k: 18, Acc Mean: 0.809, Std: 0.043
# >k: 20, Acc Mean: 0.810, Std: 0.038
# >k: 21, Acc Mean: 0.828, Std: 0.038
knnfigF.jpg

Step 6: 結(jié)果分析

我們的實驗是每個k值下尚骄,隨機切分20次數(shù)據(jù), 從上述的圖片中, 根據(jù)k值的增加块差,我們的測試準確率會有先上升再下降再上升的過程。 [3, 5]之間是一個很好的取值,上文我們提到憨闰,k很小的時候會發(fā)生過擬合状蜗,k很大時候會發(fā)生欠擬合,當遇到第一下降節(jié)點鹉动,此時我們可以 簡單認為不在發(fā)生過擬合轧坎,取當前的k值即可。

2.5 KNN原理介紹

k近鄰方法是一種惰性學習算法泽示,可以用于回歸和分類缸血,它的主要思想是投票機制,對于一個測試實例x, 我們在有標簽的訓練數(shù)據(jù)集上找到和最相近的k個數(shù)據(jù)械筛,用他們的label進行投票捎泻,分類問題則進行表決投票,回歸問題使用加權平均或者直接平均的方法埋哟。knn算法中我們最需要關注兩個問題:k值的選擇和距離的計算笆豁。 kNN中的k是一個超參數(shù),需要我們進行指定赤赊,一般情況下這個k和數(shù)據(jù)有很大關系闯狱,都是交叉驗證進行選擇,但是建議使用交叉驗證的時候抛计,k∈[2,20]哄孤,使用交叉驗證得到一個很好的k值。

k值還可以表示我們的模型復雜度爷辱,當k值越小意味著模型復雜度變大录豺,更容易過擬合,(用極少數(shù)的樣例來絕對這個預測的結(jié)果饭弓,很容易產(chǎn)生偏見双饥,這就是過擬合)。我們有這樣一句話弟断,k值越多學習的估計誤差越小咏花,但是學習的近似誤差就會增大。


距離/相似度的計算:

樣本之間的距離的計算阀趴,我們一般使用對于一般使用Lp距離進行計算昏翰。當p=1時候,稱為曼哈頓距離(Manhattan distance)刘急,當p=2時候棚菊,稱為歐氏距離(Euclidean distance),當p=∞時候叔汁,稱為極大距離(infty distance), 表示各個坐標的距離最大值,另外也包含夾角余弦等方法统求。

一般采用歐式距離較多检碗,但是文本分類則傾向于使用余弦來計算相似度。


knnfigG.jpg
學習感悟:

好難奥肓凇折剃!這部分沒有學明白~~~

?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市像屋,隨后出現(xiàn)的幾起案子怕犁,更是在濱河造成了極大的恐慌,老刑警劉巖己莺,帶你破解...
    沈念sama閱讀 222,865評論 6 518
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件奏甫,死亡現(xiàn)場離奇詭異,居然都是意外死亡篇恒,警方通過查閱死者的電腦和手機扶檐,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,296評論 3 399
  • 文/潘曉璐 我一進店門凶杖,熙熙樓的掌柜王于貴愁眉苦臉地迎上來胁艰,“玉大人,你說我怎么就攤上這事智蝠√诿矗” “怎么了?”我有些...
    開封第一講書人閱讀 169,631評論 0 364
  • 文/不壞的土叔 我叫張陵杈湾,是天一觀的道長解虱。 經(jīng)常有香客問我,道長漆撞,這世上最難降的妖魔是什么殴泰? 我笑而不...
    開封第一講書人閱讀 60,199評論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮浮驳,結(jié)果婚禮上悍汛,老公的妹妹穿的比我還像新娘。我一直安慰自己至会,他們只是感情好离咐,可當我...
    茶點故事閱讀 69,196評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著奉件,像睡著了一般宵蛀。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上县貌,一...
    開封第一講書人閱讀 52,793評論 1 314
  • 那天术陶,我揣著相機與錄音,去河邊找鬼煤痕。 笑死梧宫,一個胖子當著我的面吹牛征候,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播祟敛,決...
    沈念sama閱讀 41,221評論 3 423
  • 文/蒼蘭香墨 我猛地睜開眼疤坝,長吁一口氣:“原來是場噩夢啊……” “哼凰狞!你這毒婦竟也來了责嚷?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 40,174評論 0 277
  • 序言:老撾萬榮一對情侶失蹤疚膊,失蹤者是張志新(化名)和其女友劉穎埠巨,沒想到半個月后历谍,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,699評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡辣垒,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,770評論 3 343
  • 正文 我和宋清朗相戀三年望侈,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片勋桶。...
    茶點故事閱讀 40,918評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡脱衙,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出例驹,到底是詐尸還是另有隱情捐韩,我是刑警寧澤,帶...
    沈念sama閱讀 36,573評論 5 351
  • 正文 年R本政府宣布鹃锈,位于F島的核電站荤胁,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏屎债。R本人自食惡果不足惜仅政,卻給世界環(huán)境...
    茶點故事閱讀 42,255評論 3 336
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望盆驹。 院中可真熱鬧圆丹,春花似錦、人聲如沸召娜。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,749評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽玖瘸。三九已至秸讹,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間雅倒,已是汗流浹背璃诀。 一陣腳步聲響...
    開封第一講書人閱讀 33,862評論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留蔑匣,地道東北人劣欢。 一個月前我還...
    沈念sama閱讀 49,364評論 3 379
  • 正文 我出身青樓棕诵,卻偏偏與公主長得像,于是被迫代替她去往敵國和親凿将。 傳聞我的和親對象是個殘疾皇子校套,可洞房花燭夜當晚...
    茶點故事閱讀 45,926評論 2 361

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