高斯樸素貝葉斯分類的原理解釋和手寫程式碼實現
2022-04-10由 deephub 發表于 農業
數學標準差是什麼
高斯樸素貝葉斯 (GNB) 是一種基於機率方法和高斯分佈的機器學習的分類技術。 高斯樸素貝葉斯假設每個引數(也稱為特徵或預測變數)具有預測輸出變數的獨立能力。 所有引數的預測組合是最終預測,它返回因變數被分類到每個組中的機率,最後的分類被分配給機率較高的分組(類)。
什麼是高斯分佈?
高斯分佈也稱為正態分佈,是描述自然界中連續隨機變數的統計分佈的統計模型。 正態分佈由其鐘形曲線定義, 正態分佈中兩個最重要的特徵是均值 (μ) 和標準差 (σ)。 平均值是分佈的平均值,標準差是分佈在平均值周圍的“寬度”。
重要的是要知道正態分佈的變數 (X) 從 -∞ < X < +∞ 連續分佈(連續變數),並且模型曲線下的總面積為 1。
多分類的高斯樸素貝葉斯
匯入必要的庫:
from random import random
from random import randint
import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib。pyplot as plt
import statistics
from sklearn。model_selection import train_test_split
from sklearn。preprocessing import StandardScaler
from sklearn。naive_bayes import GaussianNB
from sklearn。metrics import confusion_matrix
from mlxtend。plotting import plot_decision_regions
現在建立一個預測變數呈正態分佈的資料集。
#Creating values for FeNO with 3 classes:
FeNO_0 = np。random。normal(20, 19, 200)
FeNO_1 = np。random。normal(40, 20, 200)
FeNO_2 = np。random。normal(60, 20, 200)
#Creating values for FEV1 with 3 classes:
FEV1_0 = np。random。normal(4。65, 1, 200)
FEV1_1 = np。random。normal(3。75, 1。2, 200)
FEV1_2 = np。random。normal(2。85, 1。2, 200)
#Creating values for Broncho Dilation with 3 classes:
BD_0 = np。random。normal(150,49, 200)
BD_1 = np。random。normal(201,50, 200)
BD_2 = np。random。normal(251, 50, 200)
#Creating labels variable with three classes:(2)disease (1)possible disease (0)no disease:
not_asthma = np。zeros((200,), dtype=int)
poss_asthma = np。ones((200,), dtype=int)
asthma = np。full((200,), 2, dtype=int)
#Concatenate classes into one variable:
FeNO = np。concatenate([FeNO_0, FeNO_1, FeNO_2])
FEV1 = np。concatenate([FEV1_0, FEV1_1, FEV1_2])
BD = np。concatenate([BD_0, BD_1, BD_2])
dx = np。concatenate([not_asthma, poss_asthma, asthma])
#Create DataFrame:
df = pd。DataFrame()
#Add variables to DataFrame:
df[‘FeNO’] = FeNO。tolist()
df[‘FEV1’] = FEV1。tolist()
df[‘BD’] = BD。tolist()
df[‘dx’] = dx。tolist()
#Check database:
df
我們的df有 600 行和 4 列。 現在我們可以透過視覺化檢查變數的分佈:
fig, axs = plt。subplots(2, 3, figsize=(14, 7))
sns。kdeplot(df[‘FEV1’], shade=True, color=“b”, ax=axs[0, 0])
sns。kdeplot(df[‘FeNO’], shade=True, color=“b”, ax=axs[0, 1])
sns。kdeplot(df[‘BD’], shade=True, color=“b”, ax=axs[0, 2])
sns。distplot( a=df[“FEV1”], hist=True, kde=True, rug=False, ax=axs[1, 0])
sns。distplot( a=df[“FeNO”], hist=True, kde=True, rug=False, ax=axs[1, 1])
sns。distplot( a=df[“BD”], hist=True, kde=True, rug=False, ax=axs[1, 2])
plt。show()
透過人肉的檢查,資料似乎接近高斯分佈。 還可以使用 qq-plots仔細檢查:
from statsmodels。graphics。gofplots import qqplot
from matplotlib import pyplot
#q-q plot:
fig, axs = pyplot。subplots(1, 3, figsize=(15, 5))
qqplot(df[‘FEV1’], line=‘s’, ax=axs[0])
qqplot(df[‘FeNO’], line=‘s’, ax=axs[1])
qqplot(df[‘BD’], line=‘s’, ax=axs[2])
pyplot。show()
雖然不是完美的正態分佈,但已經很接近了。下面檢視的資料集和變數之間的相關性:
#Exploring dataset:
sns。pairplot(df, kind=“scatter”, hue=“dx”)
plt。show()
可以使用框線圖檢查這三組的分佈,看看哪些特徵可以更好的區分出類別
# plotting both distibutions on the same figure
fig, axs = plt。subplots(2, 3, figsize=(14, 7))
fig = sns。kdeplot(df[‘FEV1’], hue= df[‘dx’], shade=True, color=“r”, ax=axs[0, 0])
fig = sns。kdeplot(df[‘FeNO’], hue= df[‘dx’], shade=True, color=“r”, ax=axs[0, 1])
fig = sns。kdeplot(df[‘BD’], hue= df[‘dx’], shade=True, color=“r”, ax=axs[0, 2])
sns。boxplot(x=df[“dx”], y=df[“FEV1”], palette = ‘magma’, ax=axs[1, 0])
sns。boxplot(x=df[“dx”], y=df[“FeNO”], palette = ‘magma’,ax=axs[1, 1])
sns。boxplot(x=df[“dx”], y=df[“BD”], palette = ‘magma’,ax=axs[1, 2])
plt。show()
手寫樸素貝葉斯分類
手寫程式碼並不是讓我們重複的製造輪子,而是透過自己編寫程式碼對演算法更好的理解。在進行貝葉斯分類之前,先要了解正態分佈。
正態分佈的數學公式定義了一個觀測值出現在某個群體中的機率:
我們可以建立一個函式來計算這個機率:
def normal_dist(x , mean , sd):
prob_density = (1/sd*np。sqrt(2*np。pi)) * np。exp(-0。5*((x-mean)/sd)**2)
return prob_density
知道正態分佈公式,就可以計算該樣本在三個分組(分類)機率。 首先,需要計算所有預測特徵和組的均值和標準差:
#Group 0:
group_0 = df[df[‘dx’] == 0]print(‘Mean FEV1 group 0: ’, statistics。mean(group_0[‘FEV1’]))
print(‘SD FEV1 group 0: ’, statistics。stdev(group_0[‘FEV1’]))
print(‘Mean FeNO group 0: ’, statistics。mean(group_0[‘FeNO’]))
print(‘SD FeNO group 0: ’, statistics。stdev(group_0[‘FeNO’]))
print(‘Mean BD group 0: ’, statistics。mean(group_0[‘BD’]))
print(‘SD BD group 0: ’, statistics。stdev(group_0[‘BD’]))
#Group 1:
group_1 = df[df[‘dx’] == 1]
print(‘Mean FEV1 group 1: ’, statistics。mean(group_1[‘FEV1’]))
print(‘SD FEV1 group 1: ’, statistics。stdev(group_1[‘FEV1’]))
print(‘Mean FeNO group 1: ’, statistics。mean(group_1[‘FeNO’]))
print(‘SD FeNO group 1: ’, statistics。stdev(group_1[‘FeNO’]))
print(‘Mean BD group 1: ’, statistics。mean(group_1[‘BD’]))
print(‘SD BD group 1: ’, statistics。stdev(group_1[‘BD’]))
#Group 2:
group_2 = df[df[‘dx’] == 2]
print(‘Mean FEV1 group 2: ’, statistics。mean(group_2[‘FEV1’]))
print(‘SD FEV1 group 2: ’, statistics。stdev(group_2[‘FEV1’]))
print(‘Mean FeNO group 2: ’, statistics。mean(group_2[‘FeNO’]))
print(‘SD FeNO group 2: ’, statistics。stdev(group_2[‘FeNO’]))
print(‘Mean BD group 2: ’, statistics。mean(group_2[‘BD’]))
print(‘SD BD group 2: ’, statistics。stdev(group_2[‘BD’]))
現在,使用一個隨機的樣本進行測試:
FEV1 = 2。75
FeNO = 27
BD = 125
#Probability for:
#FEV1 = 2。75
#FeNO = 27
#BD = 125
#We have the same number of observations, so the general probability is: 0。33
Prob_geral = round(0。333, 3)
#Prob FEV1:
Prob_FEV1_0 = round(normal_dist(2。75, 4。70, 1。08), 10)
print(‘Prob FEV1 0: ’, Prob_FEV1_0)
Prob_FEV1_1 = round(normal_dist(2。75, 3。70, 1。13), 10)
print(‘Prob FEV1 1: ’, Prob_FEV1_1)
Prob_FEV1_2 = round(normal_dist(2。75, 3。01, 1。22), 10)
print(‘Prob FEV1 2: ’, Prob_FEV1_2)
#Prob FeNO:
Prob_FeNO_0 = round(normal_dist(27, 19。71, 19。29), 10)
print(‘Prob FeNO 0: ’, Prob_FeNO_0)
Prob_FeNO_1 = round(normal_dist(27, 42。34, 19。85), 10)
print(‘Prob FeNO 1: ’, Prob_FeNO_1)
Prob_FeNO_2 = round(normal_dist(27, 61。78, 21。39), 10)
print(‘Prob FeNO 2: ’, Prob_FeNO_2)
#Prob BD:
Prob_BD_0 = round(normal_dist(125, 152。59, 50。33), 10)
print(‘Prob BD 0: ’, Prob_BD_0)
Prob_BD_1 = round(normal_dist(125, 199。14, 50。81), 10)
print(‘Prob BD 1: ’, Prob_BD_1)
Prob_BD_2 = round(normal_dist(125, 256。13, 47。04), 10)
print(‘Prob BD 2: ’, Prob_BD_2)
#Compute probability:
Prob_group_0 = Prob_geral*Prob_FEV1_0*Prob_FeNO_0*Prob_BD_0
print(‘Prob group 0: ’, Prob_group_0)
Prob_group_1 = Prob_geral*Prob_FEV1_1*Prob_FeNO_1*Prob_BD_1
print(‘Prob group 1: ’, Prob_group_1)
Prob_group_2 = Prob_geral*Prob_FEV1_2*Prob_FeNO_2*Prob_BD_2
print(‘Prob group 2: ’, Prob_group_2)
可以看到,這個樣本具有屬於第 2 組的機率最高。這就是樸素貝葉斯手動計算的的流程,但是這種成熟的演算法可以使用來自 Scikit-Learn 的更高效的實現。
Scikit-Learn的分類器樣例
Scikit-Learn的GaussianNB為我們提供了更加高效的方法,下面我們使用GaussianNB進行完整的分類例項。首先建立 X 和 y 變數,並執行訓練和測試拆分:
#Creating X and y:
X = df。drop(‘dx’, axis=1)
y = df[‘dx’]
#Data split into train and test:
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0。30)
在輸入之前還需要使用 standardscaler 對資料進行標準化:
sc = StandardScaler()
X_train = sc。fit_transform(X_train)
X_test = sc。transform(X_test)
現在構建和評估模型:
#Build the model:
classifier = GaussianNB()
classifier。fit(X_train, y_train)
#Evaluate the model:
print(“training set score: %f” % classifier。score(X_train, y_train))
print(“test set score: %f” % classifier。score(X_test, y_test))
下面使用混淆矩陣來視覺化結果:
# Predicting the Test set results
y_pred = classifier。predict(X_test)
#Confusion Matrix:
cm = confusion_matrix(y_test, y_pred)
print(cm)
透過混淆矩陣可以看到,的模型最適合預測類別 0,但類別 1 和 2 的錯誤率很高。為了檢視這個問題,我們使用變數構建決策邊界圖:
df。to_csv(‘data。csv’, index = False)
data = pd。read_csv(‘data。csv’)
def gaussian_nb_a(data):
x = data[[‘BD’,‘FeNO’,]]。values
y = data[‘dx’]。astype(int)。values
Gauss_nb = GaussianNB()
Gauss_nb。fit(x,y)
print(Gauss_nb。score(x,y))
#Plot decision region:
plot_decision_regions(x,y, clf=Gauss_nb, legend=1)
#Adding axes annotations:
plt。xlabel(‘X_train’)
plt。ylabel(‘y_train’)
plt。title(‘Gaussian Naive Bayes’)
plt。show()
def gaussian_nb_b(data):
x = data[[‘BD’,‘FEV1’,]]。values
y = data[‘dx’]。astype(int)。values
Gauss_nb = GaussianNB()
Gauss_nb。fit(x,y)
print(Gauss_nb。score(x,y))
#Plot decision region:
plot_decision_regions(x,y, clf=Gauss_nb, legend=1)
#Adding axes annotations:
plt。xlabel(‘X_train’)
plt。ylabel(‘y_train’)
plt。title(‘Gaussian Naive Bayes’)
plt。show()
def gaussian_nb_c(data):
x = data[[‘FEV1’,‘FeNO’,]]。values
y = data[‘dx’]。astype(int)。values
Gauss_nb = GaussianNB()
Gauss_nb。fit(x,y)
print(Gauss_nb。score(x,y))
#Plot decision region:
plot_decision_regions(x,y, clf=Gauss_nb, legend=1)
#Adding axes annotations:
plt。xlabel(‘X_train’)
plt。ylabel(‘y_train’)
plt。title(‘Gaussian Naive Bayes’)
plt。show()
gaussian_nb_a(data)
gaussian_nb_b(data)
gaussian_nb_c(data)
透過決策邊界我們可以觀察到分類錯誤的原因,從圖中我們看到,很多點都是落在決策邊界之外的,如果是實際資料我們需要分析具體原因,但是因為是測試資料所以我們也不需要更多的分析。
https://www。overfit。cn/post/0457f85f2c184ff0864db5256654aef1
作者:Carla Martins