分類分析 - - K-近鄰(KNN)算法(代碼工具python)

1、分類分析--K近鄰(KNN)算法原理

核心思想:根據離自己最近的鄰居判斷自己屬於哪一類,如上圖當圓的半徑(距離)爲1時,k個個體中有2/3個是三角形,則目標圓點(預測點)的分類和三角形爲一類;當半徑(距離)取值爲2時,k個特徵個體中有3/5個是正方形,則認爲預測點和正方形爲一類的思想。由此也說明了KNN算法的結果很大程度取決於K的選擇。

我們設定要取的k個鄰近點來看屬於哪一類別的分類時,其實就找距離目標(預測)點最近的k個點就可以了,那麼我們就要先求得各個樣本點離預測點的距離d。

在KNN中,通過計算對象間距離來作爲各個對象之間的非相似性指標,避免了對象之間的匹配問題,在這裏距離一般使用歐氏距離或曼哈頓距離或名可夫斯基距離:

 

2、特徵值進行標準化:

當特徵變量之間差值非常大時,如果不進行標準化處理,則會導致預測錯誤。如下圖,當k值取3時,非標準化計算的距離最近的電影是E、F、D,100%判斷爲動作片;標準化處理後最近距離的電影是C、B、D,則判斷爲愛情片,顯然更準確。

3、KNN的優缺點

KNN算法的優勢:KNN通過依據k個對象中佔優的類別進行決策,而不是單一的對象類別決策。

KNN算法的缺勢:

  • k值取得太小容易受到異常值影響,
  • K值取得過大容易受到樣本不均衡的影響(如a類取10個樣本,b類取30個樣本,k取20顯然分佈不均)。
  • K值取奇數不取偶數(偶數會出現同票現象)
  • 懶情算法,對測試樣本分類時的計算量大,內存開銷大
  • 必須指定K值,K值選擇不當則分類精度不能保證
  • 使用場景:小數據場景,幾幹~幾萬樣本,具體場景具體業務去測試

4、python實現及案例

API:

sklearn.neighbors.KNeighborsClassifier(n_neighbors=5,algorithm='auto)

  •     sklearn.neighbors.KNeighborsClassifier(n_neighbors=5.algorithm='auto')

  •  n_neighbors:int.可選(默i認=5),k_.neighbors查詢默認使用的鄰居數
        algornthm:{'auto',‘ball_tree','kd_tree','brute'},可選用於計算最近鄰居的算法:ball_tree'將會使用BallTree,'kd_tree將使用KDTree。‘auto將嘗試根據傳遞給t方法的值來決定最合適的算法。(不同實現方式影響效率)

案例數據說明:

df = sklearn.datasets.load_iris() #iris:花的數據集

實例數量:150(三個類各有50個)

屬性數量:4(數值型,數值型,幫助預測的屬性和類)

Attribute Information:·sepal length 薯片長度(釐米)

·sepal width 薯片寬度(釐米)

·petal length花瓣長度(釐米)

·petal width花瓣寬度(釐米)

·target_names:Setosa山鳶尾、Versicolour 變色鳶尾、Virginica 維吉尼亞鳶尾

#1、獲取數據

from sklearn import datasets      #機器學習數據集庫
#sklearn.datasets.load_*()        # *:表示某個數據集的名稱,load_:獲取小規模數據集
df = datasets.load_iris()       #iris:花的數據集
#display(df.data)  #返回特徵值(自變量)數組
#display(df.target) #返回目標值(因變量)數組
#print(df["DESCR"]) #返回描述信息
display(df["feature_names"]) #返回特徵值的字段名稱
display(df.target_names) #返回目標值數字對應解釋

# 2、數據集劃分

from sklearn.model_selection import train_test_split
x_train,x_test,y_train,y_test = train_test_split(df.data,df.target,test_size=0.2,random_state=11)
print(x_train.shape,x_test.shape,y_train.shape,y_test.shape)

# 3、特徵工程:標準化

from sklearn.preprocessing import StandardScaler
import pandas as pd
transfer = StandardScaler() #實例化一個轉換器類
#標準化訓練集
x_train = transfer.fit_transform(x_train) #調用fit_transform()
data_train = pd.DataFrame(x_train,columns=df["feature_names"])
data_train["y"] = y_train
display(data_train.head(3))
# 標準化測試集
x_test=transfer.transform(x_test) #調用fit_transform()
'''
注意:爲什麼用transfer.transform(),而不是transfer.fit_transform()????
原因:前面fit()計算訓練集每一列的平均值、標準差,
    transform()(x-mean)/std,再進行最終的轉換,
    也就是說這樣處理,使用的均值和標準差是訓練集的,然後再標準化轉化,
    否則對測試集樣本再次求標準差和均值是不合理的。
    或者也可以先做完特徵工程後,再拆分數據集,也是合理的。
'''
data_test = pd.DataFrame(x_test,columns=df["feature_names"])
data_test["y"] = y_test
display(data_test.head(3))

# 4、knn預估器訓練模型
from sklearn.neighbors import KNeighborsClassifier  #knn算法庫
from sklearn.model_selection import GridSearchCV    #網格搜索和交叉驗證

#實例化一個轉換器類
#estimator = KNeighborsClassifier(n_neighbors=5,algorithm='auto') #直接選擇好參數k後執行

#加入模型選擇與調優,網格搜索和交叉驗證
#網格搜索和交叉驗證原理:後面單獨一篇文章介紹
estimator = KNeighborsClassifier()
#準備參數
param_dict = {"n_neighbors":[1,3,5,7,9,11,13,15,17,19]} #k值設定的可能取值
estimator = GridSearchCV(estimator,param_grid=param_dict,cv=10) #cv=10是10折交叉驗證

#執行預估器
estimator.fit(data_train.iloc[:,:4],data_train.iloc[:,-1])
#輸出結果反映最開始按照默認k=5執行,然後從傳入的k值進行模型對比,然後選出最優
'''
GridSearchCV(cv=10, error_score='raise',
       estimator=KNeighborsClassifier(algorithm='auto', leaf_size=30, metric='minkowski',
           metric_params=None, n_jobs=1, n_neighbors=5, p=2,
           weights='uniform'),
       fit_params=None, iid=True, n_jobs=1,
       param_grid={'n_neighbors': [1, 3, 5, 7, 9, 11, 13, 15, 17, 19]},
       pre_dispatch='2*n_jobs', refit=True, return_train_score='warn',
       scoring=None, verbose=0)
'''
# 5、模型評估選擇
#方法1:比對真實值和預測值
y_predict = estimator.predict(data_test.iloc[:,:4])  #計算預測值
print(y_predict)
b = data_test.iloc[:,-1] == y_predict  #比對真實值和預測值,相同的返回True
coun = data_test[b].count()[0]  #統計正確的個數
scale = coun/data_test.iloc[:,-1].count()  #計算正確的比例
display(scale)
#方法2:直接計算準確率
accuracy=estimator.score(x_test,y_test)
print(accuracy)

# 3、查看網格搜索和交叉驗證返回結果
# 最佳參數:best_params_
print("最佳參數k:",estimator.best_params_)
# 驗證集的最佳結果:best_score_
print("驗證集的最佳結果準確率:",estimator.best_score_)
# 最佳估計器:best_estimator_
print("最佳估計器",estimator.best_estimator_)
#注意best_estimator_的輸出解釋:metric='minkowski'是名可夫斯基距離,當p=1時是使用曼哈頓距離,當p=2時是使用歐式距離
# 交叉驗證結果:cv_results_
#print(estimator.cv_results_)  #比較長這裏就不輸出了
# 封裝與應用
'''
組織封裝代碼,爲節約運算成本,需要將模型調優選擇測試部分的代碼單獨封裝,直接調用最優秀模型。
時間久了,需要再次出入新的數據驗證模型是否最優,再調用調優部分的代碼,然後修改爲新的最優模型。

寫入實際需要預測的數據接口,預測返回需要的結果。完事!!!

後面有文章單獨詳細介紹和操作
'''

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章