python機器學習演算法——KNN演算法

程序计算机人發表於2024-04-16

  如題,KNN演算法。

  參考:

          https://www.showmeai.tech/article-detail/187

  前提總結:KNN演算法,或許就是“近墨者黑,近朱者赤”。

  1.機器學習與分類問題

    1)分類問題

     2)分類問題的數學抽象

從演算法的角度解決一個分類問題,我們的訓練資料會被對映成 維空間的樣本點(這裡的 就是特徵維度),我們需要做的事情是對 維樣本空間的點進行類別區分,某些點會歸屬到某個類別。

  2.K近鄰演算法核心思想

    1)K近鄰核心思想

        在 KNN 分類中,輸出是一個分類族群。一個物件的分類是由其鄰居的「多數表決」確定的, 個最近鄰居( 為正整數,通常較小)中最常見的分類決定了賦予該物件的類別。

若 ,則該物件的類別直接由最近的一個節點賦予。

        在 KNN 迴歸中,輸出是該物件的屬性值。該值是其 個最近鄰居的值的平均值。

        近鄰居法採用向量空間模型來分類,概念為相同類別的案例,彼此的相似度高。而可以藉由計算與已知類別案例之相似度,來評估未知類別案例可能的分類。

    2)豆子分類例子

        1968年,Cover 和 Hart 提出了最初的近鄰法,思路是——未知的豆離哪種豆最近,就認為未知豆和該豆是同一種類。

        最近鄰演算法的缺陷是對噪聲資料過於敏感。從圖中可以得到,一個圈起來的藍點和兩個圈起來的紅點到綠點的距離是相等的,根據最近鄰演算法,該點的形狀無法判斷。

        為了解決這個問題,我們可以把位置樣本週邊的多個最近樣本計算在內,擴大參與決策的樣本量,以避免個別資料直接決定決策結果。

        引進 近鄰演算法——選擇未知樣本一定範圍內確定個數的 個樣本,該 個樣本大多數屬於某一型別,則未知樣本判定為該型別。 近鄰演算法是最近鄰演算法的一個延伸。

  3.K近鄰演算法步驟與示例

    1)K近鄰演算法工作原理

        存在一個樣本資料集合,也稱作訓練樣本集,並且樣本集中每個資料都存在標籤,即我們知道樣本集中每個資料與所屬分類的對應關係。

        輸入沒有標籤的新資料後,將新資料的每個特徵與樣本集中資料對應的特徵進行比較,然後演算法提取樣本集中特徵最相似資料(最近鄰)的分類標籤。

        一般來說,只選擇樣本資料集中前 個最相似的資料。 一般不大於 ,最後,選擇 箇中出現次數最多的分類,作為新資料的分類。

        理解:提取和測試目標欄位,篩選一種變數,取得測試集和訓練集,確定k(間接得出距離),得到均值(KNN後的,即是那個次數最多的分類)作為新資料的分類。

    2)K近鄰演算法引數選擇

        如何選擇一個最佳的 值取決於資料。一般情況下,在分類時較大的 值能夠減小噪聲的影響,但會使類別之間的界限變得模糊。一個較好的 值能透過各種啟發式技術(見超引數最佳化)來獲取。

        噪聲和非相關性特徵的存在,或特徵尺度與它們的重要性不一致會使 近鄰演算法的準確性嚴重降低。對於選取和縮放特徵來改善分類已經做了很多研究。一個普遍的做法是利用進化演算法最佳化功能擴充套件,還有一種較普遍的方法是利用訓練樣本的互資訊進行選擇特徵。

        在二元(兩類)分類問題中,選取 為奇數有助於避免兩個分類平票的情形。在此問題下,選取最佳經驗 值的方法是自助法。

        說明: KNN 沒有顯示的訓練過程,它是「懶惰學習」的代表,它在訓練階段只是把資料儲存下來,訓練時間開銷為 ,等收到測試樣本後進行處理。

這裡有一個樣例(課上也同樣講到了)

    3)K近鄰演算法示例

  4.K近鄰演算法的缺點與改進

    1)K近鄰演算法的優缺點

        優點:精度高、對異常值不敏感、無資料輸入假定。
        缺點:計算複雜度高、空間複雜度高。
        適用資料範圍:數值型和標稱型。

    2)K近鄰演算法的核心要素:距離度量準則

        近鄰演算法能用一種有效的方式隱含的計算決策邊界。另外,它也可以顯式的計算決策邊界,以及有效率的這樣做計算,使得計算複雜度是邊界複雜度的函式。 近鄰演算法依賴於空間中相近的點做類別判斷,判斷距離遠近的度量標準非常重要。

        距離的度量標準,對很多演算法來說都是核心要素(比如無監督學習的 聚類演算法 也很大程度依賴距離度量),也對其結果有很大的影響。

    3)K近鄰演算法的核心要素:K的大小

        對於 KNN 演算法而言, 的大小取值也至關重要,如果選擇較小的 值,意味著整體模型變得複雜(模型容易發生過擬合),模型學習的近似誤差(approximation error)會減小,但估計誤差(estimation error)會增大。

        如果選擇較大的 值,就意味著整體的模型變得簡單,減少學習的估計誤差,但缺點是學習的近似誤差會增大。

        在實際的應用中,一般採用一個比較小的 值。並採用交叉驗證的方法,選取一個最優的 值。

    4)K近鄰演算法的缺點與改進

      1)缺點

        樣本庫容量依賴性較強對 KNN 演算法在實際應用中的限制較大:

           有不少類別無法提供足夠的訓練樣本,使得 KNN 演算法所需要的相對均勻的特徵空間條件無法得到滿足,使得識別的誤差較大。

        值的確定:

           KNN 演算法必須指定 值, 值選擇不當則分類精度不能保證。

     2)改進方法

        加快 KNN 演算法的分類速度。

          濃縮訓練樣本當訓練樣本集中樣本數量較大時,為了減小計算開銷,可以對訓練樣本集進行編輯處理,即從原始訓練樣本集中選擇最優的參考子集進行 近鄰尋找,從而減少訓練樣本的儲存量和提高計算效率。

加快 個最近鄰的搜尋速度這類方法是透過快速搜尋演算法,在較短時間內找到待分類樣本的 個最近鄰。


        對訓練樣本庫的維護。

          對訓練樣本庫進行維護以滿足 KNN 演算法的需要,包括對訓練樣本庫中的樣本進行新增或刪除,採用適當的辦法來保證空間的大小,如符合某種條件的樣本可以加入資料庫中,同時可以對資料庫庫中已有符合某種條件的樣本進行刪除。從而保證訓練樣本庫中的樣本提供 KNN 演算法所需要的相對均勻的特徵空間。

  5.案例介紹

      資料集請去原網站下載,保留一下我的資料集位置:

      將預計出租房子資料與資料集中每條記錄比較計算歐式距離,取出距離最小的5條記錄,將其價格取平均值,可以將其看做預計出租房子的市場平均價格。(可以認為k為5,之後會詳細解釋為什麼要取平均值的)

      原始碼請去原網址觀看,原網址本文文首和文末都有貼出。記錄一下我的原始碼保留位置:

      關於自己對原始碼的解釋(不建議觀看)

   import模組:

    (vim貌似沒有找到自動導包的外掛,可以在windows的相關python的IDE進行編寫然後再複製到vim也行,也可以直接在windows裡編寫執行,但是還是建議在linux系統裡啦,希望我的linux不會記憶體不夠,我給了100G,只是用來寫程式碼沒事的吧)

    

有關資料的有numpy和pandas,比如說pandas的DataFrame物件(相關操作實踐寫著寫著就會了),類似於
    col1 col2 col3
0    xxx xxx xxx
1    xxx xxx xxx
………………………………………………………………

然後計算歐式距離的有scipy(數學函式庫)的spatial(空間的)
之後就是因為資料範圍使用的標準化,sklearning.processing.StandardScaler(Scaler標量的),processing過程,是過程中的資料準備
接下來是主要,KNN演算法,sklearn.neighbors.KNN,這個包名是因為KNN演算法的KNeighbors,k近鄰演算法
最後是誤差判斷,knn使用均方根誤差,mean_squared_error(這個意思是均平方誤差,所以需要最後還需要開根號)
來自sklearn的metrics,metrics(指標)
sklearn用於分類,聚類等

記憶重點:
open(path,'encoding=gb18030',errors='ignore')
paht = r'路徑'

由於python的變數沒有型別,所以諸如 dc_listings = pd.read_cv(file) ,然後又出現了 dc_listings = dc_listings['features']很重要

pd.read_csv(file)得出來的結果是DataFrame物件例項
也有這麼用的:
features = ['xxx','xxxx','xxx']
dc_listings['features']是一個擷取了部分列的DataFrame物件例項,程式碼這裡是這麼寫的dc_listings = dc_listings['features']
意思大概就是,如果儘可能地和其他語言融合,features的這些就是下標,然後擷取一部分表可以使用features列表
不過其實是DataFrame物件啦。

資料初步清洗
突然找到很詳細的連結:[200~https://www.cnblogs.com/nerd/p/14405726.html

np.abs(dc_listings.accommodates - our_acc_value)加上sort是為了那些靠近3容納(accommodates)的資料。(篩選資料,樣例是有一套房子即將出租,選取相似的,就是多變數的一種變數)
dc_listings['distance'] 是新增一個列的,注意這個用法
sample是用來獲取隨機樣本的,因為提取的資料可能會有規律
dropna是用來刪除有缺失值的

資料標準化:
對我們想要的特徵進行標準化的:
dc_listings[features] = StandardScale().fit_transform(dc_listings[features])
normalized = dc_listings[features]
標準化的原因是,理想情況下我們的列的資料範圍是一樣的,但是現實很難,所以需要標準化(具體實現我們抽象掉吧,現在還是別去看了)

分出訓練集和測試集合
norm_train_dc_features = normalized_listings[:2792]
資料集是由pandas的DataFrame來呈現的,
iloc是用來找到datafram的索引和列的
https://blog.csdn.net/Bigboss7/article/details/118597351
這裡的程式碼示例是第1行和第accommodates和bathrooms列的:first_listings = normalized_listings.iloc[0][['accommodates', 'bathrooms']]
(類似的fifth就不講了)

(透過DataFrame的行索引和列索引就可以知道很多語句了)
https://blog.csdn.net/weixin_42107718/article/details/98659921

所以norm_train_df = normalized_listings[:2792]應該是行
索引,0到2792行

first_listings = normalized_listings.iloc[0]['accommodates','bathrooms']
這個就是dataframes的iloc方法

用python方法做多變數KNN模型
def predict_price_multivariate(new_listing_value,feature_colummns):
多變數 is multi(multipy)variate(variable)
normalized是歸一化的意思

distance.cdist(temp_df[feature_columns],new_listing_value[feature_columns]))是計算兩個集合的距離,feature_columns可以是多個特徵

knn_5 = temp_df.price.iloc[:5]
predicted_price = knn_t.mean() mean我記得是均值
knn_5那個,應該是這個意思,我們從那個圖中可以知道是一個圓形的看圓內種類,那個圓就是幾何上的距離。我們按照距離排序
,其實圓的半徑應該是第5行的那個(行索引為4),這裡可以理解成k是5

mean,均值,可以理解成平均值,
先透過距離排序,以此獲得price的排名,然後再均值。
均值,是因為距離問題吧,如果是a類,價格應該是某一個範圍,
如果是b類,價格應該是另一個範圍,透過圓內誰的種類多(相應的在某一個特定範圍的多)計算出來的均值肯定會偏向種類多的價格範圍。

關於計算距離的方法,這個例子採用的是歐式距離,import語句是
from scipy.spatial import distance
distance.cdist(temp_df[feature_columns],new_listing_value[feature_columns])
由於資料初步清洗那裡先一步排序需要的accomodates了,所以這裡雖然是多特徵,但是可能bathrooms的影響更大點。
cdist是communlate distance(計算距離)

norm_test_df['predicted_price'] = norm_test_df[cols].apply(predict_price_multivariate,feature_columns = cols, axis = 1)
需要注意的是norm_test_df[cols]的cols是兩個列名,這裡應該是需要處理的兩個列,得出的結果變成一個列,去查了apply方法,是對列的資料進行逐一遍歷


norm_test_df['squared_error'] = (norm_test_df['predicted_price'] - norm_test_df['price']) ** 2
mse = norm_test_df['squared_error'].mean()
rmse = mese ** (1/2)


利用sklearn完成KNN
col=['accommodates','beadrooms']
knn = KNeighborRegressor() Regressor是迴歸的意思

將自變數和因變數放入模型訓練,並用測試資料測試。
knn.fit(norm_train_df[cols],norm_train_df['price'])
(測試即是得出曲線)
two_features_predictions = knn.predict(norm_test_df[cols])

計算預測值與實際值的均方根誤差
two_features_mse = mean_squared_error(norm_test_df['price'],two_features_prediction)
(也就是將預測出來的資料和我們的原先的test進行比對看看誤差有多大)

two_features_rmse = two_features_mse ** (1/2)

print(two_features_rmse)


KNN_first_start.py(或者說原作者給出的原始碼)實際上表現了兩種用法,一種是python構建多變數KNN模型,一種是sklearn的多變數KNN模型。

  步驟總結:

那麼透過原始碼自己總結一下步驟:

  1.匯入資料並提取目標欄位(可以理解成加快knn的分類方法?)(提取多少要麼看題目要麼看自己)

  2.進行初步資料清洗,先將多變數中的一個變數進行排序,隨機,替換不能要的字元,刪除缺失行,標準化清洗得出的資料,取得訓練集和測試集

  3.獲得多變數KNN模型中想要的列的資料(後面貌似沒有用到),可以使用python方法做多變數KNN模型,也可以使用sklearn提供的KNN,記得兩種方法都要計算誤差。

參考連結:https://www.showmeai.tech/article-detail/187

相關文章