當處理連續型特徵資料時,高斯貝氏分類別(Gaussian Naive Bayes)是最適合的選擇。這種分類別假設特徵在每個類別中都遵循正態分佈。

以下是使用 scikit-learn 實作高斯貝氏分類別的範例:

# 載入必要的函式庫
from sklearn import datasets
from sklearn.naive_bayes import GaussianNB

# 載入資料
iris = datasets.load_iris()
features = iris.data
target = iris.target

# 建立高斯貝氏分類別物件
classifier = GaussianNB()

# 訓練模型
model = classifier.fit(features, target)

這段程式碼首先從 scikit-learn 載入 iris 資料集,這是一個經典的分類別題資料集,包含三種不同品種的鳶尾花測量資料。接著我們建立了 GaussianNB 分類別物件,並使用 fit 方法訓練模型。高斯貝氏分類別特別適合處理連續特徵資料,如這裡的花瓣長度、寬度等測量值。

高斯貝氏分類別的數學原理與應用

高斯貝氏分類別的核心假設是特徵值 $x$ 在給定類別 $y$ 的條件下遵循正態分佈:

p(x_j|y) = \frac{1}{\sqrt{2\pi\sigma_y^2}}e^{-\frac{(x_j-\mu_y)^2}{2\sigma_y^2}}

其中 \sigma_y^2\mu_y 分別是類別 y 中特徵 x_j 的方差和平均值。由於這種正態分佈的假設,高斯貝氏分類別最適合用於所有特徵都是連續值的情況。

在實際應用中,我們可以使用訓練好的模型來預測新觀測值的類別:

# 建立新的觀測值
new_observation = [[4, 4, 4, 0.4]]

# 預測類別
predicted_class = model.predict(new_observation)
print(predicted_class)  # 輸出: [1]

這段程式碼展示瞭如何使用已訓練的模型對新資料進行預測。我們建立了一個新的觀測值(一朵未知品種的鳶尾花的測量資料),然後使用 predict 方法預測其品種。結果顯示預測類別為 1,對應於 iris 資料集中的第二個品種。

高斯貝氏分類別的一個有趣特性是允許我們為各個目標類別指定先驗信念。我們可以使用 GaussianNB 的 priors 引數來實作:

# 建立具有自定義先驗機率的高斯貝氏分類別
clf = GaussianNB(priors=[0.25, 0.25, 0.5])

# 訓練模型
model = clf.fit(features, target)

在這個例子中,我們指定了三個類別的先驗機率分別為 0.25, 0.25 和 0.5。這表示在看到任何資料前,我們認為第三類別機率是前兩類別兩倍。如果不指定 priors 引數,分類別會根據資料自動調整先驗機率。

值得注意的是,高斯貝氏分類別輸出的原始預測機率(透過 predict_proba 方法獲得)並不是校準過的。這意味著這些機率值不應被視為真實機率。如果需要獲得可靠的預測機率,我們需要使用等渦迴歸(isotonic regression)或相關方法進行校準,這點我將在後面詳細討論。

離散與計數特徵的多項式貝氏分類別

處理離散與計數資料的方法

當面對離散特徵或計數資料時,多項式貝氏分類別(Multinomial Naive Bayes)是更合適的選擇。這種分類別假設特徵遵循多項式分佈,特別適合處理如文字分類別問題。

下面是使用多項式貝氏分類別的範例:

# 載入必要的函式庫
import numpy as np
from sklearn.naive_bayes import MultinomialNB
from sklearn.feature_extraction.text import CountVectorizer

# 建立文字資料
text_data = np.array(['I love Brazil. Brazil!',
                      'Brazil is best',
                      'Germany beats both'])

# 建立詞袋模型
count = CountVectorizer()
bag_of_words = count.fit_transform(text_data)

# 建立特徵矩陣
features = bag_of_words.toarray()

# 建立目標向量
target = np.array([0, 0, 1])

# 建立具有自定義先驗機率的多項式貝氏分類別
classifier = MultinomialNB(class_prior=[0.25, 0.5])

# 訓練模型
model = classifier.fit(features, target)

這段程式碼示範瞭如何使用多項式貝氏分類別處理文字資料。首先我們建立一個簡單的文字資料集,包含三個句子,其中前兩個與巴西有關,最後一個與德國有關。接著使用 CountVectorizer 將這些文字轉換為詞袋模型(每個單詞出現的次數)。然後建立目標向量,將前兩個句子標記為類別 0(親巴西),最後一個句子標記為類別 1(親德國)。最後我們建立並訓練了一個多項式貝氏分類別,並指定了兩個類別的先驗機率。

多項式貝氏分類別的應用場景

多項式貝氏分類別的工作原理與高斯貝氏分類別,但它假設特徵遵循多項式分佈。在實踐中,這意味著這種分類別常用於處理離散資料(如電影評分從 1 到 5)。

其中一個最常見的應用是使用詞袋模型或 TF-IDF 方法進行文字分類別在我們的例子中,我們建立了一個玩具文字資料集,將文字串轉換為詞袋特徵矩陣和相應的目標向量。

與高斯貝氏分類別一樣,我們可以使用 fit 方法訓練模型,並使用 predict 方法預測新觀察值的類別:

# 建立新的觀測值
new_observation = [[0, 0, 0, 1, 0, 1, 0]]

# 預測新觀測值的類別
predicted_class = model.predict(new_observation)
print(predicted_class)  # 輸出: [0]

這段程式碼展示瞭如何使用已訓練的多項式貝氏分類別對新文字進行分類別新觀測值是一個詞袋向量,代表一個新句子中各單詞的出現次數。模型預測這個新句子屬於類別 0(親巴西)。

如果未指定 class_prior 引數,先驗機率將根據訓練資料自動學習。如果希望使用均勻分佈作為先驗,可以設定 fit_prior=False。

多項式貝氏分類別還有一個加性平滑超引數 alpha,需要透過調參技術來最佳化預設值為 1.0,而 0.0 表示不進行平滑處理。平滑處理對於處理訓練集中未出現的特徵非常重要,可以避免因為零機率而導致的計算問題。

二元特徵的伯努利貝氏分類別

二元特徵分類別解決方案

當我們的資料由二元特徵組成時,伯努利貝氏分類別(Bernoulli Naive Bayes)是最適合的選擇。這種分類別假設所有特徵都是二元的,即它們只有兩種可能的值(例如,特徵存在或不存在)。

下面是使用伯努利貝氏分類別的範例:

# 載入必要的函式庫
import numpy as np
from sklearn.naive_bayes import BernoulliNB

# 建立三個二元特徵
features = np.random.randint(2, size=(100, 3))

# 建立二元目標向量
target = np.random.randint(2, size=(100, 1)).ravel()

# 建立具有自定義先驗機率的伯努利貝氏分類別
classifier = BernoulliNB(class_prior=[0.25, 0.5])

# 訓練模型
model = classifier.fit(features, target)

這段程式碼示範了伯努利貝氏分類別的基本用法。我們首先建立了一個隨機的二元特徵矩陣,包含 100 個樣本,每個樣本有 3 個特徵,值為 0 或 1。然後建立一個隨機的二元目標向量,也是由 0 和 1 組成。接著建立一個伯努利貝氏分類別,指定兩個類別的先驗機率為 0.25 和 0.5。最後訓練模型。

伯努利貝氏分類別的特性與應用

伯努利貝氏分類別假設所有特徵都是二元的,例如它們只能取兩個值(如經過獨熱編碼的名義類別特徵)。與它的多項式表親一樣,伯努利貝氏分類別

預測機率校準:提升機器學習模型可靠性的關鍵技術

在機器學習中,分類別輸出的原始預測機率往往不能直接反映真實情況。這是因為某些演算法(如決策樹、SVM或樸素貝葉斯)會產生偏離實際可能性的機率值。當我研究機器學習模型在實際應用場景中的表現時,發現未經校準的機率可能導致決策失誤,尤其在風險評估或資源分配等關鍵場景中。

為何需要機率校準?

原始模型輸出的機率值通常存在以下問題:

  1. 極端化傾向 - 某些模型(如樸素貝葉斯)傾向於產生接近0或1的極端機率
  2. 缺乏可靠性 - 機率值與實際結果頻率不比對
  3. 決策偏差 - 未校準的機率會導致根據閾值的決策出現系統性偏差

使用scikit-learn實作機率校準

在scikit-learn中,可以使用CalibratedClassifierCV類別產生經過良好校準的預測機率。這個類別用k折交叉驗證的方式來校準機率值:

# 匯入必要的函式庫
from sklearn.naive_bayes import GaussianNB
from sklearn.calibration import CalibratedClassifierCV
import numpy as np

# 建立基礎分類別
base_classifier = GaussianNB()

# 建立校準分類別
calibrated_classifier = CalibratedClassifierCV(
    base_classifier, 
    method='sigmoid',  # 使用Platt's sigmoid方法
    cv=5  # 5折交叉驗證
)

# 擬合模型
calibrated_classifier.fit(features, target)

# 預測校準後的機率
calibrated_probs = calibrated_classifier.predict_proba(new_observation)

上面的程式碼展示瞭如何使用scikit-learn的CalibratedClassifierCV類別校準機率。這裡我們選擇了高斯樸素貝葉斯作為基礎分類別,然後使用Platt’s sigmoid方法進行校準。cv=5引數指定了使用5折交叉驗證,這意味著資料會被分成5份,每次使用4份訓練模型,剩下的1份用於校準機率。最終輸出的機率是所有折疊的平均結果。

校準前後的機率差異

來看一個實際例子,比較校準前後的機率差異:

# 未校準的高斯樸素貝葉斯預測機率
classifier.fit(features, target).predict_proba(new_observation)
# 輸出: array([[ 2.58229098e-04, 9.99741447e-01, 3.23523643e-07]])

# 校準後的預測機率
classifier_sigmoid.predict_proba(new_observation)
# 輸出: array([[ 0.31859969, 0.63663466, 0.04476565]])

從上面的結果可以看出,未校準的樸素貝葉斯分類別給出了非常極端的機率估計 - 第二個類別的機率接近100%,而其他類別幾乎為0。這是樸素貝葉斯的典型特徵,因為它假設特徵間條件獨立,這在實際資料中通常不成立,導致機率估計過於自信。

相比之下,校準後的機率分佈更加平滑合理,第二個類別的機率降至約64%,第一個類別有約32%的機率,第三個類別有約4.5%的機率。這種較為平衡的機率分佈通常能更好地反映真實的不確定性。

校準方法選擇

CalibratedClassifierCV提供了兩種校準方法:

  1. Platt’s sigmoid模型 (method='sigmoid') - 使用邏輯迴歸函式將原始分數對映到校準機率
  2. 等分迴歸 (method='isotonic') - 非引數技術,使用分段常數函式進行校準

選擇哪種方法取決於資料量和分佈特性:

  • 當樣本量較小(如少於100筆觀測值)時,等分迴歸容易過擬合,此時Platt’s sigmoid模型更適合
  • 對於較大的資料集,等分迴歸通常表現較好,因為它不依賴於特定的函式形式

在我的實踐中,處理中小型資料集時通常選擇sigmoid方法,而處理大型資料集時則傾向於使用等分迴歸。例如,在處理Iris資料集(僅有150個樣本)時,sigmoid方法是更穩健的選擇。

無監督學習:聚類別演算法探索

在機器學習領域中,我們經常面臨這樣的情況:手上有大量資料,但缺乏標籤訊息。例如,我想分析購物行為但不知道哪些客戶是會員、哪些不是。這時,監督學習無法應用,而無監督學習中的聚類別演算法就能派上用場。

聚類別核心思想

聚類別演算法的目標是識別資料中潛在的分組,將相似的觀測值聚集在一起。如果會員和非會員的購物行為確實存在差異,那麼平均而言,兩個會員之間的行為差異應該小於會員與非會員之間的差異。換句話說,資料中應該存在明顯的分群。

K-means聚類別最常用的聚類別法

K-means是最流行的聚類別演算法之一,它嘗試將觀測值分成k個組,每個組內的方差相近。

# 匯入必要的函式庫
from sklearn import datasets
from sklearn.preprocessing import StandardScaler
from sklearn.cluster import KMeans

# 載入資料
iris = datasets.load_iris()
features = iris.data

# 標準化特徵
scaler = StandardScaler()
features_std = scaler.fit_transform(features)

# 建立k-means物件
cluster = KMeans(n_clusters=3, random_state=0, n_jobs=-1)

# 訓練模型
model = cluster.fit(features_std)

這段程式碼展示瞭如何使用scikit-learn實作K-means聚類別我們首先載入經典的Iris花卉資料集,然後使用StandardScaler對特徵進行標準化,這是K-means的重要前處理步驟,因為K-means對特徵尺度很敏感。

接著建立KMeans物件,設定群集數量n_clusters=3(因為Iris資料集有3種花),random_state=0確保結果可重現,n_jobs=-1則利用所有可用CPU核心加速計算。最後使用fit方法訓練模型。

K-means演算法的工作原理

K-means的運作過程可以概括為以下步驟:

  1. 隨機選擇k個點作為聚類別心
  2. 對每個觀測值:
    • 計算該觀測值與每個聚類別心的距離
    • 將觀測值分配給最近的聚類別心
  3. 將每個聚類別心移動到其所屬群集的均值位置
  4. 重複步驟2和3,直到沒有觀測值改變所屬群集為止

K-means的關鍵假設

在使用K-means時,需要注意以下三個關鍵假設:

  1. 群集呈凸形(如圓形、球形)
  2. 所有特徵具有相同的尺度(這就是為什麼我們需要標準化)
  3. 各群集大小相近(即觀測值數量均衡)

如果這些假設無法滿足,可能需要考慮其他聚類別法。

分析聚類別果

訓練完成後,我們可以檢視每個觀測值的預測類別:

# 檢視預測的類別
model.labels_

對於Iris資料集,我們可以將預測結果與真實類別比較:

# 檢視真實類別
iris.target

雖然標籤值不同(因為聚類別法產生的標籤是任意的),但K-means的分組結果與實際花種類別相當接近。這說明K-means能有效捕捉資料的自然分組結構。

使用聚類別型進行預測

訓練好的聚類別型可以用來預測新觀測值的群集歸屬:

# 建立新觀測值
new_observation = [[0.8, 0.8, 0.8, 0.8]]

# 預測觀測值的群集
model.predict(new_observation)
# 輸出: array([0], dtype=int32)

這個例子展示瞭如何使用訓練好的K-means模型對新資料進行預測。新觀測值會被分配到距離最近的聚類別心所代表的群集。每個聚類別心代表了該群集的「平均」特徵值。

我們可以檢視每個聚類別中心點:

# 檢視聚類別心
model.cluster_centers_

這些中心點的坐標反映了每個群集的核心特徵。在實際應用中,分析這些中心點有助於理解不同群集的特性差異。

提升K-means聚類別率:Mini-Batch K-means

當處理大型資料集時,標準K-means可能會變得非常耗時。這時可以使用Mini-Batch K-means來加速聚類別程:

# 匯入必要的函式庫
from sklearn.cluster import MiniBatchKMeans

# 建立mini-batch k-means物件
cluster = MiniBatchKMeans(n_clusters=3, random_state=0, batch_size=100)

# 訓練模型
model = cluster.fit(features_std)

Mini-Batch K-means是標準K-means的變體,主要差異在於計算過程中只使用隨機抽樣的觀測值子集,而不是所有觀測值。這種方法可以顯著減少演算法達到收斂所需的時間,同時只犧牲很小的聚類別量。

batch_size=100引數指定了每次迭代使用的觀測值數量。對於大型資料集,這個方法可以將計算時間從小時級別減少到分鐘級別,使得在資源有限的環境中也能高效處理大型聚類別題。

Mini-Batch K-means的優缺點

優點

  • 計算速度快,特別適合大型資料集
  • 記憶體求低,可以處理不適合記憶體資料集
  • 結果通常與標準K-means相近

缺點

  • 聚類別量可能略低於標準K-means
  • 收斂性稍差,可能需要更多迭代
  • 對初始聚類別心的選擇更敏感

在我的資料分析實踐中,當處理包含數十萬或更多觀測值的資料集時,Mini-Batch K-means是我的首選,因為它能在可接受的時間內提供良好的聚類別果。對於中小型資料集,標準K-means通常是更好的選擇,因為它能提供更穩定的聚類別果。

在機器學習模型佈署中,機率校準是一個常被忽視但極為重要的步驟。未經校準的機率可能導致錯誤的決策,特別是在需要精確風險評估的場景中。透過使用CalibratedClassifierCV,我們可以顯著改善模型輸出機率的可靠性,從而提高根據這些機率的決策品質。

聚類別法則提供了一種強大的無監督學習方法,可以在沒有標籤的情況下發現資料中的自然分組。K-means因其簡單性和有效性成為最廣泛使用的聚類別法之一,而Mini-Batch K-means則為處理大型資料集提供了高效的解決方案。

在實際應用中,選擇適當的聚類別法和引數(如群集數量k)至關重要。通常需要結合領域知識和評估指標(如輪廓係數)來確定最佳設定。無論是機率校準還是聚類別析,都是資料科學工具箱中不可或缺的工具,能夠幫助我們從資料中提取更有價值的訊息。

進階叢集技術:超越K-means的資料分群方法

在進入機器學習領域後,K-means通常是我們接觸的第一個叢集演算法。然而,它的限制也相當明顯:需要預先指定叢集數量、假設叢集呈現球形,與對異常值敏感。當面對形狀不規則、密度變化大的資料時,我們需要更先進的叢集技術。

在本文中,我將介紹幾種強大的叢集演算法,它們能夠克服K-means的侷限,在各種複雜資料集上提供更優質的分群結果。從自動決定叢集數量的MeanShift,到能夠識別高密度區域的DBSCAN,再到建立叢集階層的凝聚式叢集,這些技術各有所長,適用於不同場景。

MiniBatchKMeans:K-means的高效變體

在探討其他演算法前,值得一提的是K-means的一個高效變體:MiniBatchKMeans。這個演算法保留了K-means的核心思想,但引入了批次處理機制,大幅提升了運算效率。

MiniBatchKMeans的關鍵在於batch_size引數,它控制每批次隨機選取的觀測數量。這個引數存在明顯的權衡關係:較大的批次能提供更穩定的叢集結果,但計算成本也更高;較小的批次雖然速度更快,但結果可能不如標準K-means穩定。

在處理大規模資料集時,MiniBatchKMeans可以將訓練時間縮短數十倍,同時保持接近標準K-means的叢集品質。我在處理百萬級別的電子商務使用者為資料時,發現將batch_size設為總資料量的1%左右,能在效率和準確性之間取得良好平衡。

MeanShift叢集:自動發現資料中的高密度區域

問題情境

假設你正在分析客戶購物行為資料,但不確定應該將客戶分成多少群體,也不想對這些群體的形狀做出假設。傳統的K-means要求你預先指定叢集數量,這在探索性分析階段可能並不合適。

解決方案:MeanShift叢集

MeanShift演算法能夠自動識別資料中的高密度區域,無需預先指定叢集數量:

# 載入必要函式庫
from sklearn import datasets
from sklearn.preprocessing import StandardScaler
from sklearn.cluster import MeanShift

# 載入資料
iris = datasets.load_iris()
features = iris.data

# 標準化特徵
scaler = StandardScaler()
features_std = scaler.fit_transform(features)

# 建立MeanShift物件
cluster = MeanShift(n_jobs=-1)

# 訓練模型
model = cluster.fit(features_std)

這段程式碼展示了MeanShift叢集的基本應用流程:

  1. 首先載入鳶尾花資料集作為示範
  2. 使用StandardScaler進行特徵標準化,這對於MeanShift特別重要,因為它根據距離度量
  3. 建立MeanShift叢集器,設定n_jobs=-1以使用所有可用CPU核心加速計算
  4. 使用fit方法訓練模型,演算法會自動決定叢集數量和形狀

MeanShift的工作原理與應用

MeanShift的概念雖簡單,但解釋起來有些抽象。以一個比喻來說明:想像一個籠罩在濃霧中的足球場(二維特徵空間),場上站著100個人(我們的觀測值)。由於能見度有限,每個人只能看到很短的距離內的情況。

每分鐘,每個人都會環顧四周,並朝著他們能看到的人最多的方向走一步。隨著時間推移,人們開始聚集在一起,形成越來越大的群體。最終結果是場上形成了幾個人群集中的區域。每個人被分配到他們最終所在的叢集中。

scikit-learn的MeanShift實作比這個比喻更為複雜,但基本邏輯相同。它有兩個重要引數需要了解:

  1. bandwidth:設定觀測值用來確定移動方向的區域(核心)半徑。在我們的比喻中,這相當於一個人能在濃霧中看多遠。預設情況下,演算法會自動估算一個合理的bandwidth值(但會顯著增加計算成本)。

  2. cluster_all:有時在MeanShift中,某些觀測值的核心內可能沒有其他觀測值(就像足球場上有些人看不到任何其他人)。預設情況下,MeanShift會將這些"孤兒"觀測值分配到最近觀測值的核心中。但如果我們設定cluster_all=False,這些孤兒觀測值會被標記為-1,表示它們不屬於任何叢集。

MeanShift的優勢在於它能夠找到任意形狀的叢集,與無需預先指定叢集數量。然而,它的主要缺點是計算成本較高,尤其是在高維度資料上。在實際應用中,當資料集規模超過數萬筆記錄時,MeanShift的執行時間會變得相當長。

DBSCAN:識別高密度區域的叢集技術

問題情境

你正在分析地理位置資料,希望找出人口密集的區域,這些區域可能呈現不規則形狀,與資料中可能存在噪聲點(如錯誤記錄的位置)。

解決方案:DBSCAN叢集

DBSCAN(Density-Based Spatial Clustering of Applications with Noise)是一種根據密度的叢集演算法,特別適合發現任意形狀的叢集,同時能夠識別噪聲點:

# 載入必要函式庫from sklearn import datasets
from sklearn.preprocessing import StandardScaler
from sklearn.cluster import DBSCAN

# 載入資料
iris = datasets.load_iris()
features = iris.data

# 標準化特徵
scaler = StandardScaler()
features_std = scaler.fit_transform(features)

# 建立DBSCAN物件
cluster = DBSCAN(eps=0.3, min_samples=5, n_jobs=-1)

# 訓練模型
model = cluster.fit(features_std)

# 檢視叢集標籤
print(model.labels_)

這段程式碼展示了DBSCAN叢集的實作過程:

  1. 與之前類別,首先載入並標準化鳶尾花資料
  2. 建立DBSCAN叢集器,設定兩個關鍵引數:eps(鄰域半徑)和min_samples(成為核心點的最小鄰居數)
  3. 訓練模型並檢視叢集標籤,其中-1表示噪聲點(離群值)

DBSCAN的原理與引數調整

DBSCAN的核心思想是識別資料中的高密度區域。它根據以下步驟運作:

  1. 隨機選擇一個未被存取的觀測值x_i
  2. 如果x_i有至少min_samples個距離小於eps的鄰居,則將其視為叢集的一部分
  3. 對x_i的所有鄰居、鄰居的鄰居等遞迴重複步驟2,這些被視為叢集的核心樣本
  4. 當步驟3無法找到更多近鄰觀測值時,重新選擇一個未存取的點(回到步驟1)

完成後,我們得到一系列叢集的核心樣本。最後,任何靠近叢集但不是核心樣本的觀測值被視為叢集的一部分,而不靠近任何叢集的觀測值被標記為離群值。

DBSCAN有三個主要引數需要設定:

  • eps:觀測值之間被視為鄰居的最大距離。這個引數決定了我們如何定義"近"
  • min_samples:一個觀測值要成為核心點所需的最小鄰居數量
  • metric:計算距離的方式,如歐幾裡德距離(euclidean)或曼哈頓距離(manhattan)

在實際應用中,eps和min_samples的選擇至關重要。如果eps太小或min_samples太大,大多數點會被標記為噪聲;相反,如果eps太大或min_samples太小,不同叢集可能會被錯誤地合併在一起。

我通常使用k-距離圖(k-distance graph)來幫助確定適當的eps值:計算每個點到其第k個最近鄰的距離(其中k=min_samples),然後繪製這些距離的排序圖。圖中的"拐點"通常是eps的好選擇。

DBSCAN的優勢在於它能夠發現任意形狀的叢集,識別噪聲點,與不需要預先指定叢集數量。它特別適合空間資料集,如地理位置資料或影畫素分群。然而,它在處理不同密度的叢集時可能表現不佳,因為全域eps引數無法適應區域性密度變化。