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)流程:
計算已知類別數(shù)據(jù)集中點與當(dāng)前點之間的距離。
按距離遞增次序排序。
選取與當(dāng)前點距離最小的k個點。
統(tǒng)計前k個點所在的類別出現(xiàn)的頻率。
返回前k個點出現(xiàn)頻率最高的類別作為當(dāng)前點的預(yù)測分類。
1.1 距離公式
距離公式在k近鄰算法中扮演著至關(guān)重要的角色,直接影響最終預(yù)測結(jié)果。常見的距離公式有:
歐式距離
曼哈頓距離
契比雪夫距離
閔可夫斯基距離
上述四種距離計算公式,都將各分量的量綱忽略了,也沒有考慮各分量的分布。
標(biāo)準(zhǔn)化歐式距離
余弦距離
向量夾角的余弦值,越接近與+1表明夾角越小,越接近于-1表明夾角越大。漢明距離
兩個等長字符串s1與s2的漢明距離為:將其中一個變?yōu)榱硗庖粋€所需要做的最小字符替換次數(shù)。
字符串或變量在計算集中表示為二進(jìn)制后,非零位個數(shù)的差值。Jaccard Distance
距離算法簡介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)色的正方形一類。
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)確性。
特征預(yù)處理的常用方法
歸一化法:通過對原始數(shù)據(jù)進(jìn)行變換把數(shù)據(jù)映射到(默認(rèn)為[0,1])之間。
最大值與最小值非常容易受異常點影響,所以這種方法魯棒性較差,只適合傳統(tǒng)精確小數(shù)據(jù)場景。標(biāo)準(zhǔn)化:通過對原始數(shù)據(jù)進(jìn)行變換把數(shù)據(jù)變換到均值為0,標(biāo)準(zhǔn)差為1范圍內(nèi)。
如果出現(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])
第二步:數(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": [1, 3, 5, 7]}
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.00099572, 0.00066511, 0.00033236, 0.00033259]), 'std_fit_time': array([3.64363778e-06, 4.70304900e-04, 4.70021655e-04, 4.70358829e-04]), 'mean_score_time': array([0.00299184, 0.0020051 , 0.00198833, 0.0033323 ]), 'std_score_time': array([8.14490846e-04, 1.41827329e-05, 8.06420792e-04, 1.23373824e-03]), 'param_n_neiors': masked_array(data=[1, 3, 5, 7],
7 mask=[False, False, False, False],
8 fill_value='?',
9 dtype=object), 'params': [{'n_neiors': 1}, {'n_neiors': 3}, {'n_neiors': 5}, {'n_neiors': 7}], 'split0_test_score': array([0.95, 0.95, 0.95, 0.95]), 'split1_test_score': array([0.925, 0.975, 0.975, 1. ]), 'split2_test_score': array([0.975, 0.975, 0.975, 0.975]), 'mean_test_score': array([0.95 , 0.96666667, 0.96666667, 0.975 ]), 'std_test_score': array([0.02041241, 0.01178511, 0.01178511, 0.02041241]), 'rank_test_score': array([4, 2, 2, 1])}
第五步:模型評估
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
工程師必備
- 項目客服
- 培訓(xùn)客服
- 平臺客服
TOP




















