Gaussian Naive Bayes, Giải thích

Gaussian Naive Bayes, Giải thích

Nút nguồn: 2021431

Gaussian Naive Bayes, Giải thích
Vùng quyết định của bộ phân loại Bayes ngây thơ Gaussian. Hình ảnh của Tác giả.

 

Tôi nghĩ rằng đây là một điều kinh điển khi bắt đầu sự nghiệp khoa học dữ liệu: Phân loại Naive Bayes. hay đúng hơn là tôi nên nói gia đình của các bộ phân loại Bayes ngây thơ, vì chúng có nhiều hương vị. Ví dụ, có một Bayes ngây thơ đa thức, một Bayes ngây thơ Bernoulli và cũng có một bộ phân loại Bayes ngây thơ Gaussian, mỗi cái chỉ khác nhau ở một chi tiết nhỏ, như chúng ta sẽ tìm hiểu. Các thuật toán Bayes ngây thơ khá đơn giản trong thiết kế nhưng tỏ ra hữu ích trong nhiều tình huống phức tạp trong thế giới thực.

Trong bài viết này, bạn có thể tìm hiểu

  • cách hoạt động của bộ phân loại Bayes ngây thơ,
  • tại sao nên định nghĩa chúng theo cách của chúng và
  • cách triển khai chúng trong Python bằng NumPy.

Bạn có thể tìm thấy mã trên Github của tôi.

Nó có thể giúp một chút để kiểm tra mồi của tôi về thống kê Bayesian Giới thiệu nhẹ nhàng về Suy luận Bayes để làm quen với công thức Bayes. Vì chúng tôi sẽ triển khai trình phân loại theo cách học tuân thủ scikit, nên bạn cũng nên xem bài viết của tôi Xây dựng Hồi quy scikit-learning tùy chỉnh của riêng bạn. Tuy nhiên, chi phí tìm hiểu scikit khá nhỏ và dù sao thì bạn cũng có thể làm theo.

Chúng ta sẽ bắt đầu khám phá lý thuyết đơn giản đến kinh ngạc về phân loại Bayes ngây thơ và sau đó chuyển sang thực hiện.

Chúng ta thực sự quan tâm đến điều gì khi phân loại? Chúng ta đang thực sự làm gì, đầu vào và đầu ra là gì? Đáp án đơn giản:

Cho trước một điểm dữ liệu x, xác suất của x thuộc về một lớp c nào đó là bao nhiêu?

Đó là tất cả những gì chúng tôi muốn trả lời với bất kì phân loại. Bạn có thể trực tiếp lập mô hình tuyên bố này dưới dạng xác suất có điều kiện: p(c|x).

Ví dụ, nếu có

  • lớp 3 c₁c₂c₃
  • gồm 2 tính năng x₁x₂,

kết quả của một bộ phân loại có thể giống như p(c₁|x₁x₂)=0.3, p(c₂|x₁x₂)=0.5 và p(c₃|x₁x₂)=0.2. Nếu chúng tôi quan tâm đến một nhãn duy nhất làm đầu ra, chúng tôi sẽ chọn nhãn có xác suất cao nhất, tức là c₂ với xác suất 50% ở đây.

Trình phân loại Bayes ngây thơ cố gắng tính toán các xác suất này một cách trực tiếp.

Vịnh Naive

Ok, vì vậy đã cho một điểm dữ liệu x, chúng tôi muốn tính toán p(c|x) cho tất cả các lớp và sau đó xuất ra c với xác suất cao nhất. Trong các công thức bạn thường thấy đây là

 

Gaussian Naive Bayes, Giải thích
Hình ảnh của Tác giả.

 

Lưu ý: tối đa p(c|x) trả về xác suất tối đa trong khi argmax p(c|x) trả về c với xác suất cao nhất này.

Nhưng trước khi chúng ta có thể tối ưu hóa p(c|x), chúng ta phải có khả năng tính toán nó. Đối với điều này, chúng tôi sử dụng Định lý Bayes:

 

Gaussian Naive Bayes, Giải thích
Định lý Bayes. Hình ảnh của Tác giả.

 

Đây là phần Bayes của Bayes ngây thơ. Nhưng bây giờ, chúng ta có một vấn đề sau: p(x|c) Và p(c)?

Đây là tất cả những gì về việc đào tạo một bộ phân loại Bayes ngây thơ.

Đào tạo

Để minh họa mọi thứ, chúng ta hãy sử dụng bộ dữ liệu đồ chơi với hai đặc điểm thực x₁x₂và ba lớp c₁c₂c₃ trong những điều sau đây.

 

Gaussian Naive Bayes, Giải thích
Dữ liệu, được trực quan hóa. Hình ảnh của Tác giả.

 

Bạn có thể tạo tập dữ liệu chính xác này thông qua

from sklearn.datasets import make_blobs X, y = make_blobs(n_samples=20, centers=[(0,0), (5,5), (-5, 5)], random_state=0)

Hãy để chúng tôi bắt đầu với xác suất lớp p(c), xác suất mà một số lớp c được quan sát trong tập dữ liệu được dán nhãn. Cách đơn giản nhất để ước tính điều này là chỉ tính tần suất tương đối của các lớp và sử dụng chúng làm xác suất. Chúng tôi có thể sử dụng tập dữ liệu của mình để xem chính xác điều này có nghĩa là gì.

Có 7/20 điểm xếp loại c₁ (màu xanh) trong tập dữ liệu, do đó chúng tôi nói p(c₁)=7/20. Chúng tôi có 7 điểm cho lớp c₂ (màu đỏ) cũng vậy, do đó chúng tôi đặt p(c₂)=7/20. lớp học cuối cùng c₃ (màu vàng) chỉ có 6 điểm, do đó p(c₃)=6/20.

Phép tính xác suất lớp đơn giản này giống như cách tiếp cận khả năng tối đa. Tuy nhiên, bạn cũng có thể sử dụng cái khác trước khi phân phối, nếu bạn thích. Ví dụ: nếu bạn biết rằng tập dữ liệu này không đại diện cho dân số thực vì lớp c₃ sẽ xuất hiện trong 50% trường hợp, sau đó bạn đặt p(c₁)=0.25, p(c₂)=0.25 và p(c₃)=0.5. Bất cứ điều gì giúp bạn cải thiện hiệu suất trên tập kiểm tra.

Bây giờ chúng ta chuyển sang khả năng p(x|c)=p(x₁x₂|c). Một cách tiếp cận để tính toán khả năng này là lọc tập dữ liệu cho các mẫu có nhãn và sau đó cố gắng tìm một bản phân phối (ví dụ: Gaussian 2 chiều) nắm bắt các tính năng x₁x₂.

Thật không may, thông thường, chúng tôi không có đủ mẫu cho mỗi lớp để thực hiện ước tính chính xác về khả năng xảy ra.

Để có thể xây dựng một mô hình mạnh mẽ hơn, chúng tôi thực hiện giả định ngây thơ rằng các tính năng x₁x₂ đang độc lập ngẫu nhiên, được c. Đây chỉ là một cách thú vị để làm cho toán học dễ dàng hơn thông qua

 

Gaussian Naive Bayes, Giải thích
Hình ảnh của tác giả

 

cho mọi lớp học c. Đây là nơi ngây thơ một phần của Bayes ngây thơ đến từ vì phương trình này nói chung không đúng. Tuy nhiên, ngay cả khi đó Bayes ngây thơ vẫn mang lại kết quả tốt, đôi khi nổi bật trong thực tế. Đặc biệt đối với các vấn đề NLP với các tính năng túi từ, Bayes ngây thơ đa thức sẽ tỏa sáng.

Các đối số được đưa ra ở trên là giống nhau đối với bất kỳ trình phân loại Bayes ngây thơ nào mà bạn có thể tìm thấy. Bây giờ nó chỉ phụ thuộc vào cách bạn mô hình hóa p(x₁|c₁), p(x₂|c₁), p(x₁|c₂), p(x₂|c₂), p(x₁|c₃) và p(x₂|c₃).

Nếu các tính năng của bạn chỉ là 0 và 1, bạn có thể sử dụng một Phân phối Bernoulli. Nếu chúng là số nguyên thì a Phân phối đa thức. Tuy nhiên, chúng tôi có các giá trị tính năng thực và quyết định Gaussian phân phối, do đó có tên là Gaussian ngây thơ Bayes. Chúng tôi giả sử các hình thức sau đây

 

Gaussian Naive Bayes, Giải thích
Hình ảnh của Tác giả.

 

Ở đâu μᵢ,ⱼ là giá trị trung bình và σᵢ,ⱼ là độ lệch chuẩn mà chúng ta phải ước tính từ dữ liệu. Điều này có nghĩa là chúng tôi nhận được một ý nghĩa cho mỗi tính năng i kết hợp với một lớp cⱼ, trong trường hợp của chúng tôi 2*3=6 có nghĩa là. Điều tương tự cũng xảy ra với các độ lệch chuẩn. Điều này gọi cho một ví dụ.

Chúng ta hãy thử ước tính μ₂,₁ và σ₂,₁. Bởi vì j=1, chúng tôi chỉ quan tâm đến lớp học c₁, hãy để chúng tôi chỉ giữ các mẫu có nhãn này. Còn các mẫu sau:

# samples with label = c_1 array([[ 0.14404357, 1.45427351], [ 0.97873798, 2.2408932 ], [ 1.86755799, -0.97727788], [ 1.76405235, 0.40015721], [ 0.76103773, 0.12167502], [-0.10321885, 0.4105985 ], [ 0.95008842, -0.15135721]])

Bây giờ, vì i=2 chúng ta chỉ phải xem xét cột thứ hai. μ₂,₁ là giá trị trung bình và σ₂,₁ độ lệch chuẩn cho cột này, nghĩa là μ₂,₁ = 0.49985176 và σ₂,₁ = 0.9789976.

Những con số này có ý nghĩa nếu bạn nhìn lại biểu đồ phân tán từ phía trên. Các tính năng x₂ của các mẫu từ lớp c₁ là khoảng 0.5, như bạn có thể thấy từ hình ảnh.

Chúng tôi tính toán điều này ngay bây giờ cho năm kết hợp khác và chúng tôi đã hoàn thành!

Trong Python, bạn có thể làm như thế này:

from sklearn.datasets import make_blobs
import numpy as np # Create the data. The classes are c_1=0, c_2=1 and c_3=2.
X, y = make_blobs( n_samples=20, centers=[(0, 0), (5, 5), (-5, 5)], random_state=0
) # The class probabilities.
# np.bincounts counts the occurence of each label.
prior = np.bincount(y) / len(y) # np.where(y==i) returns all indices where the y==i.
# This is the filtering step.
means = np.array([X[np.where(y == i)].mean(axis=0) for i in range(3)])
stds = np.array([X[np.where(y == i)].std(axis=0) for i in range(3)])

Chúng tôi nhận

# priors
array([0.35, 0.35, 0.3 ])
# means array([[ 0.90889988, 0.49985176], [ 5.4111385 , 4.6491892 ], [-4.7841679 , 5.15385848]])
# stds
array([[0.6853714 , 0.9789976 ], [1.40218915, 0.67078568], [0.88192625, 1.12879666]])

Đây là kết quả của việc đào tạo một bộ phân loại Bayes ngây thơ Gaussian.

Dự đoán

Công thức dự đoán đầy đủ là

 

Gaussian Naive Bayes, Giải thích
Hình ảnh của Tác giả.

 

Giả sử một điểm dữ liệu mới x*=(-2, 5) vào.

 

Gaussian Naive Bayes, Giải thích
Hình ảnh của Tác giả.

 

Để xem nó thuộc lớp nào, chúng ta hãy tính p(c|x*) cho tất cả các lớp. Từ hình ảnh, nó phải thuộc về lớp c₃ = 2, nhưng hãy xem. Hãy bỏ qua mẫu số p(x) trong một giây. Sử dụng vòng lặp sau để tính toán các đề cử cho j = 1, 2, 3.

x_new = np.array([-2, 5]) for j in range(3): print( f"Probability for class {j}: {(1/np.sqrt(2*np.pi*stds[j]**2)*np.exp(-0.5*((x_new-means[j])/stds[j])**2)).prod()*p[j]:.12f}" )

Chúng tôi nhận

Probability for class 0: 0.000000000263
Probability for class 1: 0.000000044359
Probability for class 2: 0.000325643718

Tất nhiên, những xác suất (chúng ta không nên gọi chúng theo cách đó) đừng cộng lại thành một vì chúng ta đã bỏ qua mẫu số. Tuy nhiên, đây không phải là vấn đề vì chúng ta chỉ cần lấy các xác suất không chuẩn hóa này và chia cho tổng của chúng, sau đó chúng sẽ bằng một. Vì vậy, chia ba giá trị này cho tổng của chúng khoảng 0.00032569, chúng tôi nhận được

 

Gaussian Naive Bayes, Giải thích
Hình ảnh của Tác giả.

 

Một người chiến thắng rõ ràng, như chúng tôi mong đợi. Bây giờ, hãy để chúng tôi thực hiện nó!

Việc triển khai này cho đến nay không hiệu quả, không ổn định về số lượng, nó chỉ phục vụ mục đích giáo dục. Chúng tôi đã thảo luận về hầu hết mọi thứ, vì vậy bây giờ sẽ dễ dàng theo dõi. Bạn có thể bỏ qua tất cả các check chức năng, hoặc đọc bài viết của tôi Xây dựng scikit-learning tùy chỉnh của riêng bạn nếu bạn quan tâm đến chính xác những gì họ làm.

Chỉ cần lưu ý rằng tôi đã thực hiện một predict_proba phương pháp đầu tiên để tính xác suất. phương pháp predict chỉ cần gọi phương thức này và trả về chỉ mục (= lớp) với xác suất cao nhất bằng cách sử dụng hàm argmax (nó lại ở đó!). Lớp chờ các lớp từ 0 đến k-1, ở đâu k là số lớp.

import numpy as np
from sklearn.base import BaseEstimator, ClassifierMixin
from sklearn.utils.validation import check_X_y, check_array, check_is_fitted class GaussianNaiveBayesClassifier(BaseEstimator, ClassifierMixin): def fit(self, X, y): X, y = check_X_y(X, y) self.priors_ = np.bincount(y) / len(y) self.n_classes_ = np.max(y) + 1 self.means_ = np.array( [X[np.where(y == i)].mean(axis=0) for i in range(self.n_classes_)] ) self.stds_ = np.array( [X[np.where(y == i)].std(axis=0) for i in range(self.n_classes_)] ) return self def predict_proba(self, X): check_is_fitted(self) X = check_array(X) res = [] for i in range(len(X)): probas = [] for j in range(self.n_classes_): probas.append( ( 1 / np.sqrt(2 * np.pi * self.stds_[j] ** 2) * np.exp(-0.5 * ((X[i] - self.means_[j]) / self.stds_[j]) ** 2) ).prod() * self.priors_[j] ) probas = np.array(probas) res.append(probas / probas.sum()) return np.array(res) def predict(self, X): check_is_fitted(self) X = check_array(X) res = self.predict_proba(X) return res.argmax(axis=1)

Kiểm tra việc thực hiện

Mặc dù đoạn mã này khá ngắn nhưng vẫn còn quá dài để hoàn toàn chắc chắn rằng chúng tôi không mắc phải bất kỳ lỗi nào. Vì vậy, hãy để chúng tôi kiểm tra giá vé so với bộ phân loại GaussianNB scikit-learning.

my_gauss = GaussianNaiveBayesClassifier()
my_gauss.fit(X, y)
my_gauss.predict_proba([[-2, 5], [0,0], [6, -0.3]])

kết quả đầu ra

array([[8.06313823e-07, 1.36201957e-04, 9.99862992e-01], [1.00000000e+00, 4.23258691e-14, 1.92051255e-11], [4.30879705e-01, 5.69120295e-01, 9.66618838e-27]])

Dự đoán bằng cách sử dụng predict phương pháp là

# my_gauss.predict([[-2, 5], [0,0], [6, -0.3]])
array([2, 0, 1])

Bây giờ, chúng ta hãy sử dụng scikit-learning. Ném vào một số mã

from sklearn.naive_bayes import GaussianNB gnb = GaussianNB()
gnb.fit(X, y)
gnb.predict_proba([[-2, 5], [0,0], [6, -0.3]])

sản lượng

array([[8.06314158e-07, 1.36201959e-04, 9.99862992e-01], [1.00000000e+00, 4.23259111e-14, 1.92051343e-11], [4.30879698e-01, 5.69120302e-01, 9.66619630e-27]])

Các con số trông giống như những con số trong bộ phân loại của chúng tôi, nhưng chúng hơi khác một chút ở một vài chữ số được hiển thị cuối cùng. Chúng tôi có làm gì sai không? Không. Phiên bản scikit-learning chỉ đơn thuần sử dụng một siêu tham số khác var_smoothing=1e-09 . Nếu chúng ta đặt cái này thành không, chúng tôi nhận được chính xác số của chúng tôi. Hoàn hảo!

Hãy xem các khu vực quyết định của bộ phân loại của chúng tôi. Tôi cũng đã đánh dấu ba điểm mà chúng tôi đã sử dụng để thử nghiệm. Một điểm gần biên giới chỉ có 56.9% cơ hội thuộc về loại đỏ, như bạn có thể thấy từ predict_proba đầu ra. Hai điểm còn lại được phân loại với độ tin cậy cao hơn nhiều.

 

Gaussian Naive Bayes, Giải thích

Các khu vực quyết định với 3 điểm mới. Hình ảnh của Tác giả.

 

Trong bài viết này, chúng ta đã tìm hiểu cách hoạt động của bộ phân loại Gaussian ngây thơ Bayes và đưa ra trực giác về lý do tại sao nó được thiết kế theo cách đó — đó là một cách tiếp cận trực tiếp để lập mô hình xác suất quan tâm. So sánh điều này với hồi quy Logistic: ở đó, xác suất được mô hình hóa bằng hàm tuyến tính với hàm sigmoid được áp dụng trên nó. Nó vẫn là một mô hình dễ dàng, nhưng nó không cảm thấy tự nhiên như một bộ phân loại Bayes ngây thơ.

Chúng tôi tiếp tục bằng cách tính toán một số ví dụ và thu thập một số đoạn mã hữu ích trong quá trình thực hiện. Cuối cùng, chúng tôi đã triển khai bộ phân loại Bayes ngây thơ Gaussian hoàn chỉnh theo cách hoạt động tốt với scikit-learning. Điều đó có nghĩa là bạn có thể sử dụng nó trong tìm kiếm đường ống hoặc lưới chẳng hạn.

Cuối cùng, chúng tôi đã thực hiện một kiểm tra nhỏ về sự tỉnh táo bằng cách nhập bộ phân loại Bayes ngây thơ Gaussian của scikit-learning và kiểm tra xem cả hai, bộ phân loại của chúng tôi và scikit-learning đều cho kết quả giống nhau. Thử nghiệm này đã thành công.

 
 
Tiến sĩ Robert Kübler là Nhà Khoa học Dữ liệu tại Publicis Media và Tác giả tại Hướng tới Khoa học Dữ liệu.

 
Nguyên. Đăng lại với sự cho phép.
 

Dấu thời gian:

Thêm từ Xe đẩy