樸素貝葉斯擴展

多項式貝葉斯

文本分類

當新來一個文本時,我要對每一個類別y都計算一個向量θy= (θy1,…,θyn) 其中,n表示詞彙表中詞的種類數,即特徵空間的維度

θyi:這個樣本如果屬於類別 y時,特徵 i出現的概率P(xi| y),即條件概率

分子:這個新文本中特徵 i在類別 y下出現的次數

分母:對分子求和

•在機器學習中,樸素貝葉斯分類器是一系列以假設特徵之間強獨立(樸素)下運用貝葉斯定理爲基礎的簡單概率分類器。

•高度可擴展的,求解過程只需花費線性時間

•目前來說,樸素貝葉斯在文本分類(textclassification)的領域的應用多,無論是sklearn還是Spark Mllib中,都只定制化地實現了在文本分類領域的算法

回憶上面的知識後,看下面的案例:
在這裏插入圖片描述

調用sklearn接口

import pandas as pd
df = pd.DataFrame([[0,1],[1,1],[2,1],[3,-1],[4,-1],
                   [5,-1],[6,1],[7,1],[8,1],[9,-1]])
X = df[[0]]
Y = df[1]
from sklearn.naive_bayes import MultinomialNB
from sklearn.tree import DecisionTreeClassifier
model = MultinomialNB()
model.fit(X,Y)
print(Y.values.T)
model.predict(X)
打印結果:
['beijing', 'chinese', 'japan', 'macao', 'shanghai', 'tokyo']
[[1 2 0 0 0 0]
 [0 2 0 0 1 0]
 [0 1 0 1 0 0]
 [0 1 1 0 0 1]]
[1]

自己實現:

import pandas as pd
import numpy as np
from sklearn.feature_extraction.text import CountVectorizer
df = pd.read_csv("input/bayes_xinxi.txt")  #讀取數據
tfCoder =CountVectorizer(token_pattern="[a-zA-Z|\u4e00-\u9fa5]+")  #TF模型
#訓練TF模型
tfCoder.fit(df['words'])
names_feature = tfCoder.get_feature_names()#獲取詞語名
print(names_feature)
Y =  df['Y'].value_counts().keys()#獲取類別種類的list
class_prior = []  #用於存儲先驗概率
feature_prob = [] #用於存儲條件概率
for y in Y: #遍歷每個類別
    df2 = df[df['Y']==y]#獲取每個類別下的DF
    prior = len(df2)/len(df)#計算先驗概率
    #將先驗概率加入集合
    class_prior.append(prior)
    #計算條件概率
    a = tfCoder.transform(df2['words']).toarray()
    prob = (np.sum(a,axis=0)+1)/(np.sum(a)+len(names_feature))
    feature_prob.append(prob)
    #將條件概率加入集合
print("-----------進行測試-----------")
X = ['Chinese Chinese Chinese Tokyo Japan'] #訓練數據
T =   tfCoder.transform(X).toarray()#將訓練數據轉爲array類型
class_prior =np.array(class_prior)
feature_prob = np.array(feature_prob)
c = feature_prob**T
c
sj = []
for i in range(len(c)):
    s=1
    for j in c[i]:
        s*=j
    sj.append(s)
sj = np.array(sj)

Y[np.argmax(sj*class_prior)] #輸出概率最大的類別

樸素貝葉斯算法推導

特徵屬性間是獨立得,所以得到:

p(XIY,X1,...,XI1,XI+1,...,Xm)=p(XIY) p(X_I|Y,X_1,...,X_{I-1},X_{I+1},...,X_m)=p(X_I|Y)\\
優化一下公式:
P(yx1,x2,...,xm)=P(y)P(x1,x2,...,xmy)P(x1,x2,...,xm)=P(y)i=1mP(xiy)P(x1,x2,...,xm) P(y|x_1,x_2,...,x_m) = \frac{P(y)P(x_1,x_2,...,x_m|y)}{P(x_1,x_2,...,x_m)}\\ =\frac{P(y)\prod_{i=1}^{m}P(x_i|y)}{P(x_1,x_2,...,x_m)}
在給定樣本下,p(x1,x2,…,xm)是常數,所以得到:
P(yx1,x2,...,xm)P(y)i=1mP(xiy) P(y|x_1,x_2,...,x_m)\to P(y)\prod_{i=1}^{m}P(x_i|y)
然後求解最大的概率:
y=argymaxP(y)i=1mP(xiy) \overline y = \arg_y max P(y)\prod_{i=1}^{m}P(x_i|y)

高斯樸素貝葉斯

Gaussian Naive Bayes是指當特徵屬性爲連續值時,而且分佈服從高斯分佈,那麼在計算P(x|y)的時候可以直接使用高斯分佈的概率公式:
g(x,μ,σ)=12πσe(xμ)22σ2P(xkyk)=g(xk,μyk,σyk) g(x,\mu,\sigma)=\frac{1}{\sqrt{2\pi}\sigma}-e^{\frac{(x-\mu)^2}{2\sigma^2}}\\ P(x_k|y_k) = g(x_k,\mu_{y_k},\sigma_{y_k})
因此只需要計算出各個類別中此特徵項劃分的各個均值和標準差

伯努利樸素貝葉斯

Bernoulli Naive Bayes是指當特徵屬性爲連續值時,而且分佈服從伯努利分佈,那麼在計算P(x|y)的時候可以直接使用伯努利分佈的概率公式:
P(xky)=P(1y)xk+(1P(1y))(1xk) P(x_k|y)=P(1|y)x_k+(1-P(1|y))(1-x_k)
伯努利分佈是一種離散分佈,只有兩種可能的結果。1表示成功,出現的概率爲p;0表示失敗,出現的概率爲q=1-p;其中均值爲E(x)=p,方差爲Var(X)=p(1-p)

使用高斯樸素貝葉斯實現鳶尾花的分類

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib as mpl
from sklearn.preprocessing import StandardScaler, MinMaxScaler, PolynomialFeatures
from sklearn.naive_bayes import GaussianNB, MultinomialNB#高斯貝葉斯和多項式樸素貝葉斯
from sklearn.pipeline import Pipeline
from sklearn.metrics import accuracy_score
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
## 設置屬性防止中文亂碼
mpl.rcParams['font.sans-serif'] = [u'SimHei']
mpl.rcParams['axes.unicode_minus'] = False
# 花萼長度、花萼寬度,花瓣長度,花瓣寬度
iris_feature_E = 'sepal length', 'sepal width', 'petal length', 'petal width'
iris_feature_C = u'花萼長度', u'花萼寬度', u'花瓣長度', u'花瓣寬度'
iris_class = 'Iris-setosa', 'Iris-versicolor', 'Iris-virginica'
features = [2,3]
## 讀取數據
path = './datas/iris.data'  # 數據文件路徑
data = pd.read_csv(path, header=None)
x = data[list(range(4))]
x = x[features]
# pd.Categorical().codes  pd.Categorial().codes  pd.Categorical().codes  pd.Categorical().codes
y = pd.Categorical(data[4]).codes ## 直接將數據特徵轉換爲0,1,2

print ("總樣本數目:%d;特徵屬性數目:%d" % x.shape)
## 0. 數據分割,形成模型訓練數據和測試數據
x_train1, x_test1, y_train1, y_test1 = train_test_split(x, y, train_size=0.8, random_state=14)
x_train, x_test, y_train, y_test = x_train1, x_test1, y_train1, y_test1
print ("訓練數據集樣本數目:%d, 測試數據集樣本數目:%d" % (x_train.shape[0], x_test.shape[0]))
## 高斯貝葉斯模型構建
clf = Pipeline([
        ('sc', StandardScaler()),#標準化,把它轉化成了高斯分佈
        ('poly', PolynomialFeatures(degree=4)),
        ('clf', GaussianNB())]) # MultinomialNB多項式貝葉斯算法中要求特徵屬性的取值不能爲負數
## 訓練模型
clf.fit(x_train, y_train)
## 計算預測值並計算準確率
y_train_hat = clf.predict(x_train)
print ('訓練集準確度: %.2f%%' % (100 * accuracy_score(y_train, y_train_hat)))
y_test_hat = clf.predict(x_test)
print ('測試集準確度:%.2f%%' % (100 * accuracy_score(y_test, y_test_hat)))
## 產生區域圖
N, M = 500, 500     # 橫縱各採樣多少個值
x1_min1, x2_min1 = x_train.min()
x1_max1, x2_max1 = x_train.max()
x1_min2, x2_min2 = x_test.min()
x1_max2, x2_max2 = x_test.max()
x1_min = np.min((x1_min1, x1_min2))
x1_max = np.max((x1_max1, x1_max2))
x2_min = np.min((x2_min1, x2_min2))
x2_max = np.max((x2_max1, x2_max2))

t1 = np.linspace(x1_min, x1_max, N)
t2 = np.linspace(x2_min, x2_max, N)
x1, x2 = np.meshgrid(t1, t2)  # 生成網格採樣點
x_show = np.dstack((x1.flat, x2.flat))[0] # 測試點

cm_light = mpl.colors.ListedColormap(['#77E0A0', '#FF8080', '#A0A0FF'])
cm_dark = mpl.colors.ListedColormap(['g', 'r', 'b'])
y_show_hat = clf.predict(x_show)                  # 預測值
y_show_hat = y_show_hat.reshape(x1.shape)
## 畫圖
plt.figure(facecolor='w')
plt.pcolormesh(x1, x2, y_show_hat, cmap=cm_light)     # 預測值的顯示
plt.scatter(x_train[features[0]], x_train[features[1]], c=y_train, edgecolors='k', s=50, cmap=cm_dark)
plt.scatter(x_test[features[0]], x_test[features[1]], c=y_test, marker='^', edgecolors='k', s=120, cmap=cm_dark)
plt.xlabel(iris_feature_C[features[0]], fontsize=13)
plt.ylabel(iris_feature_C[features[1]], fontsize=13)
plt.xlim(x1_min, x1_max)
plt.ylim(x2_min, x2_max)
plt.title(u'GaussianNB對鳶尾花數據的分類結果, 正確率:%.3f%%' % (100 * accuracy_score(y_test, y_test_hat)), fontsize=18)
plt.grid(True)
plt.show()

在這裏插入圖片描述

使用Ridge KNN 多項式樸素貝葉斯 伯努利樸素貝葉斯 隨機森林

SVM LinearSVC-11 LinearSVC-l2

import numpy as np
from time import time
import matplotlib.pyplot as plt
import matplotlib as mpl

from sklearn.datasets import fetch_20newsgroups#引入新聞數據包

from sklearn.feature_extraction.text import TfidfVectorizer#做tfidf編碼

from sklearn.feature_selection import SelectKBest, chi2#卡方檢驗——特徵篩選
from sklearn.linear_model import RidgeClassifier
from sklearn.svm import LinearSVC,SVC
from sklearn.naive_bayes import MultinomialNB, BernoulliNB #引入多項式和伯努利的貝葉斯
from sklearn.neighbors import KNeighborsClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import GridSearchCV
from sklearn import metrics
###  基準模型方法
def benchmark(clf,name):
    print (u'分類器:', clf)
    
    ##  設置最優參數,並使用5折交叉驗證獲取最優參數值
    alpha_can = np.logspace(-2, 1, 10)
    model = GridSearchCV(clf, param_grid={'alpha': alpha_can}, cv=5)
    m = alpha_can.size
    
    ## 如果模型有一個參數是alpha,進行設置
    if hasattr(clf, 'alpha'):
        model.set_params(param_grid={'alpha': alpha_can})
        m = alpha_can.size
    ## 如果模型有一個k近鄰的參數,進行設置
    if hasattr(clf, 'n_neighbors'):
        neighbors_can = np.arange(1, 15)
        model.set_params(param_grid={'n_neighbors': neighbors_can})
        m = neighbors_can.size
    ## LinearSVC最優參數配置
    if hasattr(clf, 'C'):
        C_can = np.logspace(1, 3, 3)
        model.set_params(param_grid={'C':C_can})
        m = C_can.size
    ## SVM最優參數設置
    if hasattr(clf, 'C') & hasattr(clf, 'gamma'):
        C_can = np.logspace(1, 3, 3)
        gamma_can = np.logspace(-3, 0, 3)
        model.set_params(param_grid={'C':C_can, 'gamma':gamma_can})
        m = C_can.size * gamma_can.size
    ## 設置深度相關參數,決策樹
    if hasattr(clf, 'max_depth'):
        max_depth_can = np.arange(4, 10)
        model.set_params(param_grid={'max_depth': max_depth_can})
        m = max_depth_can.size
    
    ## 模型訓練
    t_start = time()
    model.fit(x_train, y_train)
    t_end = time()
    t_train = (t_end - t_start) / (5*m)
    print (u'5折交叉驗證的訓練時間爲:%.3f秒/(5*%d)=%.3f秒' % ((t_end - t_start), m, t_train))
    print (u'最優超參數爲:', model.best_params_)
    
    ## 模型預測
    t_start = time()
    y_hat = model.predict(x_test)
    t_end = time()
    t_test = t_end - t_start
    print (u'測試時間:%.3f秒' % t_test)
    
    ## 模型效果評估
    train_acc = metrics.accuracy_score(y_train, model.predict(x_train))
    test_acc = metrics.accuracy_score(y_test, y_hat)
    print (u'訓練集準確率:%.2f%%' % (100 * train_acc))
    print (u'測試集準確率:%.2f%%' % (100 * test_acc))
    
    ## 返回結果(訓練時間耗時,預測數據耗時,訓練數據錯誤率,測試數據錯誤率, 名稱)
    return t_train, t_test, 1-train_acc, 1-test_acc, name
    ## 設置屬性防止中文亂碼
mpl.rcParams['font.sans-serif'] = [u'SimHei']
mpl.rcParams['axes.unicode_minus'] = False
### 數據加載
print (u'加載數據...')
t_start = time()
## 不要頭部信息
remove = ('headers', 'footers', 'quotes')
## 只要這四類數據
categories = 'alt.atheism', 'talk.religion.misc', 'comp.graphics', 'sci.space'

## 分別加載訓練數據和測試數據
data_train = fetch_20newsgroups(data_home='./datas/',subset='train', categories=categories, shuffle=True, random_state=0, remove=remove)
data_test = fetch_20newsgroups(data_home='./datas/',subset='test', categories=categories, shuffle=True, random_state=0, remove=remove)

## 完成
print (u"完成數據加載過程.耗時:%.3fs" % (time() - t_start))
### 獲取加載數據的儲存空間
def size_mb(docs):
    return sum(len(s.encode('utf-8')) for s in docs) / 1e6

categories = data_train.target_names
data_train_size_mb = size_mb(data_train.data)
data_test_size_mb = size_mb(data_test.data)

print (u'數據類型:', type(data_train.data))
print("%d文本數量 - %0.3fMB (訓練數據集)" % (len(data_train.data), data_train_size_mb))
print("%d文本數量 - %0.3fMB (測試數據集)" % (len(data_test.data), data_test_size_mb))
print (u'訓練集和測試集使用的%d個類別的名稱:' % len(categories))
print(categories)
### 數據重命名
x_train = data_train.data
y_train = data_train.target
x_test = data_test.data
y_test = data_test.target
### 輸出前5個樣本
print (u' -- 前5個文本 -- ')
for i in range(5):
    print (u'文本%d(屬於類別 - %s):' % (i+1, categories[y_train[i]]))
    print (x_train[i])
    print ('\n\n')
### 文檔轉換爲向量
## 轉換
# 要求輸入的數據類型必須是list,list中的每條數據,單詞是以空格分割開的
vectorizer = TfidfVectorizer(input='content', stop_words='english', max_df=0.5, sublinear_tf=True)
x_train = vectorizer.fit_transform(data_train.data)  # x_train是稀疏的,scipy.sparse.csr.csr_matrix
x_test = vectorizer.transform(data_test.data)
print (u'訓練集樣本個數:%d,特徵個數:%d' % x_train.shape)
print (u'停止詞:\n')
print(vectorizer.get_stop_words())
## 獲取最終的特徵屬性名稱
feature_names = np.asarray(vectorizer.get_feature_names())
## 特徵選擇
ch2 = SelectKBest(chi2, k=1000)
x_train = ch2.fit_transform(x_train, y_train)
x_test = ch2.transform(x_test)
feature_names = [feature_names[i] for i in ch2.get_support(indices=True)]
### 使用不同的分類器對數據進行比較
print (u'分類器的比較:\n')
clfs = [
    [RidgeClassifier(), 'Ridge'],
    [KNeighborsClassifier(), 'KNN'],
    [MultinomialNB(), 'MultinomialNB'],
    [BernoulliNB(), 'BernoulliNB'],
    [RandomForestClassifier(n_estimators=200), 'RandomForest'],
    [SVC(), 'SVM'],
    [LinearSVC(loss='squared_hinge', penalty='l1', dual=False, tol=1e-4), 'LinearSVC-l1'],
    [LinearSVC(loss='squared_hinge', penalty='l2', dual=False, tol=1e-4), 'LinearSVC-l2']
]

## 將訓練數據保存到一個列表中
result = []
for clf,name in clfs:
    # 計算算法結果
    a = benchmark(clf,name)
    # 追加到一個列表中,方便進行展示操作
    result.append(a)
    print ('\n')
## 將列表轉換爲數組
result = np.array(result)
### 獲取需要畫圖的數據
result = [[x[i] for x in result] for i in range(5)]
training_time, test_time, training_err, test_err, clf_names = result

training_time = np.array(training_time).astype(np.float)
test_time = np.array(test_time).astype(np.float)
training_err = np.array(training_err).astype(np.float)
test_err = np.array(test_err).astype(np.float)
### 畫圖
x = np.arange(len(training_time))
plt.figure(figsize=(10, 7), facecolor='w')
ax = plt.axes()
b0 = ax.bar(x+0.1, training_err, width=0.2, color='#77E0A0')
b1 = ax.bar(x+0.3, test_err, width=0.2, color='#8800FF')
ax2 = ax.twinx()
b2 = ax2.bar(x+0.5, training_time, width=0.2, color='#FFA0A0')
b3 = ax2.bar(x+0.7, test_time, width=0.2, color='#FF8080')
plt.xticks(x+0.5, clf_names)
plt.legend([b0[0], b1[0], b2[0], b3[0]], (u'訓練集錯誤率', u'測試集錯誤率', u'訓練時間', u'測試時間'), loc='upper left', shadow=True)
plt.title(u'新聞組文本數據分類及不同分類器效果比較', fontsize=18)
plt.xlabel(u'分類器名稱')
plt.grid(True)
plt.tight_layout(2)
plt.show()

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章