上一期【人工智能-16】機器學習:概念、工具介紹、數據集、特征工程
文章目錄
- 一 、KNN算法
- 1. 應用理由
- 2. 原理核心:距離度量 + 多數投票/平均
- 3. 優點和缺點
- 二、模型選擇和調優
- 1.使用理由
- 2.原理核心:數據劃分與性能平均
- 3.超參數搜索
- 4. 應用場景總結
- 三、樸素貝葉斯分類
- 1.使用理由
- 2.原理核心:貝葉斯定理 + 條件獨立假設
- 3.優點和缺點
一 、KNN算法
- KNN 是一種基本的、惰性學習 (Lazy Learning) 的監督學習算法,主要用于分類和回歸任務。
- 核心思想: “物以類聚,人以群分”。對于一個待預測的新樣本,在特征空間中找出與它最相似的 K 個訓練樣本(即“最近鄰”),然后根據這 K 個鄰居的信息來預測新樣本的類別(分類)或值(回歸)。
- 惰性學習: KNN 在訓練階段僅存儲訓練數據集,不進行任何顯式的模型構建。所有的計算(主要是距離計算)都推遲到預測階段進行。
1. 應用理由
- 簡單直觀,易于理解和實現: 算法原理非常直接,沒有復雜的數學推導。
- 無需顯式訓練: 節省了訓練時間(但預測時間可能較長)。
- 非參數方法: 不對數據的基礎分布做任何假設,適用于各種形狀的數據分布。
- 天然支持多分類: 處理多類別問題非常自然。
- 對新的訓練樣本增量更新友好: 只需將新樣本加入存儲的訓練集即可,無需重新訓練整個模型。
- 適用于特征間關系復雜的情況: 只要定義了合適的距離度量,就能工作。
2. 原理核心:距離度量 + 多數投票/平均
- 選擇距離度量: 衡量特征空間中樣本間“相似度”或“距離”。常用距離包括:
- 歐氏距離 (Euclidean Distance): 最常用,計算多維空間中的直線距離。公式核心:各維度差值的平方和再開方。
將x和x1的差值平方加上x和x2的差值的平方,然后對結果開方 - 曼哈頓距離 (Manhattan Distance): 計算各維度絕對差值的總和。對異常值比歐氏距離稍魯棒。
x和x1相減的差的絕對值加上x和x2相減的差的絕對值,最后的和就是曼哈頓距離。 - 閔可夫斯基距離 (Minkowski Distance): 歐氏距離和曼哈頓距離的泛化。
- 余弦相似度 (Cosine Similarity): 衡量向量方向的一致性,常用于文本分類。
- 歐氏距離 (Euclidean Distance): 最常用,計算多維空間中的直線距離。公式核心:各維度差值的平方和再開方。
- 選擇 K 值: 需要人為指定的超參數,表示要考慮的最近鄰的數量。
- 預測階段:
- 分類:
- 計算待預測樣本與訓練集中所有樣本的距離。
- 找出距離最近的 K 個訓練樣本。
- 統計這 K 個鄰居中出現次數最多的類別。
- 將該類別作為待預測樣本的類別(多數投票法)。
- 回歸:
- 計算待預測樣本與訓練集中所有樣本的距離。
- 找出距離最近的 K 個訓練樣本。
- 計算這 K 個鄰居目標值的平均值。
- 將該平均值作為待預測樣本的預測值。
- 分類:
import joblib
from sklearn.neighbors import KNeighborsClassifier
from sklearn.model_selection import train_test_split
from sklearn.datasets import load_iris
from sklearn.preprocessing import StandardScaler# 加載數據集
iris = load_iris()
X = iris.data
y = iris.target
x_train,x_test,y_train,y_test = train_test_split(X,y,train_size=0.8,random_state=22)# 特征工程:標準化
# 之所以只對x進行標準化,是因為要取消x的單位,并使x中過大的特征值不會影響訓練結果
transfer = StandardScaler()
x_train = transfer.fit_transform(x_train)
x_test = transfer.transform(x_test)
# 模型訓練
model = KNeighborsClassifier(n_neighbors=7)
model.fit(x_train,y_train)# 模型評估
y_predict = model.predict(x_test)
print(y_predict)
print(y_test)
print(y_predict == y_test)
# score = np.sum(y_predict == y_test) / len(y_test)
score = model.score(x_test,y_test)
print(score)
# 模型保存
joblib.dump(model,'../src/model/KNN.pkl')
joblib.dump(transfer,'../src/model/transfer.pkl')
# 預測
x_new = [[4.2,2.6,1.8,0.9],[5.2,3.6,1.8,0.9],[1.2,1.6,1.8,2.9]]
x_new = transfer.transform(x_new)
y_new = model.predict(x_new)
print(y_new)
result = iris.target_names[y_new]
print(result)
3. 優點和缺點
- 優點:
- 簡單直觀,易于理解和實現。
- 無需訓練階段(惰性學習)。
- 非參數,對數據分布無假設。
- 天然支持多分類。
- 對新的訓練樣本增量更新友好。
- 缺點:
- 預測階段計算量大,速度慢: 需要計算待測樣本與所有訓練樣本的距離,時間復雜度高。不適合大數據集或實時預測。
- 對特征尺度和相關性敏感: 不同特征的量綱(單位)差異大或特征高度相關時,距離度量會失真。必須進行特征標準化/歸一化。
- 對高維數據效果差(維數災難): 在高維空間中,數據點趨于稀疏,距離度量變得不那么有意義且計算效率更低。
- 需要選擇合適的 K 值和距離度量: K 值選擇對結果影響很大:
- K 太小:模型復雜,對噪聲敏感,容易過擬合(決策邊界崎嶇)。
- K 太大:模型簡單,可能忽略數據局部特征,容易欠擬合(決策邊界平滑)。
- 對不平衡數據集敏感: 多數類容易主導投票結果。
- 存儲開銷大: 需要存儲整個訓練數據集。
所以基本不使用了
二、模型選擇和調優
- 這些是用于評估機器學習模型性能、比較不同模型或算法以及調整模型超參數(如 KNN 中的 K,決策樹的最大深度,SVM 的 C 和 gamma)的關鍵技術。它們的目標是在未見過的數據上獲得對模型泛化能力的可靠估計,避免僅依賴訓練數據評估導致的過度樂觀(過擬合)。
- 核心問題: 如何充分利用有限的數據,既訓練模型又可靠地評估其泛化能力?
- 基本流程: 將數據集劃分為訓練集 (Training Set) 用于模型訓練/參數學習,驗證集 (Validation Set) 用于模型選擇和超參數調優,測試集 (Test Set) 用于最終評估選定模型的泛化能力。交叉驗證方法通過多次劃分來更充分地利用數據。
1.使用理由
- 獲得可靠的泛化性能估計: 防止模型在訓練集上過擬合,評估其在真實未知數據上的表現。
- 模型選擇: 比較不同模型(如邏輯回歸 vs 隨機森林 vs SVM)在相同數據集上的性能,選擇最優模型。
- 超參數調優: 為選定的模型算法,系統地搜索最佳超參數組合(如網格搜索、隨機搜索),避免手動試錯。
- 充分利用有限數據: 特別是在數據集較小時,交叉驗證方法通過多次劃分和平均,比單次留出法提供更穩定、偏差更小的性能估計。
- 減少評估結果的方差: 單次隨機劃分訓練/測試集可能導致評估結果波動較大。交叉驗證通過多次評估取平均來降低這種方差。
2.原理核心:數據劃分與性能平均
- 保留交叉驗證 (Hold-Out Validation / Train-Validation-Test Split):
- 原理: 將原始數據集 一次性 隨機劃分為三個互斥的子集:
- 訓練集 (Training Set): 用于訓練模型(學習模型參數)。
- 驗證集 (Validation Set): 用于在訓練過程中評估模型性能,指導模型選擇或超參數調優。調整模型行為(如選擇超參數)就是基于在驗證集上的表現。
- 測試集 (Test Set): 用于在模型選擇和超參數調優過程完全結束后,對最終選定的模型進行一次性的、無偏的性能評估。測試集在調優過程中絕對不能使用。
- 關鍵點:
- 劃分比例常見如:訓練 60-80%,驗證 10-20%,測試 10-20%。
- 優點: 簡單、快速、計算開銷小。
- 缺點:
- 評估結果高度依賴于單次隨機劃分。如果劃分“不幸運”,評估結果可能不能代表模型真實性能(高方差)。
- 數據利用率低: 用于訓練/調優的數據量減少了(被驗證集和測試集占用)。
- 在小數據集上,驗證集/測試集樣本可能太少,導致評估不穩定。
- 原理: 將原始數據集 一次性 隨機劃分為三個互斥的子集:
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_splitx,y = load_iris(return_X_y=True)
# 劃分為訓練集和測試集 stratify=y 表示訓練集和測試集的標簽分布要一致
x_train,x_test,y_train,y_test = train_test_split(x,y,train_size=0.8,random_state=22,stratify=y)
# 將測試集劃分為測試集和驗證集
x_test,x_val,y_test,y_val = train_test_split(x_test,y_test,train_size=0.5,random_state=22,stratify=y)
print(y_test)
- k 折交叉驗證 (k-Fold Cross-Validation):
- 原理: 解決留出法評估方差大和數據利用率低的問題。
- 將原始數據集隨機劃分為 k 個大小基本相等的互斥子集(稱為“折”或“份”,Folds)。
- 依次進行 k 次訓練和驗證:
- 每次使用 k-1 個折的數據作為訓練集。
- 使用剩下的 1 個折的數據作為驗證集。
- 計算模型在每次驗證集上的性能指標(如準確率、F1)。
- 計算這 k 次性能指標的平均值,作為模型泛化性能的估計。
- 可選: 使用全部數據(k 折都用上了)重新訓練最終模型(使用通過交叉驗證確定的最佳超參數)。
- 獨立的測試集仍然需要用于最終評估(如果可用)。
- 關鍵點:
- k 是超參數,常用值為 5 或 10。
- 優點:
- 顯著降低評估結果的方差(相比單次留出法),結果更穩定可靠。
- 數據利用率高: 每個樣本都被用作驗證集恰好一次,同時有 (k-1)/k 的數據用于訓練。特別適合數據集較小的情況。
- 缺點:
- 計算開銷大: 需要訓練 k 個模型。當 k 很大或模型訓練很慢時,代價高昂。
- 劃分仍是隨機的,如果數據分布有特殊結構(如嚴重類別不平衡),隨機 k 折可能導致某些折中某些類別的樣本極少或缺失。
- 原理: 解決留出法評估方差大和數據利用率低的問題。
# KFold
from sklearn.model_selection import KFoldx,y = load_iris(return_X_y=True)
# KFold(n_splits,shuffle,random_state)
# n_splits:要劃分的折數默認為5 shuffle:是否打亂數據,默認為False random_state:隨機數種子
k = KFold(n_splits=5,shuffle=True,random_state=22)
re = k.split(x,y)
print(next(re))
print(next(re))
- 分層 k 折交叉驗證 (Stratified k-Fold Cross-Validation):
- 原理: 針對分類問題中隨機 k 折可能破壞類別分布的問題。它是 k 折交叉驗證的變體。
- 在劃分每一折時,確保每個折中各個類別的樣本比例與原始數據集中的整體比例盡可能保持一致。
- 關鍵點:
- 優點:
- 保留了 k 折交叉驗證降低方差、高數據利用率的優點。
- 尤其適用于類別不平衡的數據集。能保證每個折都包含所有類別的代表樣本(即使數量很少),使性能評估更公平、更穩定、偏差更小。
- 缺點: 計算開銷同 k 折交叉驗證。主要應用于分類問題,回歸問題有時也可用(保持目標值分布)。
- 優點:
- 原理: 針對分類問題中隨機 k 折可能破壞類別分布的問題。它是 k 折交叉驗證的變體。
from sklearn.model_selection import StratifiedKFoldx,y = load_iris(return_X_y=True)
# StratifiedKFold(n_splits,shuffle,random_state)
k = StratifiedKFold(n_splits=5,shuffle=True,random_state=22)
re = k.split(x,y)
print(next(re))
print(next(re))
3.超參數搜索
超參數搜索也叫網格搜索(Grid Search)
比如在KNN算法中,k是一個可以人為設置的參數,所以就是一個超參數。網格搜索能自動的幫助我們找到最好的超參數值。
class sklearn.model_selection.GridSearchCV(estimator, param_grid)說明:
同時進行交叉驗證(CV)、和網格搜索(GridSearch),GridSearchCV實際上也是一個估計器(estimator),同時它有幾個重要屬性:best_params_ 最佳參數best_score_ 在訓練集中的準確率best_estimator_ 最佳估計器cv_results_ 交叉驗證過程描述best_index_最佳k在列表中的下標
參數:estimator: scikit-learn估計器實例param_grid:以參數名稱(str)作為鍵,將參數設置列表嘗試作為值的字典示例: {"n_neighbors": [1, 3, 5, 7, 9, 11]}cv: 確定交叉驗證切分策略,值為:(1)None 默認5折(2)integer 設置多少折如果估計器是分類器,使用"分層k-折交叉驗證(StratifiedKFold)"。在所有其他情況下,使用KFold。
from sklearn.model_selection import GridSearchCV
from sklearn.neighbors import KNeighborsClassifier
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
x,y = load_iris(return_X_y=True)knn = KNeighborsClassifier(n_neighbors=6)
# GridSearchCV(estimator,param_grid,cv)
# estimator: 模型 param_grid: 參數字典 cv: 確定交叉驗證切分策略,默認5折
model = GridSearchCV(knn,param_grid={'n_neighbors':[1,2,3,4,5,6,7,8,9,10]},cv=5)model.fit(x,y)
print(model.best_params_)
print(model.best_score_)
print(model.best_estimator_ == knn)# 使用模型print(model.predict(x))
4. 應用場景總結
- 保留交叉驗證: 數據集非常大、訓練模型速度慢時,追求快速評估和調優。初步實驗。
實際使用時,一般都用這個方法。至于為什么用,因為數據量太大了,使用這個方法可能都要花費很長的時間,別說k折和分層k折(時間成本和計算資源的花費太大)。跟保留交叉驗證的缺點一對比,還是保留交叉驗證好。 - k 折交叉驗證: 數據集大小適中,需要更穩定、偏差更小的性能評估和超參數調優。
- 分層 k 折交叉驗證: 分類問題,特別是數據集較小或存在明顯類別不平衡時。確
三、樸素貝葉斯分類
- 樸素貝葉斯是一系列基于貝葉斯定理和特征條件獨立假設的簡單概率分類器。
- 核心思想: 計算給定樣本特征條件下,該樣本屬于各個類別的后驗概率,并將樣本分到后驗概率最大的那個類別。
- “樸素 (Naive)” 源于其一個關鍵假設:所有特征在給定類別標簽的條件下是相互獨立的。這個假設在現實中往往不成立,但即使如此,樸素貝葉斯在實踐中常常表現得出乎意料的好。
1.使用理由
- 計算效率極高,訓練和預測速度快: 訓練階段主要計算各種先驗概率和條件概率(計數或估計密度),預測階段只需計算少量概率乘積。非常適合大規模數據集和實時預測。
- 易于實現且效果往往不錯: 算法相對簡單,實現容易。盡管條件獨立假設很強,但在許多實際應用(尤其是文本分類、垃圾郵件過濾)中表現優異。
- 對小規模數據表現良好: 即使訓練數據量較少也能工作,不容易過擬合。
- 能處理多分類問題。
- 提供概率預測: 不僅能給出分類結果,還能給出樣本屬于每個類別的概率估計,這在需要不確定性度量的場景中很有用。
2.原理核心:貝葉斯定理 + 條件獨立假設
- 貝葉斯定理: 核心公式是
P(Y|X) = [P(X|Y) * P(Y)] / P(X)
。Y
:類別變量。X = (X1, X2, ..., Xn)
:特征向量(n 個特征)。P(Y|X)
:后驗概率。即在觀察到特征X
的條件下,樣本屬于類別Y
的概率(我們想求的)。P(Y)
:先驗概率。即在未觀察到任何特征時,樣本屬于類別Y
的概率(根據訓練數據中各類別的頻率估計)。P(X|Y)
:似然 (Likelihood)。即在樣本屬于類別Y
的條件下,觀察到特征X
的概率。P(X)
:證據 (Evidence)。即觀察到特征X
的概率(對所有類別是相同的,在比較不同Y
的后驗概率時可忽略)。
- 目標: 對于給定的樣本特征
X
,找到使其后驗概率P(Y|X)
最大的那個類別Y
(最大后驗估計 - MAP)。 - “樸素”條件獨立假設: 假設所有特征
X1, X2, ..., Xn
在給定類別Y
的條件下相互獨立。這使得復雜的聯合似然P(X1, X2, ..., Xn | Y)
的計算變得簡單:- P(X∣Y)=P(x1,x2,...,xn∣Y)=P(x1∣Y)P(x2∣Y)...P(xn∣Y)P(X|Y) = P(x_1, x_2, ..., x_n|Y) = P(x_1|Y)P(x_2|Y)...P(x_n|Y)P(X∣Y)=P(x1?,x2?,...,xn?∣Y)=P(x1?∣Y)P(x2?∣Y)...P(xn?∣Y)
- 即:聯合似然 = 每個特征條件概率的乘積。
- 分類決策:
- 將貝葉斯定理和條件獨立假設結合:
P(Y∣X)=P(x1∣Y)P(x2∣Y)...P(xn∣Y)P(Y)P(X)P(Y|X) = \frac{P(x_1|Y)P(x_2|Y)...P(x_n|Y)P(Y)}{P(X)}P(Y∣X)=P(X)P(x1?∣Y)P(x2?∣Y)...P(xn?∣Y)P(Y)? - 例:Y是好人,X是高富帥(x1x2x3就分別是高、富、帥)。想要得知高富帥中好人的概率,就要用
好人中長得高的概率
乘以好人中有錢的概率
乘以好人中長得帥的概率
乘以是好人的概率
再除以是高富帥
的概率,這個結果就是在高富帥中是好人
的概率。 - 這里只是舉了一個高富帥中好人的例子,當然也可以算壞人的概率,或者在某種紋理某種顏色某種聲音下是好西瓜的概率。我們都知道了這些概率,那么再有新的數據時根據這些概率選擇計算結果最大的那個類別
Y
作為預測類別。
- 將貝葉斯定理和條件獨立假設結合:
- 估計概率:
- 先驗概率
P(Y)
: 用訓練數據中類別Y
出現的頻率估計:P(Y) = count(Y) / N
(N 是總樣本數)。 - 條件概率
P(Xi | Y)
:- 離散特征: 用類別
Y
的樣本中,特征Xi
取特定值x_i
的頻率估計:P(Xi=x_i | Y) = count(Xi=x_i and Y) / count(Y)
。 - 連續特征: 通常假設特征在給定類別下服從某種分布(如高斯分布),然后使用該類別下的樣本估計分布的參數(如均值和方差),再用概率密度函數計算
P(Xi=x_i | Y)
。常見的是高斯樸素貝葉斯 (Gaussian Naive Bayes)。
- 離散特征: 用類別
- 先驗概率
from sklearn.naive_bayes import MultinomialNB
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_splitx,y = load_iris(return_X_y=True)x_train,x_test,y_train,y_test = train_test_split(x,y,train_size=0.8,random_state=22)
# 由于貝葉斯模型是統計概率來進行預測的,所以不是固定的標簽數據,預測不準確
model = MultinomialNB()
model.fit(x_train,y_train) # 統計先驗概率
print(model.score(x_test,y_test)) # 0.6666666666666666
3.優點和缺點
- 優點:
- 訓練和預測速度極快,計算效率高。
- 實現簡單,易于理解。
- 對小規模數據有效,對缺失數據不太敏感。
- 在多分類問題中表現良好。
- 能夠輸出分類的概率估計。
- 在文本分類(如垃圾郵件檢測、情感分析)等特征維度高且特征獨立假設相對合理的領域表現尤為出色。
- 缺點:
- 核心缺點:“樸素”的條件獨立假設在現實中往往不成立。 特征之間通常存在相關性。違反此假設會降低模型的準確性。
- 概率估計可能不夠準確: 雖然能輸出概率,但基于強獨立性假設得到的概率值可能不太可靠(尤其在特征相關性強時)。
- 零概率問題: 如果測試數據中出現了一個在訓練數據中某個類別下從未出現過的特征值,會導致該特征的條件概率為 0,從而使整個后驗概率為 0。需要使用平滑技術(如拉普拉斯平滑 / Laplace Smoothing / Additive Smoothing)來解決:在計數時給每個特征值的出現次數加一個小的正數(通常為 1)。
- 對輸入數據的分布假設敏感: 對于連續特征,如果選擇的分布(如高斯分布)與真實分布差異很大,會影響性能。
- 特征重要性: 不如決策樹或隨機森林那樣直觀地提供特征重要性排序。