01 K-近鄰算法介紹與實現(xiàn)

關(guān)鍵詞:人工智能, 算法

1. 算法簡介1.1 距離公式1.2 K值的選擇1.3 其它概念2. 實例:鳶尾花種類預(yù)測

1. 算法簡介

核心理念:根據(jù)你的鄰居來推斷出你的類別。
定義: 如果一個樣本在特征空間中的k個最相似(即特征空間中最鄰近)的樣本中的大多數(shù)屬于某一個類別,則該樣本也屬于這個類別。

簡單講就是定義一組變量描述一個類,定義一種距離計算公式描述各個實例之間的差異大小,如果被推測的實例與某些已知目標(biāo)值的實例最近(距離公式最短等),那么則仍為被推測實例的目標(biāo)值也是該值。
K 近鄰算法使用的模型實際上對應(yīng)于對特征空間的劃分。距離度量、K 值的選擇和分類決策規(guī)則是該算法的三個基本要素。

適用范圍: 字符識別、文本分類、圖像識別等領(lǐng)域。

實現(xiàn)流程:

  1. 計算已知類別數(shù)據(jù)集中點與當(dāng)前點之間的距離。

  2. 按距離遞增次序排序。

  3. 選取與當(dāng)前點距離最小的k個點。

  4. 統(tǒng)計前k個點所在的類別出現(xiàn)的頻率。

  5. 返回前k個點出現(xiàn)頻率最高的類別作為當(dāng)前點的預(yù)測分類。

1.1 距離公式

距離公式在k近鄰算法中扮演著至關(guān)重要的角色,直接影響最終預(yù)測結(jié)果。常見的距離公式有:

  1. 歐式距離

    01 K-近鄰算法介紹與實現(xiàn)的圖1

  2. 曼哈頓距離

    01 K-近鄰算法介紹與實現(xiàn)的圖2

  3. 契比雪夫距離
    01 K-近鄰算法介紹與實現(xiàn)的圖3

  4. 閔可夫斯基距離
    01 K-近鄰算法介紹與實現(xiàn)的圖4

上述四種距離計算公式,都將各分量的量綱忽略了,也沒有考慮各分量的分布。

  1. 標(biāo)準(zhǔn)化歐式距離
    01 K-近鄰算法介紹與實現(xiàn)的圖5

  2. 余弦距離
    向量夾角的余弦值,越接近與+1表明夾角越小,越接近于-1表明夾角越大。
    01 K-近鄰算法介紹與實現(xiàn)的圖6

  3. 漢明距離
    兩個等長字符串s1與s2的漢明距離為:將其中一個變?yōu)榱硗庖粋€所需要做的最小字符替換次數(shù)。
    字符串或變量在計算集中表示為二進(jìn)制后,非零位個數(shù)的差值。

  4. Jaccard Distance
    距離算法簡介

  5. Mahalanobis Distance
    距離算法簡介

1.2 K值的選擇

k值的作用:少數(shù)服從多數(shù),k值決定選民多少

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

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

01 K-近鄰算法介紹與實現(xiàn)的圖7

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

總結(jié):k值過小容易收到異常點影響;k值過大收到樣本均衡的問題。
k值一般選擇個位的奇數(shù),如 3、5、7、9。

近似誤差: 過擬合,在訓(xùn)練集上表現(xiàn)好,測試集表現(xiàn)不好。

估計誤差: 估計誤差好才是真的好

1.3 其它概念

kd樹:
用于在模型中快速找到預(yù)測點的近鄰。
原理:A和B的距離很近,B和C的距離很遠(yuǎn),那么A和C的距離也很遠(yuǎn)。
樹的建立:先選擇方差大維度進(jìn)行分隔,然后選另一維度,循環(huán)往復(fù)

交叉驗證:
首先將數(shù)據(jù)集分成訓(xùn)練集、驗證集
訓(xùn)練集再分為訓(xùn)練集、測試集
首先用訓(xùn)練集進(jìn)行訓(xùn)練、然后用測試集測試準(zhǔn)確率。

作用:保證準(zhǔn)確率更加可信,但不能提高模型的準(zhǔn)確性。

01 K-近鄰算法介紹與實現(xiàn)的圖8

特征預(yù)處理的常用方法

  • 歸一化法:通過對原始數(shù)據(jù)進(jìn)行變換把數(shù)據(jù)映射到(默認(rèn)為[0,1])之間。
    01 K-近鄰算法介紹與實現(xiàn)的圖9
    最大值與最小值非常容易受異常點影響,所以這種方法魯棒性較差,只適合傳統(tǒng)精確小數(shù)據(jù)場景。

  • 標(biāo)準(zhǔn)化:通過對原始數(shù)據(jù)進(jìn)行變換把數(shù)據(jù)變換到均值為0,標(biāo)準(zhǔn)差為1范圍內(nèi)。
    01 K-近鄰算法介紹與實現(xiàn)的圖10
    如果出現(xiàn)異常點,由于具有一定數(shù)據(jù)量,少量的異常點對于平均值的影響并不大,從而方差改變較小。

標(biāo)準(zhǔn)化在已有樣本足夠多的情況下比較穩(wěn)定,適合現(xiàn)代嘈雜大數(shù)據(jù)場景。

2. 實例:鳶尾花種類預(yù)測

鳶尾花案例  
鳶尾花數(shù)據(jù)集:特征值4個:萼片長度、萼片寬度、花瓣長度、花瓣寬度;目標(biāo)值1個:鶯尾花的種類(共計3類)  
數(shù)據(jù)集: 
   實例數(shù)150個,三類各有50個

第一步:從sklearn中獲取數(shù)據(jù)集

 1import seaborn as sns
2import matplotlib.pyplot as plt
3import pandas as pd
4from sklearn.datasets import load_iris
5# 獲取鳶尾花數(shù)據(jù)集
6iris = load_iris()
7# 可視化數(shù)據(jù),判斷特征值是否可以將類別分開
8# 把數(shù)據(jù)轉(zhuǎn)換成dataframe的格式
9iris_d = pd.DataFrame(iris["data"], columns=iris.feature_names)
10iris_d["Species"] = iris.target
11
12%matplotlib inline
13
14
15def plot_iris(iris, col1, col2):
16    sns.lmplot(x=col1, y=col2, data=iris, hue="Species", fit_reg=False)
17    plt.xlabel(col1)
18    plt.ylabel(col2)
19    plt.show()
20
21
22# 常看各個特征之間的關(guān)系
23plot_iris(iris_d, iris.feature_names[0], iris.feature_names[2])
24# plot_iris(iris_d,iris.feature_names[0],iris.feature_names[3])
25# plot_iris(iris_d,iris.feature_names[1],iris.feature_names[2])
26# plot_iris(iris_d,iris.feature_names[1],iris.feature_names[3])
27# plot_iris(iris_d,iris.feature_names[2],iris.feature_names[3])

01 K-近鄰算法介紹與實現(xiàn)的圖11

第二步:數(shù)據(jù)集劃分

1from sklearn.model_selection import train_test_split
2# random_state 是隨機數(shù)種子;test_size 是測試集所占的比例
3x_train, x_test, y_train, y_test = train_test_split(
4    iris.data, iris.target, random_state=20, test_size=0.2)

第三步:特征工程,數(shù)據(jù)標(biāo)準(zhǔn)化

1from sklearn.preprocessing import StandardScaler
2transfer = StandardScaler()
3# 找出訓(xùn)練集數(shù)據(jù)的均值、方差,并保存在tansfer中,供后續(xù)標(biāo)準(zhǔn)化使用。
4x_train = transfer.fit_transform(x_train)
5print(f"訓(xùn)練數(shù)據(jù)集的均值是:{transfer.mean_}")
6print(f"訓(xùn)練數(shù)據(jù)集的標(biāo)準(zhǔn)差是:{transfer.var_}")
7# 使用訓(xùn)練數(shù)據(jù)集的均值、方差轉(zhuǎn)換測試數(shù)據(jù)集
8x_test = transfer.transform(x_test)
1訓(xùn)練數(shù)據(jù)集的均值是:[5.82833333 3.1        3.71333333 1.19833333]
2訓(xùn)練數(shù)據(jù)集的標(biāo)準(zhǔn)差是:[0.67436389 0.19883333 3.13398889 0.59749722]

第四步:機器學(xué)習(xí)訓(xùn)練模型

 1from sklearn.model_selection import GridSearchCV
2from sklearn.neiors import KNeiorsClassifier
3estimator_0 = KNeiorsClassifier()
4# 模型選擇與調(diào)優(yōu)——網(wǎng)格搜索和交叉驗證
5# 定義要優(yōu)化的參數(shù)可取值范圍
6param_dict = {"n_neiors": [1357]}
7# 定義交叉驗證的次數(shù)cv等
8estimator = GridSearchCV(estimator_0, param_grid=param_dict, cv=3)
9# 訓(xùn)練
10estimator.fit(x_train, y_train)
11# 輸出交叉驗證結(jié)果
12print("交叉驗證中最好的結(jié)果:\n", estimator.best_score_)
13print("交叉驗證中最好的參數(shù):\n", estimator.best_estimator_)
14print("每次交叉驗證的準(zhǔn)確率結(jié)果:\n", estimator.cv_results_)
1交叉驗證中最好的結(jié)果:
2 0.975
3交叉驗證中最好的參數(shù):
4 KNeiorsClassifier(n_neiors=7)
5每次交叉驗證的準(zhǔn)確率結(jié)果:
6 {'mean_fit_time'array([0.000995720.000665110.000332360.00033259]), 'std_fit_time'array([3.64363778e-064.70304900e-044.70021655e-044.70358829e-04]), 'mean_score_time'array([0.002991840.0020051 , 0.001988330.0033323 ]), 'std_score_time'array([8.14490846e-041.41827329e-058.06420792e-041.23373824e-03]), 'param_n_neiors': masked_array(data=[1357],
7             mask=[FalseFalseFalseFalse],
8       fill_value='?',
9            dtype=object), 'params': [{'n_neiors'1}, {'n_neiors'3}, {'n_neiors'5}, {'n_neiors'7}], 'split0_test_score'array([0.950.950.950.95]), 'split1_test_score'array([0.9250.9750.9751.   ]), 'split2_test_score'array([0.9750.9750.9750.975]), 'mean_test_score'array([0.95      , 0.966666670.966666670.975     ]), 'std_test_score'array([0.020412410.011785110.011785110.02041241]), 'rank_test_score'array([4221])}

第五步:模型評估

1# 方法一:對比真實值和預(yù)測值
2print("對比結(jié)果為:\n", y_test == estimator.predict(x_test))
3
4# 方法二:直接計算準(zhǔn)確率
5score = estimator.score(x_test, y_test)
6print("準(zhǔn)確率為:", score)
1對比結(jié)果為:
2 [ True  True  True  True  True  True  True  True  True  True  True  True
3 False  True  True  True  True  True  True  True  True  True  True  True
4  True  True  True  True  True False]
5準(zhǔn)確率為: 0.9333333333333333



01 K-近鄰算法介紹與實現(xiàn)的圖12

登錄后免費查看全文
立即登錄
App下載
技術(shù)鄰APP
工程師必備
  • 項目客服
  • 培訓(xùn)客服
  • 平臺客服

TOP

25
15
12