樸素貝葉斯分類器
- 樸素貝葉斯分類器
-
- 數學原理
- python實作
- 執行個體(基于scikit-learn)
-
- kaggle上的泰坦尼克幸存者預測
- 新聞主題分類
樸素貝葉斯分類器
貝葉斯分類器是一類分類算法的總稱,這類算法均以貝葉斯定理作為基礎。
數學原理
貝葉斯方法最早由英國牧師托馬斯·貝葉斯在《論有關機遇問題的求解》中提出一種歸納推理的理論,當時并沒有被數學界普遍接受。到了20世紀中葉,在傳統統計學出現困難的時候,貝葉斯方法被重新提出,并發展成為一種新的統計學。有别于傳統統計學,貝葉斯統計學引入了先驗機率分布這一概念,在統計學模型中更加注重人的主觀判斷。例如,對于一個每天都要品茶的女士來說,他能分辨出茶中是先加的牛奶還是先加的茶葉的機率要比不喝茶的人要高得多。在統計模型中加入先驗機率分布,在處理小樣本資料時往往會有更好的表現。
貝葉斯分類器在數學上主要是基于貝葉斯公式。貝葉斯公式的推導過程:
聯合機率:

于是就有:
将貝葉斯公式用于分類問題,我們有
我們最終是想求得基于給定的特征下,目标資料屬于某一類别的機率p(類别|特征)。然後,我們比較他屬于各類别機率的大小,認為他應歸類到機率最大的類别。可以看出,貝葉斯分類器的本質就是最大後驗機率估計。
在實際計算中,因為所有的p(特征)都是一樣的,是以在實際計算中我們隻需要計算聯合機率暨p(特征|類别)p(類别)的大小。
以上是基于一個特征進行分類的原理,同樣的在基于多個特征進行分類的時候我們有
其中,c表示類别,x1、x2、…、xn表示樣本提供的n個特征。
由于上式子中分母的都一樣,隻需要比較分子的大小。但實際上p(x1,x2,…,xn)仍舊比較難直接求出。于是在樸素貝葉斯中引入了一個很強的假設,假設所有的特征x1、x2、…、xn互相獨立。于是我們有
樸素貝葉斯分類器适用于有監督學習的分類問題。優點是簡單易懂、學習效率高,在某些領域分類問題中能出現很好的結果。缺點是自變量之間的獨立性假設在現實中很難滿足;連續變量的正态性假設也會對結果的精度産生影響。
python實作
介紹完上面的數學理論,下面我們用python動手寫一個樸素貝葉斯分類器。
#-*- coding:utf-8 -*-
import numpy as np
def NaiveBayes(traindata, trainlabel):
classes = 10 #類别數
features = 784 #樣本次元
sampleNum = trainlabel.shape[0]
#計算p(c)
Pc = np.zeros((classes, 1))
for c in range(classes):
c_i = (trainlabel == c) #統計标簽中類别c的樣本數量
c_i_num = np.sum(c_i)
Pc[c] = (c_i_num+1)/sampleNum #laplace校準
Pc = np.log(Pc)
#計算p(x|c)
y_num = 2 #每個特征可能的取值個數
c_f_y_count = np.zeros((classes, feature, y_num)) #統計每個類别每個特征的每種可能出現次數
for k in range(sampleNum):
c = trainlabel[k]
data = traindata[k]
for f in range(featrues):
y = data[f]
c_f_y_count[c][f][y] += 1
Px_c = np.zeros((classes, featrues, y_num)) #統計每個類别每個特征的每種可能取值的機率
for c in range(classes):
for f in range(features):
c_f_y_num = np.sum(c_f_y_count[c][f])
for y in range(y_num):
Px_c[c][f][y] = np.log((c_f_y_count[c][f][y]+1)/c_f_y_num)
return Pc, Px_c
def predict(Pc, Px_c, x):
classes = 10
features = 784
Pc_x = [0]*classes #記錄每個類别的後驗機率
for c in range(classes):
Px_c_sum = 0
for f in range(features):
Px_c_sum += Px_c[c][f][x[f]] #對機率值取log 連乘變成了求和運算
Pc_x[c] = Px_c_sum + Pc[c]
pre_c = Pc_x.index(max(Pc_x)) #找到每個類别的後驗機率中的最大值對應的類别
return pre_c
def test(Pc, Px_c, testdata, testlabel):
sampleNum = testlabel.shape[0]
count = 0.0
for i in range(sampleNum):
data = testdata[i]
label = testlabel[i]
pre_label = predict(Pc, Px_c, data)
if(pre_label == label):
count += 1
acc = count/sampleNum
return acc
if __name__ == '__main__':
traindata,trainlabel = loadData('../Mnist/mnist_train.csv')
evaldata,evallabel = loadData('../Mnist/mnist_test.csv')
Pc,Px_c = NaiveBayes(traindata,trainlabel)
accuracy = test(Pc, Px_c, evaldata, evallabel)
print('accuracy rate is:',accuracy)
執行個體(基于scikit-learn)
kaggle上的泰坦尼克幸存者預測
kaggle.com目前将泰坦尼克号ML競賽作為熟悉 Kaggle 平台工作原理的最佳挑戰。此項比賽會不停地重開,以便帶領新人熟悉kaggle平台,同時泰坦尼克号幸存者預測也一個經典的機器學習分類的應用場景。
競賽的目的很簡單:使用機器學習建立一個模型,預測哪些乘客在泰坦尼克号沉船事件中能幸存下來。資料集的下載下傳位址:
https://www.kaggle.com/c/titanic/data
使用貝葉斯分類器預測代碼如下:
# -*- coding:utf-8 -*-
import numpy as np
import pandas as pd
import matplotlib.pylab as plt
from sklearn.preprocessing import StandardScaler
from sklearn.naive_bayes import BernoulliNB #伯努利模型
#讀入資料
datatrain = pd.read_csv('train.csv')
datatest = pd.read_csv('test.csv')
#去掉幾種無用特征
datatrain = datatrain.drop(labels=['PassengerId', 'Name', 'Ticket', 'Cabin'], axis=1)
datatest = datatest.drop(labels=['PassengerId', 'Name', 'Ticket', 'Cabin'], axis=1)
#去除缺失值
datatrain = datatrain.dropna()
#填補測試集的缺失值
datatest = datatest.fillna(datatest.mean()['Age':'Fare'])
#屬性轉化為數值型
datatrain_dummy = pd.get_dummies(datatrain[['Sex', 'Embarked']])
datatest_dummy = pd.get_dummies(datatest[['Sex', 'Embarked']])
#編碼後和資料拼接
datatrain_conti = pd.DataFrame(datatrain, columns=['Survived', 'Pclass', 'Age', 'SibSp', 'Parch','Fare'], index=datatrain.index)
datatrain = datatrain_conti.join(datatrain_dummy)
datatest_conti = pd.DataFrame(datatrain, columns=['Survived', 'Pclass', 'Age', 'SibSp', 'Parch','Fare'], index=datatest.index)
datatest = datatest_conti.join(datatest_dummy)
X_train = datatrain.iloc[:,1:]
y_train = datatrain.iloc[:,0]
X_test = datatest
#标準化
stdsc = StandardScaler()
X_train_conti_std = stdsc.fit_transform(X_train[['Age''SibSp','Parch','Fare']])
X_test_conti_std = stdsc.fit_transform(X_test[['Age''SibSp','Parch','Fare']])
#将ndarray轉為datatrainframe
X_train_conti_std = pd.DataFrame(data=X_train_conti_std,columns=['Age''SibSp','Parch','Fare'],index=X_train.index)
X_test_conti_std = pd.DataFrame(data=X_test_conti_std,columns=['Age''SibSp','Parch','Fare'],index=X_test.index)
#有序分類變量Pclass
X_train_cat = X_train[['Pclass']]
X_test_cat = X_test[['Pclass']]
#無序已編碼的分類變量
X_train_dummy = X_train[['Sex_female','Sex_male','Embarked_Q','Embarked_S']]
X_test_dummy = X_test[['Sex_female','Sex_male','Embarked_Q','Embarked_S']]
#拼接為datatrainframe
X_train_set = [X_train_cat, X_train_conti_std, X_train_dummy]
X_test_set = [X_test_cat, X_test_conti_std, X_test_dummy]
X_train = pd.concat(X_train_set, axis=1)
X_test = pd.concat(X_test_set, axis=1)
clf = BernoulliNB()
clf.fit(X_train,y_train)
predicted = clf.predict(X_test)
datatest['Survived'] = predicted.astype(int)
datatest[['PassengerId','Survived']].to_csv('submission.csv', sep=',', index=False)
新聞主題分類
文本分類指的是這樣一類分類任務。在使用資料挖掘分類方法的基礎上,經過訓練标記示例模型,對文本片段、段落或檔案進行分組和歸類。
本次實驗我們使用sklearn中的fetch_20newsgroups。
20 newsgroups資料集18000多篇新聞文章,一共涉及到20種話題,分為訓練集和測試集,通常用來做文本分類,均勻分為20個不同主題的新聞討論區集合。fetch_20newsgroups資料集是被用于文本分類、文本挖據和資訊檢索研究的國際标準資料集之一。
代碼如下:
# -*- coding:utf-8 -*-
from sklearn.datasets import fetch_20newsgroups
from sklearn.cross_validation import train_test_split
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.naive_bayes import MultinomialNB
#從網際網路下載下傳資料
news = fetch_20newsgroups(subset='all')
#随機抽取25%的資料樣本作為測試集
X_train, X_test, y_train, y_test = train_test_split(news.data, news.target, test_size=0.25, random_state=33)
#文本特征向量轉換
vec = CountVectorizer()
X_train = vec.fit_transform(X_train)
X_test = vec.fit_transform(X_test)
#建立貝葉斯分類器
mnb = MultinomialNB()
mnb.fit(X_train, y_train)
y_predict = mnb.predict(X_test)