從零開始學機器學習——分類器詳解

努力的小雨發表於2024-10-16

首先給大家介紹一個很好用的學習地址:https://cloudstudio.net/columns

今天我們將結合第一章節中清洗得到的菜品資料,利用多種分類器對這些資料進行訓練,以構建有效的模型。在這個過程中,我會詳細講解每一種分類器的原理及其重要性。

儘管這些知識點對於實踐來說並不是必須掌握的,因為第三方依賴包已經為我們完成了大量的封裝,使得呼叫這些功能僅需一行程式碼,但理解其背後的原理仍然至關重要。這將有助於我們在實際應用中更好地把握模型的表現和改進的方向。

分類路線圖

在上一章節中,我們已經檢視了微軟的小抄表,並對其進行了中文翻譯,希望這些內容對你有所幫助。今天,我們將繼續探索Scikit-learn提供的一個類似的速查表,但它的細粒度和資訊量更加豐富。這份速查表不僅能幫助您快速查詢相關資訊,還能為您在調整估計器(分類器的另一個術語)時提供實用的指導。

速查表原文地址:https://scikit-learn.org/stable/machine_learning_map.html

image

表情😭符號應理解為“如果此估計器沒有達到預期結果,則按照箭頭嘗試下一個”

然後,我們根據此路線圖選擇我們的分類器:

  • 我們有超過 50 個樣本
  • 我們想要預測一個類別
  • 我們有標記過的資料
  • 我們的樣本數少於 100000
    • ✨ 我們可以選擇線性 SVC
    • 如果那不起作用,既然我們有數值資料,沒有文字資料
      • 我們可以嘗試 ✨ K-近鄰分類器
        • 如果那不起作用,試試 ✨ SVC 和 ✨ 整合分類器

模型構建

接下來第一步則是將資料分為訓練集、測試集。

import pandas as pd
from sklearn.neighbors import KNeighborsClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.svm import SVC
from sklearn.ensemble import RandomForestClassifier, AdaBoostClassifier
from sklearn.model_selection import train_test_split, cross_val_score
from sklearn.metrics import accuracy_score,precision_score,confusion_matrix,classification_report, precision_recall_curve
import numpy as np

cuisines_df = pd.read_csv("../data/cleaned_cuisines.csv")

cuisines_label_df = cuisines_df['cuisine']
cuisines_feature_df = cuisines_df.drop(['Unnamed: 0', 'cuisine'], axis=1)

X_train, X_test, y_train, y_test = train_test_split(cuisines_feature_df, cuisines_label_df, test_size=0.3)

線性 SVC 分類器

根據我們的學習路線圖,第一步我們需要嘗試線性SVC分類器。在深入講解SVC之前,我們有必要先了解一下支援向量機(SVM)。這是因為在你搜尋SVC時,通常會找到大量關於SVM的資料,所以理解這兩者之間的區別是十分重要的。

接下來,我們將探討這兩者的不同之處,以及它們各自的特點和應用場景,以便為後續的學習奠定更紮實的基礎。

支援向量機(SVM)

支援向量機是一種強大的監督學習演算法,用於分類和迴歸問題。SVM是一個廣泛的概念,涵蓋了分類和迴歸問題;而SVC是SVM的特定應用,專門用於分類任務。在機器學習庫中,SVC通常是實現SVM的分類器的名稱,比如在Scikit-learn庫中。

支援向量機(SVM)有幾個子類,主要包括:支援向量分類(SVC)、支援向量迴歸(SVR)、一類支援向量機(One-Class SVM)、 多類支援向量機(Multi-Class SVM)、機率支援向量機(Probabilistic SVM)。這些子類允許支援向量機在不同型別的任務中表現出色。每個子類都有其獨特的實現和最佳化方式,以適應特定的應用場景。

舉個例子

如果理解線性 SVC 有些困難,我們來舉一個例子:

想象你在一個學校,有兩個班級:數學班和藝術班。每個學生都有不同的特點,比如他們的數學成績和藝術成績。你想根據這兩個成績把學生分到這兩個班級。

  1. 資料點
    • 每個學生可以用一個點在圖上表示:X1軸代表數學成績,X2軸代表藝術成績。
    • 數學班的學生通常數學成績高,藝術成績相對低。
    • 藝術班的學生通常藝術成績高,數學成績相對低。
  2. 分類目標
    你希望找到一條線(就像一個“分界線”)來把兩個班級的學生分開。
  3. 最大間隔
    SVC會尋找一條最好的分界線,使得這條線和最近的學生(支援向量)之間的距離最大。這樣,即使有一些新的學生在數學和藝術成績上介於兩者之間,這條線依然能夠較好地分類他們。
  4. 處理複雜情況
    假設有一個學生的數學和藝術成績都很中等。用一條線可能很難將這個學生明確地分到一個班級。SVC可以透過“增加維度”,想象一下你有一個第三個維度,比如“運動成績”。在這個三維空間中,SVC可以找到一個更復雜的分介面,來更好地分開這兩個班級的學生。

透過這個比喻,SVC的核心就是:

  • 它找出一種最佳的方法來區分不同的群體(如班級)。
  • 透過最大化與最近的學生(支援向量)之間的距離,確保分類更加穩健。
  • 在面對複雜情況時,可以使用其他特徵(如運動成績)來幫助更準確地分類。

為此我找了一張圖片說明一下,更容易讓你理解。H3則是最佳分界線。

image

讓我們直接來看一下程式碼。儘管實現瞭如此複雜的功能,程式碼的結構卻相對簡單明瞭。

C = 10
# 建立不同的分類器
classifiers = {
    'Linear SVC': SVC(kernel='linear', C=C, probability=True,random_state=0)
}

n_classifiers = len(classifiers)

for index, (name, classifier) in enumerate(classifiers.items()):
    classifier.fit(X_train, np.ravel(y_train))

    y_pred = classifier.predict(X_test)
    accuracy = accuracy_score(y_test, y_pred)
    print("Accuracy (train) for %s: %0.1f%% " % (name, accuracy * 100))
    print(classification_report(y_test,y_pred))

執行結果如下,從表面上看,效能表現相當不錯,準確率至少接近80%。

Accuracy (train) for Linear SVC: 78.7% 
              precision    recall  f1-score   support

     chinese       0.69      0.80      0.74       242
      indian       0.89      0.84      0.87       239
    japanese       0.73      0.71      0.72       223
      korean       0.90      0.75      0.82       250
        thai       0.76      0.83      0.79       245

    accuracy                           0.79      1199
   macro avg       0.79      0.79      0.79      1199
weighted avg       0.80      0.79      0.79      1199

K-近鄰分類器

K-近鄰分類器(K-Nearest Neighbors, KNN)是一種簡單且直觀的監督學習演算法,主要用於分類和迴歸任務。它的基本思想是透過計算資料點之間的距離,將待分類的資料點歸類到其最近的 K 個鄰居的類別中。

舉個例子

在社交網路中,我們常常能看到某些使用者與特定興趣群體的聯絡。比如,假設我們想要判斷一個新使用者的興趣所在,我們可以觀察他周圍的朋友。

當我們分析這個新使用者的社交網路時,可以檢視與他最親近的 K 個朋友。這些朋友的共同興趣和活動可以為我們提供線索。如果這 K 個朋友大多數都喜歡攝影,那麼我們可以推測,這位新使用者很可能也對攝影感興趣。

透過這種方式,我們利用社交網路中朋友的影響,判斷一個使用者的興趣和愛好,從而更好地為他推薦內容和連線。

也就是說,根據近鄰樣本推測當前資料點屬於哪一類。

image

classifiers = {
    'Linear SVC': SVC(kernel='linear', C=C, probability=True,random_state=0),
    'KNN classifier': KNeighborsClassifier(C),
}

其他程式碼無需修改,我們只需在分類物件中新增一個 KNN 分類器即可。接下來,我們將繼續觀察執行結果。值得注意的是,這一調整並未產生顯著的效果,KNN 分類器的引入似乎對模型的整體效能沒有帶來太大的提升。

Accuracy (train) for KNN classifier: 74.1% 
              precision    recall  f1-score   support

     chinese       0.70      0.76      0.73       242
      indian       0.88      0.78      0.83       239
    japanese       0.64      0.82      0.72       223
      korean       0.94      0.54      0.68       250
        thai       0.68      0.82      0.74       245

    accuracy                           0.74      1199
   macro avg       0.77      0.74      0.74      1199
weighted avg       0.77      0.74      0.74      1199

Support Vector 分類器(SVC)

支援向量分類(SVC)和線性支援向量分類(Linear SVC)都是支援向量機(SVM)的一種實現,但它們在一些關鍵方面存在區別:

  1. 核函式
  • SVC:可以使用多種核函式(如線性核、多項式核、徑向基函式核等),適用於線性可分和非線性可分的資料集。
  • Linear SVC:只使用線性核,專注於處理線性可分的資料。它在最佳化過程中不進行核變換。
  1. 適用性
  • SVC:適合處理更復雜的資料集,能夠捕捉到非線性決策邊界。
  • Linear SVC:適合高維特徵空間的資料,尤其是特徵維數大於樣本數時(例如文字分類任務)。

如果你知道資料是線性可分的或者特徵維數非常高,使用 Linear SVC 可能更高效。如果資料存在非線性關係,選擇 SVC 並使用適當的核函式更合適。

classifiers = {
    'Linear SVC': SVC(kernel='linear', C=C, probability=True,random_state=0),
    'KNN classifier': KNeighborsClassifier(C),
    'SVC': SVC(),
}

我們將繼續觀察SVC的執行結果,似乎表現得更為理想。

Accuracy (train) for SVC: 81.7% 
              precision    recall  f1-score   support

     chinese       0.73      0.82      0.77       242
      indian       0.89      0.90      0.89       239
    japanese       0.81      0.73      0.76       223
      korean       0.90      0.77      0.83       250
        thai       0.79      0.86      0.82       245

    accuracy                           0.82      1199
   macro avg       0.82      0.82      0.82      1199
weighted avg       0.82      0.82      0.82      1199

整合分類器

儘管之前的測試結果已經相當令人滿意,但為了確保我們能夠全面評估模型的效能,我們決定沿著既定路線走到最後。因此,我們將嘗試一些整合分類器,特別是隨機森林和AdaBoost。

隨機森林

隨機森林就是用很多棵決策樹來做判斷,透過隨機選擇樣本和特徵來確保多樣性,最後結合這些樹的結果來提高整體的準確性和穩定性。這樣的方法讓模型更可靠,也更能適應複雜的資料。

想象一下,你想要決定今天的午餐吃什麼,但你有很多朋友,每個朋友都有不同的口味。你可以做以下幾件事:

  1. 請教多個朋友:你詢問每個朋友的建議,而不是隻聽一個人的意見。這樣,你能得到多種不同的選擇。
  2. 隨機選擇朋友:你不是每次都問所有朋友,而是隨機挑選幾個朋友來聽聽他們的意見。這樣可以避免受到個別朋友強烈偏好的影響。
  3. 記住他們的意見:你把每個朋友的建議記下來,比如有幾個朋友推薦了義大利麵,有幾個推薦了壽司。
  4. 最終決定:最後,你根據朋友們的推薦,選擇那個被最多人推薦的餐點。

關鍵知識點

  • 多樣性:隨機森林就是這樣一個想法,它透過“請教”很多個決策樹(這些樹就像你不同的朋友),每棵樹都是在不同的資料和特徵上訓練出來的。
  • 減少錯誤:透過多個“朋友”的建議,最終的選擇(預測)往往更準確,不容易受到單個決策的錯誤影響。
  • 投票機制:所有的決策樹給出的預測結果彙總後,就像你的朋友們投票一樣,最終選擇那個“得票最多”的結果。

AdaBoost

AdaBoost 的核心思想是透過不斷學習和調整,結合多個弱分類器的力量,來提高整體的預測能力。每次迭代都關注之前的錯誤,從而使模型逐步改進。

想象一下,你在學校裡參加一個辯論比賽,但你是個初學者,可能不太擅長辯論。你決定請教一些同學,他們的辯論水平不同,有的很厲害,有的剛剛開始。

  1. 請教不同同學:你找來了幾位同學來幫你,他們各自有不同的觀點和方法。每個同學都有可能在某個方面比你更擅長。
  2. 學習和調整:第一次練習時,可能有一些論點你說得不夠好,這些同學會給你反饋,告訴你哪些地方可以改進。你會記住這些錯誤,並在下次練習時更加註意。
  3. 重視反饋:對於那些你之前說錯的論點,給這些錯誤的部分“加重”。這意味著在接下來的練習中,你會特別關注這些問題,確保你能做到更好。
  4. 綜合意見:每次練習結束後,你會把所有同學的建議結合起來。雖然每個同學的能力不同,但透過不斷調整和綜合意見,最終你會變得更強。

關鍵知識點

  • 逐步改進:AdaBoost 就是這樣一個過程。它透過多個“弱分類器”(就像你不同的同學),每個分類器可能都不是特別強,但透過不斷的調整和學習,它們一起能夠構成一個更強的“強分類器”。
  • 重視錯誤:AdaBoost 特別關注那些之前預測錯誤的樣本,透過增加它們的權重,來讓後續的分類器更加關注這些難分類的樣本。
  • 加權組合:最後,所有的分類器的結果會結合在一起,就像你綜合了所有同學的意見一樣,透過投票或加權來決定最終的預測結果。

區別與聯絡

隨機森林:每棵樹都是相對獨立的,組合後形成的模型通常更穩健,尤其在資料集比較複雜時,隨機森林的每棵樹之間的相關性較低,有助於減少方差,通常在特徵數量很大或資料集複雜時表現良好,適用於分類和迴歸任務。

AdaBoost:分類器是序列的,每個新分類器都依賴於前一個分類器的結果,建立在前一個模型的基礎上,AdaBoost 更容易受到噪聲資料的影響,因為它會對錯誤分類的樣本給予更高的關注。更適合處理一些簡單的、需要更高準確性的任務,尤其在面對資料噪聲較少的情況下。

隨機森林更注重多樣性和獨立性,而 AdaBoost 則透過聚焦於難點來提升整體效能。

接下來,對於我們實現的程式碼來說就是兩行程式碼:

# 建立不同的分類器
classifiers = {
    'Linear SVC': SVC(kernel='linear', C=C, probability=True,random_state=0),
    'KNN classifier': KNeighborsClassifier(C),
    'SVC': SVC(),
    'RFST': RandomForestClassifier(n_estimators=100),
    'ADA': AdaBoostClassifier(n_estimators=100)
}

n_estimators在隨機森林中表示將生成 100 棵決策樹。每棵樹都是透過隨機選擇樣本和特徵來訓練的。透過增加樹的數量,模型的表現通常會更穩定,且更不容易過擬合。

n_estimators在AdaBoost 這表示將建立 100 個弱分類器(通常是簡單的決策樹)。每個分類器都會基於前一個分類器的表現進行訓練,關注那些之前分類錯誤的樣本。增加分類器的數量通常能提高模型的表現,但也可能增加過擬合的風險。

執行結果如下:

Accuracy (train) for RFST: 83.4% 
              precision    recall  f1-score   support

     chinese       0.78      0.80      0.79       242
      indian       0.89      0.91      0.90       239
    japanese       0.81      0.78      0.80       223
      korean       0.89      0.81      0.85       250
        thai       0.80      0.87      0.83       245

    accuracy                           0.83      1199
   macro avg       0.83      0.83      0.83      1199
weighted avg       0.84      0.83      0.83      1199

Accuracy (train) for ADA: 69.5% 
              precision    recall  f1-score   support

     chinese       0.66      0.48      0.56       242
      indian       0.88      0.79      0.84       239
    japanese       0.66      0.64      0.65       223
      korean       0.67      0.73      0.70       250
        thai       0.64      0.82      0.72       245

    accuracy                           0.69      1199
   macro avg       0.70      0.69      0.69      1199
weighted avg       0.70      0.69      0.69      1199

到此為止,我們已經對整個路線圖中能夠應用的所有分類器進行了全面的研究。雖然在程式碼實現上,這可能僅僅涉及一行程式碼或幾個引數的調整,但在背後,我們仍需對這些模型的基本邏輯和原理有一個大致的理解。

總結

在這個學習旅程中,我們不僅深入探討了各類分類器的原理和應用,還透過實踐加深了對模型構建過程的理解。透過使用不同的演算法,如線性SVC、K-近鄰分類器、支援向量分類器及整合方法如隨機森林和AdaBoost,我們看到了資料處理和模型訓練的多樣性。在每一步的探索中,我們不僅關注了準確率,還思考了每種演算法的適用場景及其優勢。雖然使用機器學習庫簡化了實現的複雜性,但背後每個模型的邏輯與機制依然是值得我們深入瞭解的重要內容。

此外,我們學習到,模型的效能不僅依賴於選擇的演算法,還與資料的特性、預處理的質量和引數的調優緊密相關。面對不同的資料集,靈活地選擇適合的分類器和調整其引數,是提升模型效果的關鍵。透過使用Scikit-learn的速查表,我們能夠快速定位到合適的演算法,為實際應用提供了有效的指導。

當然,最後我也想鼓勵大家去看看這個學習平臺,它非常適合新手,提供了豐富的資源和易於理解的教程。


我是努力的小雨,一名 Java 服務端碼農,潛心研究著 AI 技術的奧秘。我熱愛技術交流與分享,對開源社群充滿熱情。同時也是一位騰訊雲創作之星、阿里雲專家博主、華為云云享專家、掘金優秀作者。

💡 我將不吝分享我在技術道路上的個人探索與經驗,希望能為你的學習與成長帶來一些啟發與幫助。

🌟 歡迎關注努力的小雨!🌟

相關文章