ML12-樸素貝葉斯分類

樸素貝葉斯分類是一種經(jīng)典的機器學(xué)習(xí)算法,本主題從貝葉斯的應(yīng)用場景,到其數(shù)學(xué)基礎(chǔ),并到最終的實現(xiàn)與應(yīng)用做了介紹。主要內(nèi)容包含:
??1. Naive Bayes的分類思想;
??2. Naive Bayes分類的數(shù)學(xué)基礎(chǔ);
??3. Naive Bayes分類算法實現(xiàn);
??4. Naive Bayes算法的sklearn調(diào)用;
??5. 文本特征處理;
??6. Naive Bayes算法的簡歷薪資預(yù)測實現(xiàn);


樸素貝葉斯算法說明

樸素貝葉斯算法的概要說明

  • 樸素貝葉斯是一種分類算法;
  • 屬于監(jiān)督學(xué)習(xí);
  • 使用貝葉斯定理作為數(shù)學(xué)理論基礎(chǔ)。
  • 大量樣本下會有較好的分類效果,不適用于數(shù)據(jù)特征有關(guān)聯(lián)的訓(xùn)練樣本。

應(yīng)用場景

  1. 文本分類
  2. 垃圾郵件過濾
  3. 病人分類
  4. 拼寫檢查

貝葉斯算法的優(yōu)缺點

  1. 樸素貝葉斯的主要優(yōu)點有:

    • 樸素貝葉斯模型發(fā)源于古典數(shù)學(xué)理論,有穩(wěn)定的分類效率。
    • 對小規(guī)模的數(shù)據(jù)表現(xiàn)很好,能個處理多分類任務(wù),適合增量式訓(xùn)練,尤其是數(shù)據(jù)量超出內(nèi)存時,我們可以一批批的去增量訓(xùn)練。
    • 對缺失數(shù)據(jù)不太敏感,算法也比較簡單,常用于文本分類。
  2. 樸素貝葉斯的主要缺點有:

    • 理論上,樸素貝葉斯模型與其他分類方法相比具有最小的誤差率。但是實際上并非總是如此,這是因為樸素貝葉斯模型給定輸出類別的情況下,假設(shè)屬性之間相互獨立,這個假設(shè)在實際應(yīng)用中往往是不成立的,在屬性個數(shù)比較多或者屬性之間相關(guān)性較大時,分類效果不好。而在屬性相關(guān)性較小時,樸素貝葉斯性能最為良好。對于這一點,有半樸素貝葉斯之類的算法通過考慮部分關(guān)聯(lián)性適度改進。
    • 需要知道先驗概率,且先驗概率很多時候取決于假設(shè),假設(shè)的模型可以有很多種,因此在某些時候會由于假設(shè)的先驗?zāi)P偷脑驅(qū)е骂A(yù)測效果不佳。
    • 由于我們是通過先驗和數(shù)據(jù)來決定后驗的概率從而決定分類,所以分類決策存在一定的錯誤率。
    • 對輸入數(shù)據(jù)的表達(dá)形式很敏感。

樸素貝葉斯算法的分類思想

  • 使用病人分類作為例子:
    • 已知病例:
癥狀 職業(yè) 疾病
打噴嚏 護士 感冒
打噴嚏 農(nóng)夫 過敏
頭痛 建筑工人 腦震蕩
頭痛 建筑工人 感冒
打噴嚏 教師 感冒
頭痛 教師 腦震蕩
  • 假設(shè)需要對一個新的病人的病情做判定,該病人信息如下:

    • 打噴嚏

    • 建筑工人

    • 請判定病人最可能是什么病:感冒?過敏?腦震蕩?

  • 診斷過程:

    1. 計算三種病狀的可能性:
      • 計算感冒的可能性
      • 計算過敏的可能性
      • 計算腦震蕩的可能性
    2. 可能性最大的病狀就是最終診斷
  • 如果使用概率表示可能性,則某個病狀的概率計算為:

    • P(感冒|打噴嚏x建筑工人) = P(打噴嚏x建筑工人|感冒) x P(感冒) / P(打噴嚏x建筑工人)

      • P(打噴嚏x建筑工人|感冒) = P(打噴嚏|感冒) x P(建筑工人|感冒) = \dfrac{2}{3} \times \dfrac{1}{3}

      • P(感冒) = \dfrac{3}{6}

      • P(打噴嚏x建筑工人) = P(打噴嚏) x P(建筑工人) = \dfrac{3}{6} \times \dfrac{2}{6}

      • P(感冒|打噴嚏x建筑工人) = \dfrac{\dfrac{2}{3} \times \dfrac{1}{3} \times \dfrac{3}{6}} {\dfrac{3}{6} \times \dfrac{2}{6}} = \dfrac{\dfrac{6}{54}}{\dfrac{6}{36}} = \dfrac{36}{54} = \dfrac{2}{3} = 0.6666\cdots

    • 腦震蕩的概率:

      • P(腦震蕩|打噴嚏x建筑工人) = P(打噴嚏x建筑工人|腦震蕩) x P(腦震蕩) / P(打噴嚏x建筑工人)
      • P(打噴嚏x建筑工人|腦震蕩) = P(打噴嚏|腦震蕩) x P(建筑工人|腦震蕩) = 0
    • 過敏的概率

      • P(過敏|打噴嚏x建筑工人) = P(打噴嚏x建筑工人|過敏) x P(過敏) / P(打噴嚏x建筑工人)
      • P(打噴嚏x建筑工人|過敏) = P(打噴嚏|過敏) x P(建筑工人|過敏) = 0
  • 結(jié)論:

    • 打噴嚏的建筑工人有66.6666%的概率是感冒,0%的概率是過敏與腦震蕩。

sklearn的貝葉斯應(yīng)用體驗

  • sklearn的貝葉斯實現(xiàn)是四個類:
    • 伯努利貝葉斯
    • 高斯貝葉斯
    • 多項式貝葉斯
      • The Complement Naive Bayes(補充貝葉斯)
    • sklearn的貝葉斯算法實現(xiàn)
import numpy as np
from sklearn.naive_bayes import GaussianNB, BernoulliNB, MultinomialNB, ComplementNB
from sklearn.model_selection import train_test_split
import sklearn.datasets as ds
data,target = ds.load_iris(return_X_y=True)
# 切分?jǐn)?shù)據(jù)集
data_train, data_test, target_train, target_test = train_test_split(
    data,    # 數(shù)據(jù)集
    target,    # 數(shù)據(jù)集標(biāo)簽
    test_size=0.2)  

print('--------GaussianNB')
classifier1 = GaussianNB()
classifier1.fit(data_train, target_train)
pre = classifier1.predict(data_test)
print((pre == target_test).sum())
print('--------BernoulliNB')
classifier2= BernoulliNB()
classifier2.fit(data_train, target_train)
pre = classifier2.predict(data_test)
print((pre == target_test).sum())
print('--------MultinomialNB')
classifier3 = MultinomialNB()
classifier3.fit(data_train, target_train)
pre = classifier3.predict(data_test)
print((pre == target_test).sum())
print('--------ComplementNB')
classifier4 = ComplementNB()
classifier4.fit(data_train, target_train)
pre = classifier4.predict(data_test)
print((pre == target_test).sum())
--------GaussianNB
29
--------BernoulliNB
7
--------MultinomialNB
25
--------ComplementNB
20

樸素貝葉斯算法的數(shù)學(xué)基礎(chǔ)

條件概率

  • 理解條件貝葉斯公式從條件概率開始:

    • 假設(shè)有兩個事件X, Y,事件X, Y同時發(fā)生的概率(聯(lián)合概率)可以表示如下:

      • P(X, Y)
    • 事件X,Y同時發(fā)生,還可以表示為Y已經(jīng)發(fā)生,然后X再發(fā)生的概率:

      • Y發(fā)生的概率(先驗概率,也稱邊緣概率)表示為:P(Y)
      • Y已經(jīng)發(fā)生的條件,X發(fā)生的概率就是條件概率,表示為:P(X | Y)
  • 兩個事件同時發(fā)生的概率(聯(lián)合概率)表示為:


    • P(X, Y) = P(X | Y) P(Y) = P(Y | X) P(X)

  • 從上式可以推導(dǎo)出條件概率表示::


    • P(X | Y) = \dfrac{P(X,Y)}{P(Y)}

    • P(Y | X) = \dfrac{P(X,Y)}{P(X)}
  • 從條件概率可以進一步推導(dǎo):


    • P(X | Y) = \dfrac{P(X,Y)}{P(Y)} = \dfrac{P(Y | X) P(X)}{P(Y)}

    • P(Y | X) = \dfrac{P(X,Y)}{P(X)} = \dfrac{P(X | Y) P(Y)}{P(X)}
  • 如果A, B是兩個獨立的特征,則其概率計算為:

    • P(X,Y) =P(X)P(Y)
  • 則條件概率滿足:

    • P(Y | X) = P(Y)
    • P(X | Y) = P(X)

全概率:

  • 全概率是對一復(fù)雜事件X的概率求解問題轉(zhuǎn)化為了在不同情況下發(fā)生的簡單事件的概率的求和問題。
  • 全概率公式:
    • 假設(shè)\{Y_1,Y_2,Y_n\}是一個完備事件組:
      • Y_1 \cup Y_2 \cup \cdots \cup Y_n = \Omega構(gòu)成整個樣本空間。
      • Y_i \cap Y_j = \emptyset, \quad i \neq j
    • 則對于任意一個事件X的概率使用全概率公式表示:
      • P(X) = \sum \limits _{i=1}^n P(X,Y_i)= \sum \limits _{i=1} ^ nP(X|Y_i) P(Y_i)

貝葉斯定理(公式)

  • 條件概率:

    • P(Y|X)=\dfrac{P(X,Y)}{P(X)}
  • 后驗概率(貝葉斯公式):

    • P(X | Y ) = \dfrac{P( Y | X) P(X)} {P(Y)}
  • 全概率下的貝葉斯公式

    • P(Y_k | X) = \dfrac{P(X|Y_k) P(Y_k)}{P(X)} = \dfrac{P(X|Y_k) P(Y_k)}{ \sum \limits _{i=1} ^n P(X|Y_i) P(Y_i)}

后驗概率

  • 后驗概率在表現(xiàn)形式上與條件概率一樣,但在理解上存在一些因果的區(qū)別:

    • 如果我們出門之前我們聽到新聞?wù)f今天路上出了個交通事故,那么我們想算一下堵車的概率,這個就叫做條件概率 。也就是P(堵車|交通事故)。這是有因求果。
    • 如果我們已經(jīng)出了門,然后遇到了堵車,那么我們想算一下堵車時由交通事故引起的概率有多大,那這個就叫做后驗概率 (其實也是條件概率,但是通常習(xí)慣這么說) 。也就是P(交通事故|堵車)。這是有果求因。
  • 后驗概率的概念理解:

    • 后驗概率:P(Y | X) = \dfrac{P(X | Y) P(Y)}{P(X)}

      • 歸一化因子:P(X)
      • 先驗概率:P(X)
      • 似然概率:P(X | Y)
      • 標(biāo)準(zhǔn)似然概率: \dfrac{P(X | Y) }{P(X)}
    • 后驗概率:標(biāo)準(zhǔn)似然概率 * 先驗概率

    • 貝葉斯公式就是用先驗概率求后驗概率。

多特征的情況

  • 假設(shè) P(X)=1,則貝葉斯公式為:

    • P(Y_k | X) = \dfrac{P(X|Y_k) P(Y_k)}{P(X)} = P(X|Y_k) P(Y_k)
  • 假設(shè)X=(X_1,X_2,\cdots, X_m)

    • P(Y_k | (X_1, X_2,\cdots, X_m)) =P(X_1,X_2,\cdots, X_m |Y_k) P(Y_k) = P(Y_k) \prod \limits _{i=1}^{m} P(X_i|Y_k)

樸素貝葉斯算法的推導(dǎo)

  • 條件假設(shè):
    • 存在訓(xùn)練集X= (X_1, X_2, \cdots , X_m),其分類標(biāo)簽是(C_1, C_2, \cdots,C_m)
      • X_i = (x_{i1}, x_{i1}, \cdots, x_{in}) ,一共n個樣本。
    • 分類樣本為S=(s_1, s_2, \cdots, s_m)
      • 貝葉斯算法是找出在已知訓(xùn)練集的情況,找出概率最大的那個類別。
  1. 求解問題表述:

    • \begin{align} C_{result} & = \underbrace{argmax}_{C_k}P(C=C_k|X=(X_1, X_2,\cdots, X_m)) \\& = \dfrac{\underbrace{argmax}_{C_k}P(X=(X_1,X_2,\cdots,X_m)|C=C_k)P(C=C_k)}{P(X=(X_1,X_2,\cdots, X_m))} \end{align}
  2. 假設(shè)X=(X_1,X_2,\cdots, X_m)是完備特征集:

    • P(X=(X_1,X_2,\cdots, X_m)) = \prod \limits _{i=1}^m P(X=X_i)

    • C_{result} = \underbrace{argmax}_{C_k} \dfrac{P(X=(X_1,X_2,\cdots,X_m))|C=C_k) P(C=C_k)}{\prod \limits _{i=1}^m P(X=X_i)}

    • C_{result} = \underbrace{argmax}_{C_k} \dfrac{P(C=C_k) \prod \limits_{i=1} ^m P(X=X_i |C=C_k) }{\prod \limits _{i=1}^m P(X=X_i)}

  3. 上述概率在離散情況下,使用頻次與頻率表示。

貝葉斯算法中的概率計算問題

離散值的情況

  • X_i采用多項式分布:

    • P(X=X_j | Y=C_k) = \dfrac{m_{kj}}{m_k}
      • m_k表示類別C_k出現(xiàn)的次數(shù)
      • m_kj表示在類別C_k中,X_j出現(xiàn)的次數(shù)。
  • 離散值的問題:

    • 某些時候,可能某些類別在樣本中沒有出現(xiàn),這樣可能導(dǎo)致P(X=X_j | Y=C_k) = 0
  • 離散值問題解決:

    • 引入拉普拉斯平滑,概率計算公式為:P(X_j=X_j|Y=C_k) = \dfrac{m_{kj} + \lambda}{m_k + O_j\lambda}
      • 其中\lambda為一個大于0的常數(shù),通常取為1。
      • 其中O_j為第j個特征的取值個數(shù)(實際上,這個取值在不同場合中可以根據(jù)需要確定,因為主要用來做平滑,防止概率為0,所以取得值是多少,與最終結(jié)果關(guān)系不大)。

稀疏離散值

  • 如果我們我們的X_j是非常稀疏的離散值,即各個特征出現(xiàn)概率很低,這時我們可以假設(shè)X_j符合伯努利分布:
    • 即特征X_j出現(xiàn)記為1,不出現(xiàn)記為0。即只要X_j出現(xiàn)即可,我們不關(guān)注X_j的次數(shù)。
    • P(X=X_j|Y=C_k) = P(X_j|Y=C_k)X_j + (1 - P(X_j|Y=C_k))(1-X_j)
      • 等式前的X_j還是表示特征值。
      • 等式后的X_j表示取值為0或者1(就是出現(xiàn)或者不出現(xiàn))

連續(xù)值

  • 如果我們我們的X_j是連續(xù)值,我們通常取X_j的先驗概率為正態(tài)分布,即在樣本類別C_k的值符合正態(tài)分布。這樣P(X = X_j | Y = C_k)的概率分布是:
    • P(X=X_j | Y=C_k) = \dfrac{1}{\sqrt{2\pi\sigma_k^2}}e^{-\dfrac{(X_j - \mu_k)^2}{2\sigma_k^2}}
      • 其中\mu _k為在樣本類別C_k中,所有X_j的平均值。\sigma _k ^2為在樣本類別C_k中,所有X_j的方差。

各種算法的測試效果

  • 對鳶尾花這種連續(xù)數(shù)據(jù),使用高斯貝葉斯算法無疑是合適的。
    • 下面看看離散的情況
      • 手工計算:
        • ['打噴嚏','建筑工人'] : \dfrac{2}{3}
        • ['頭痛', '護士']\dfrac{2}{3}

離散的測試效果

import numpy as np
from sklearn.naive_bayes import GaussianNB, BernoulliNB, MultinomialNB, ComplementNB
from sklearn.preprocessing import LabelEncoder
# 數(shù)據(jù)
data = np.array([
    ['打噴嚏','護士','感冒'],
    ['打噴嚏','農(nóng)夫','過敏'],
    ['頭痛','建筑工人','腦震蕩'],
    ['頭痛','建筑工人','感冒',],
    ['打噴嚏','教師','感冒',],
    ['頭痛','教師','腦震蕩']
])


# 訓(xùn)練集
data_train = np.zeros(shape=(data.shape[0], data.shape[1]-1),dtype=np.int32)

encoder = LabelEncoder()
encoder.fit(data[:,0])
# print(encoder.classes_)
# print(encoder.transform(data[:,0]))
data_train[:,0] = encoder.transform(data[:,0])

encoder.fit(data[:,1])
# print(encoder.classes_)
data_train[:,1] = encoder.transform(data[:,1])

encoder.fit(target)
# print(encoder.classes_)
target_train = encoder.transform(data[:,2])



# 測試集
test = np.array([
    ['打噴嚏','建筑工人'],
    ['頭痛', '護士']
])
data_test = np.zeros(test.shape,dtype=np.int32)
encoder.fit(test[:,0])
data_test[:,0] = encoder.transform(test[:,0])

encoder.fit(test[:,1])
# print(encoder.classes_)
data_test[:,1] = encoder.transform(test[:,1])

print('--------GaussianNB')
classifier1 = GaussianNB()
classifier1.fit(data_train, target_train)
pre = classifier1.predict(data_test)
print(pre)
print('--------BernoulliNB')
classifier2= BernoulliNB()
classifier2.fit(data_train, target_train)
pre = classifier2.predict(data_test)
print(pre)
print('--------MultinomialNB')
classifier3 = MultinomialNB()
classifier3.fit(data_train, target_train)
pre = classifier3.predict(data_test)
print(pre)
print('--------ComplementNB')
classifier4 = ComplementNB()
classifier4.fit(data_train, target_train)
pre = classifier4.predict(data_test)
print(pre)


--------GaussianNB
[2 1]
--------BernoulliNB
[2 1]
--------MultinomialNB
[0 0]
--------ComplementNB
[2 1]

連續(xù)的測試效果

% matplotlib inline
import matplotlib.pyplot as plt
from matplotlib.colors import ListedColormap
import numpy as np
from sklearn.naive_bayes import GaussianNB, BernoulliNB, MultinomialNB, ComplementNB
from sklearn.model_selection import train_test_split
import sklearn.datasets as ds


data,target = ds.load_iris(return_X_y=True)
# 切分?jǐn)?shù)據(jù)集
data_train, data_test, target_train, target_test = train_test_split(
    data,    # 數(shù)據(jù)集
    target,    # 數(shù)據(jù)集標(biāo)簽
    test_size=0.2)  

classifier = GaussianNB()
classifier.fit(data_train[:,[0, 2]], target_train)

# 可視化
figure = plt.figure('貝葉斯分類', figsize=(8, 6))
ax = figure.add_axes([0.1, 0.1, 0.8, 0.8])

x_min, x_max = data[:, 0].min(), data[:, 0].max()
y_min, y_max = data[:, 2].min(), data[:, 2].max()
x_min -= 0.25
x_max += 0.25

y_min -= 0.25
y_max += 0.25
ax.set_xlim(x_min, x_max)
ax.set_ylim(y_min, y_max)

x, y = np.mgrid[x_min: x_max:500j, y_min: y_max:500j]  # 生成網(wǎng)格

x_y_plane = np.c_[x.flat, y.flat]   #  按照列合并

pre = classifier.predict(x_y_plane)

colors = ListedColormap([(0.5, 0.8, 0.8, 1),(0.8, 0.5, 0.8, 1),(0.8, 0.8, 0.5, 1)])
colors_pure = ListedColormap([(1, 0, 0, 1),(0, 1, 0, 1),(0, 0, 1, 1)])
ax.scatter (x.flat, y.flat, c=pre, cmap=colors, s=2**2, marker='.')
ax.scatter (data[:, 0], data[:, 2], c=target, cmap=colors_pure,  s=3**2, marker='.')
plt.show()
貝葉斯分類效果

貝葉斯算法的應(yīng)用案例

  • 簡歷分類

一個簡單的詞向量的例子

  • 借鑒的文本分類的一個例子
#!/usr/bin/python
# coding=utf-8
from numpy import *

# 過濾網(wǎng)站的惡意留言  侮辱性:1     非侮辱性:0
# 創(chuàng)建一個實驗樣本
def loadDataSet():
    postingList = [['my', 'dog', 'has', 'flea', 'problems', 'help', 'please'],
                   ['maybe', 'not', 'take', 'him', 'to','dog', 'park', 'stupid'],
                   ['my', 'dalmation', 'is', 'so', 'cute', 'I', 'love', 'him'],
                   ['stop', 'posting', 'stupid', 'worthless', 'garbage'],
                   ['mr', 'licks', 'ate', 'my', 'steak', 'how', 'to', 'stop', 'him'],
                   ['quit', 'buying', 'worthless', 'dog', 'food', 'stupid']]
    classVec = [0, 1, 0, 1, 0, 1]
    return postingList, classVec

# 創(chuàng)建一個包含在所有文檔中出現(xiàn)的不重復(fù)詞的列表
def createVocabList(dataSet):
    vocabSet = set([])      # 創(chuàng)建一個空集
    for document in dataSet:
        vocabSet = vocabSet | set(document)   # 創(chuàng)建兩個集合的并集
    return list(vocabSet)

# 將文檔詞條轉(zhuǎn)換成詞向量
def setOfWords2Vec(vocabList, inputSet):
    returnVec = [0]*len(vocabList)        # 創(chuàng)建一個其中所含元素都為0的向量
    for word in inputSet:
        if word in vocabList:
            # returnVec[vocabList.index(word)] = 1     # index函數(shù)在字符串里找到字符第一次出現(xiàn)的位置  詞集模型
            returnVec[vocabList.index(word)] += 1      # 文檔的詞袋模型    每個單詞可以出現(xiàn)多次
        else:
            print("the word: %s is not in my Vocabulary!" % word)
    return returnVec

# 樸素貝葉斯分類器訓(xùn)練函數(shù)   從詞向量計算概率
def trainNB0(trainMatrix, trainCategory):
    # trainMatrix 是詞向量矩陣
    # trainCategory 是每個詞向量對應(yīng)的分類標(biāo)簽
    numTrainDocs = len(trainMatrix)   # 文檔數(shù)量
    numWords = len(trainMatrix[0])  # 詞向量特征數(shù)

    pAbusive = sum(trainCategory)/numTrainDocs  # 負(fù)面的概率

    # p0Num = zeros(numWords); p1Num = zeros(numWords)
    # p0Denom = 0.0; p1Denom = 0.0
    p0Num = ones(numWords);   # 避免一個概率值為0,最后的乘積也為0
    p1Num = ones(numWords);   # 用來統(tǒng)計兩類數(shù)據(jù)中,各詞的詞頻

    p0Denom = 2.0;  # 用于統(tǒng)計0類中的總數(shù)
    p1Denom = 2.0  # 用于統(tǒng)計1類中的總數(shù)
    # p1Num = trainMatrix[trainCategory == 1].sum(axis=0).astype(float) + 1
    # p0Num = trainMatrix[trainCategory == 0].sum(axis=0).astype(float) + 1
    # p1Denom = trainMatrix[trainCategory == 1].sum()+ 2
    # p0Denom = trainMatrix[trainCategory == 0].sum()+ 2
    # 下面的計算可以使用上面4個語句替代。
    for i in range(numTrainDocs):
        if trainCategory[i] == 1:
            p1Num += trainMatrix[I]
            p1Denom += sum(trainMatrix[I])
        else:
            p0Num += trainMatrix[I]
            p0Denom += sum(trainMatrix[I])

    # p1Vect = log(p1Num / p1Denom)    # 在類1中,每個詞的發(fā)生概率
    # p0Vect = log(p0Num / p0Denom)      # 避免下溢出或者浮點數(shù)舍入導(dǎo)致的錯誤   下溢出是由太多很小的數(shù)相乘得到的
    p1Vect = p1Num / p1Denom   # 負(fù)面:每個詞發(fā)生的頻率(不重復(fù)詞的列表,一共32個詞,對應(yīng)不同下標(biāo))
    p0Vect = p0Num / p0Denom   # 正面

    return p0Vect, p1Vect, pAbusive

# 樸素貝葉斯分類器
def classifyNB(vec2Classify, p0Vec, p1Vec, pClass1):
    p1 = sum(vec2Classify*p1Vec) * pClass1   # 由于分母都一樣,這里省略了分母
    p0 = sum(vec2Classify*p0Vec) * (1.0-pClass1) # 由于分母都一樣,這里省略了分母
    # print(p1, p0)
    if p1 > p0:
        return 1
    else:
        return 0

def testingNB():
    listOPosts, listClasses = loadDataSet()
    myVocabList = createVocabList(listOPosts)
    trainMat = []
    for postinDoc in listOPosts:
        trainMat.append(setOfWords2Vec(myVocabList, postinDoc))
    p0V, p1V, pAb = trainNB0(array(trainMat), array(listClasses))
    testEntry = ['love','my','dalmation']
    thisDoc = array(setOfWords2Vec(myVocabList, testEntry))
    print(testEntry, '分類是: ', classifyNB(thisDoc, p0V, p1V, pAb))
    testEntry = ['stupid','garbage']
    thisDoc = array(setOfWords2Vec(myVocabList, testEntry))
    print(testEntry, '分類是: ', classifyNB(thisDoc, p0V, p1V, pAb))

# 測試調(diào)用
testingNB()

['love', 'my', 'dalmation'] 分類是:  0
['stupid', 'garbage'] 分類是:  1

sklearn中文本特征處理-特征抽取

  • 很多時候,用戶數(shù)據(jù)是不適合機器學(xué)習(xí)算法的,需要做特殊的處理才能交給算法訓(xùn)練。比如文本數(shù)據(jù)。

  • 這些不能直接處理的數(shù)據(jù),需要轉(zhuǎn)換成計算能直接處理的數(shù)值型數(shù)據(jù),或者數(shù)值向量,或者矩陣。我們上面采用的方法就是其中的一種方式,當(dāng)然這種方式根據(jù)不同的數(shù)據(jù),處理方式也不同,但不過我們常用的數(shù)據(jù)除了數(shù)值型數(shù)據(jù),一般還包含:

    • 文本數(shù)據(jù);
    • 日期與時間數(shù)據(jù);
    • 圖像數(shù)據(jù);
    • 音頻與視頻數(shù)據(jù);
    • 其他數(shù)據(jù)。
  • 在這個主題內(nèi),我由于貝葉斯的主要場景是用于的場景:

    1. 文本分類
    2. 垃圾郵件過濾
    3. 病人分類
    4. 拼寫檢查

    都與文本有關(guān),所以這里我們專門講解下文本特征化相關(guān)的技能。

  • sklearn對文本的特征抽?。‵eature Extraction)函數(shù)包含:

    • feature_extraction.text.CountVectorizer([…])
      • 把文檔集合轉(zhuǎn)換為計數(shù)矩陣;
    • feature_extraction.text.HashingVectorizer([…])
      • 把文檔集合轉(zhuǎn)換為頻次矩陣;
    • feature_extraction.text.TfidfTransformer([…])
      • 把計數(shù)矩陣轉(zhuǎn)換為tf(Term frequency) 或者 tf-idf表示;
    • feature_extraction.text.TfidfVectorizer([…])
      • 把原生文檔集合轉(zhuǎn)換為TF-IDF特征矩陣.

CountVectorizer與HashingVectorizer類

  1. CountVectorizer
  • 注意CountVectorizer中使用的正則表達(dá)式。

    • ’(?u)\b\w\w+\b’ :(?u)用來支持unicode,還有其他修飾:
      • (?i)不區(qū)分大小寫
      • (?m)多行
      • (?s)單行
      • (?J)不允許出現(xiàn)重復(fù)的名字等。
  • 類構(gòu)造器定義

    class sklearn.feature_extraction.text.CountVectorizer(
        input=’content’, 
        encoding=’utf-8’, 
        decode_error=’strict’, 
        strip_accents=None, 
        lowercase=True,     # 大小寫
        preprocessor=None, 
        tokenizer=None, 
        stop_words=None,     # 禁止統(tǒng)計的詞
        token_pattern=’(?u)\b\w\w+\b’,    # 切分詞的正則表達(dá)式
        ngram_range=(1, 1), 
        analyzer=’word’, 
        max_df=1.0, 
        min_df=1, 
        max_features=None, 
        vocabulary=None, 
        binary=False, 
        dtype=<class ‘numpy.int64’>)
  • 屬性:

    • vocabulary_ : dict
  • 重要函數(shù):

    • get_feature_names(self)
# 從上面正則表達(dá)式可以知道,只有一個字母的單詞不抽取。
from sklearn.feature_extraction.text import CountVectorizer
content = ["Convert a collection of text documents to a matrix of token counts",
           "This implementation produces a sparse representation of the counts using scipy.sparse.csr_matrix."]
vectorizer = CountVectorizer(lowercase=False)
re = vectorizer.fit_transform(content)
# content的行數(shù),**詞典中索引為3的元素**, 詞頻
# (0, 3)    1   表示:第一行中,詞表中下標(biāo)為3的詞,出現(xiàn)頻次是1.(就是counts出現(xiàn)1次) 
print(re)
# 返回類型 scipy.sparse.csr.csr_matrix
# 獲取數(shù)據(jù)
names = vectorizer.get_feature_names()   # 返回特征名,結(jié)果是排序的
print(names)
ve = re.toarray()   # 返回content對應(yīng)的特征名統(tǒng)計(計數(shù))
ve

  (0, 3)    1
  (0, 16)   1
  (0, 7)    1
  (0, 15)   1
  (0, 5)    1
  (0, 13)   1
  (0, 8)    2
  (0, 2)    1
  (0, 0)    1
  (1, 4)    1
  (1, 11)   1
  (1, 17)   1
  (1, 14)   1
  (1, 10)   1
  (1, 12)   2
  (1, 9)    1
  (1, 6)    1
  (1, 1)    1
  (1, 3)    1
  (1, 8)    1
['Convert', 'This', 'collection', 'counts', 'csr_matrix', 'documents', 'implementation', 'matrix', 'of', 'produces', 'representation', 'scipy', 'sparse', 'text', 'the', 'to', 'token', 'using']





array([[1, 0, 1, 1, 0, 1, 0, 1, 2, 0, 0, 0, 0, 1, 0, 1, 1, 0],
       [0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 2, 0, 1, 0, 0, 1]],
      dtype=int64)
  1. HashingVectorizer
#  把字符串轉(zhuǎn)換為hash化的特征表示。
# This text vectorizer implementation uses the hashing trick 
# to find the token string name to feature integer index mapping.

from sklearn.feature_extraction.text import HashingVectorizer
content = ["Convert a collection of text documents to a matrix of token counts",
           "This implementation produces a sparse representation of the counts using scipy.sparse.csr_matrix."]

vectorizer = HashingVectorizer(n_features=2**16)
re = vectorizer.fit_transform(content)
# 返回類型 scipy.sparse.csr.csr_matrix
# 獲取數(shù)據(jù)
ve = re.toarray()   # 返回content對應(yīng)的字符串
ve


array([[0., 0., 0., ..., 0., 0., 0.],
       [0., 0., 0., ..., 0., 0., 0.]])

TfidfTransformer與TfidfVectorizer類

  • TF:表示詞頻率(Term Frequency)

    • 計算公式 : TF = \dfrac{詞出現(xiàn)的次數(shù)} {所有詞的總數(shù)}
  • IDF:表示逆文件頻率(Inverse Document Frequency)

    • 計算公式 : IDF = log \dfrac{文件總數(shù)}{出現(xiàn)詞的文件數(shù) + 1}
      • 分母+1的目的是防止除數(shù)為0
  • TF-IDF:

    • 計算公式 : \text{TF?IDF} = TF \times IDF
  • TF,IDF與TF-IDF的例子

import numpy as np
# 假設(shè)爬蟲爬取一篇網(wǎng)絡(luò)文章總字?jǐn)?shù)1000: Python,數(shù)據(jù)挖掘的出現(xiàn)的次數(shù)個30,20詞。
# TF=
tf1 = 30/100
tf2 = 20/100
print(tf1, tf2)

# 假設(shè)從網(wǎng)絡(luò)爬取的網(wǎng)頁是100萬,其中包含python的60萬,包含數(shù)據(jù)挖掘的0.4萬,
# IDF= 
idf1 = np.log10(100/(62))    #然對數(shù)還是常用對數(shù),在這里意義不大
idf2 =np.log10(100/(0.4))
print(idf1, idf2)

# TF-IDF=
tf_idf1 = tf1 * idf1
tf_idf2 = tf2 * idf2
print(tf_idf1, tf_idf2)
0.3 0.2
0.2076083105017461 2.3979400086720375
0.06228249315052383 0.4795880017344075
  1. TfidfTransformer
  • TfidfTransformer構(gòu)造器定義

    class sklearn.feature_extraction.text.TfidfTransformer(
        norm=’l2’, 
        use_idf=True, 
        smooth_idf=True, 
        sublinear_tf=False)   # 使用 1 + log(tf)替代tf

  • TfidfTransformer的作用:

    • 轉(zhuǎn)換計數(shù)矩陣為規(guī)范化tf 或者 tf-idf 表示,由參數(shù)決定:use_idf,默認(rèn)是 tf-idf
  • 屬性:

    • idf_ : array, shape (n_features)
#  把字符串轉(zhuǎn)換為hash化的特征表示。
# This text vectorizer implementation uses the hashing trick 
# to find the token string name to feature integer index mapping.

from sklearn.feature_extraction.text import CountVectorizer, TfidfTransformer
content = ["Convert a collection of text documents to a matrix of token counts",
           "This implementation produces a sparse representation of the counts using scipy.sparse.csr_matrix."]

count_vectorizer = CountVectorizer(lowercase=False)
re_count = count_vectorizer.fit_transform(content)
print(count_vectorizer.get_feature_names())
print(re_count)

tfidf_transformer = TfidfTransformer(use_idf=False)   # 修改use_idf為True觀察結(jié)果
re_tfidf = tfidf_transformer.fit_transform(re_count)

print(re_tfidf)   # tf_idf計算
# (0, 16)   0.3239110443766146 表示:在第一行中, 詞表中下標(biāo)為16的詞(token)的tf-idf為3239110443766146
print(re_tfidf.toarray())   # 矩陣形式的結(jié)果
['Convert', 'This', 'collection', 'counts', 'csr_matrix', 'documents', 'implementation', 'matrix', 'of', 'produces', 'representation', 'scipy', 'sparse', 'text', 'the', 'to', 'token', 'using']
  (0, 3)    1
  (0, 16)   1
  (0, 7)    1
  (0, 15)   1
  (0, 5)    1
  (0, 13)   1
  (0, 8)    2
  (0, 2)    1
  (0, 0)    1
  (1, 4)    1
  (1, 11)   1
  (1, 17)   1
  (1, 14)   1
  (1, 10)   1
  (1, 12)   2
  (1, 9)    1
  (1, 6)    1
  (1, 1)    1
  (1, 3)    1
  (1, 8)    1
  (0, 0)    0.2886751345948129
  (0, 2)    0.2886751345948129
  (0, 3)    0.2886751345948129
  (0, 5)    0.2886751345948129
  (0, 7)    0.2886751345948129
  (0, 8)    0.5773502691896258
  (0, 13)   0.2886751345948129
  (0, 15)   0.2886751345948129
  (0, 16)   0.2886751345948129
  (1, 1)    0.2672612419124244
  (1, 3)    0.2672612419124244
  (1, 4)    0.2672612419124244
  (1, 6)    0.2672612419124244
  (1, 8)    0.2672612419124244
  (1, 9)    0.2672612419124244
  (1, 10)   0.2672612419124244
  (1, 11)   0.2672612419124244
  (1, 12)   0.5345224838248488
  (1, 14)   0.2672612419124244
  (1, 17)   0.2672612419124244
[[0.28867513 0.         0.28867513 0.28867513 0.         0.28867513
  0.         0.28867513 0.57735027 0.         0.         0.
  0.         0.28867513 0.         0.28867513 0.28867513 0.        ]
 [0.         0.26726124 0.         0.26726124 0.26726124 0.
  0.26726124 0.         0.26726124 0.26726124 0.26726124 0.26726124
  0.53452248 0.         0.26726124 0.         0.         0.26726124]]
  1. TfidfVectorizer
  • 構(gòu)造器定義:

    lass sklearn.feature_extraction.text.TfidfVectorizer(
        input=’content’, 
        encoding=’utf-8’, 
        decode_error=’strict’, 
        strip_accents=None, 
        lowercase=True, 
        preprocessor=None, 
        tokenizer=None, 
        analyzer=’word’, 
        stop_words=None, 
        token_pattern=’(?u)\b\w\w+\b’, 
        ngram_range=(1, 1), 
        max_df=1.0, 
        min_df=1, 
        max_features=None, 
        vocabulary=None, 
        binary=False, 
        dtype=<class ‘numpy.float64’>, 
        norm=’l2’, 
        use_idf=True, 
        smooth_idf=True, 
        sublinear_tf=False)[source]

  • TfidfVectorizer的作用:
    • 直接把文檔轉(zhuǎn)換為tf或者tf-idf矩陣;
#  把字符串轉(zhuǎn)換為hash化的特征表示。
# This text vectorizer implementation uses the hashing trick 
# to find the token string name to feature integer index mapping.

from sklearn.feature_extraction.text import CountVectorizer, TfidfTransformer, TfidfVectorizer
content = ["Convert a collection of text documents to a matrix of token counts",
           "This implementation produces a sparse representation of the counts using scipy.sparse.csr_matrix."]

tf_idf_vectorizer = TfidfVectorizer(lowercase=False,use_idf=True)
re_tf_idf = tf_idf_vectorizer.fit_transform(content)
print(tf_idf_vectorizer.get_feature_names())
print(re_tf_idf)

print(re_tf_idf.toarray())
['Convert', 'This', 'collection', 'counts', 'csr_matrix', 'documents', 'implementation', 'matrix', 'of', 'produces', 'representation', 'scipy', 'sparse', 'text', 'the', 'to', 'token', 'using']
  (0, 0)    0.3239110443766146
  (0, 2)    0.3239110443766146
  (0, 8)    0.46093075168919306
  (0, 13)   0.3239110443766146
  (0, 5)    0.3239110443766146
  (0, 15)   0.3239110443766146
  (0, 7)    0.3239110443766146
  (0, 16)   0.3239110443766146
  (0, 3)    0.23046537584459653
  (1, 8)    0.19724216536132688
  (1, 3)    0.19724216536132688
  (1, 1)    0.2772169812630457
  (1, 6)    0.2772169812630457
  (1, 9)    0.2772169812630457
  (1, 12)   0.5544339625260915
  (1, 10)   0.2772169812630457
  (1, 14)   0.2772169812630457
  (1, 17)   0.2772169812630457
  (1, 11)   0.2772169812630457
  (1, 4)    0.2772169812630457
[[0.32391104 0.         0.32391104 0.23046538 0.         0.32391104
  0.         0.32391104 0.46093075 0.         0.         0.
  0.         0.32391104 0.         0.32391104 0.32391104 0.        ]
 [0.         0.27721698 0.         0.19724217 0.27721698 0.
  0.27721698 0.         0.19724217 0.27721698 0.27721698 0.27721698
  0.55443396 0.         0.27721698 0.         0.         0.27721698]]

sklearn中好用的數(shù)據(jù)結(jié)構(gòu)Bunch類

  • 使用對象屬性來管理字典的數(shù)據(jù)結(jié)構(gòu)。

    • 需要在構(gòu)造器定義類似字典的key。
  • 使用Bunch的好處是序列化非常方便。

from sklearn.datasets.base import Bunch
bunch  = Bunch(filed1=[], filed2=[])
print(bunch)

{'filed1': [], 'filed2': []}

關(guān)于分詞

  • Python的分詞模塊有很多,比較出名的是jieba。最新版本是0.39,安裝指令:
    • pip install jieba
    • 安裝過程截圖
  • 關(guān)于其他分詞工具
    • 百度直接搜索關(guān)鍵字:python分詞模塊,常見的有:
      • jieba(百度:https://github.com/fxsjy/jieba
      • THULAC(清華大學(xué)自然語言處理與社會人文計算實驗室)
      • SnowNLP(MIT)
      • pynlpir(大數(shù)據(jù)搜索挖掘?qū)嶒炇遥ū本┦泻A空Z言信息處理與云計算應(yīng)用工程技術(shù)研究中心))
      • CoreNLP
      • pyLTP
      • 盤古分詞
      • Yaha分詞

jieba分詞功能

import jieba
words = """
支持三種分詞模式:
1.精確模式,試圖將句子最精確地切開,適合文本分析;
2.全模式,把句子中所有的可以成詞的詞語都掃描出來, 速度非??欤遣荒芙鉀Q歧義;
3.搜索引擎模式,在精確模式的基礎(chǔ)上,對長詞再次切分,提高召回率,適合用于搜索引擎分詞。
乖乖隆地咚
"""
re_jieba = jieba.cut(words)
print(re_jieba)
print(list(re_jieba))
<generator object Tokenizer.cut at 0x11d448258>
['\n', '支持', '三種', '分', '詞模式', ':', '\n', '1', '.', '精確', '模式', ',', '試圖', '將', '句子', '最', '精確', '地', '切開', ',', '適合', '文本', '分析', ';', '\n', '2', '.', '全', '模式', ',', '把', '句子', '中', '所有', '的', '可以', '成詞', '的', '詞語', '都', '掃描', '出來', ',', ' ', '速度', '非常', '快', ',', '但是', '不能', '解決', '歧義', ';', '\n', '3', '.', '搜索引擎', '模式', ',', '在', '精確', '模式', '的', '基礎(chǔ)', '上', ',', '對長', '詞', '再次', '切分', ',', '提高', '召回', '率', ',', '適合', '用于', '搜索引擎', '分詞', '。', '\n', '乖乖隆地咚', '\n']

添加自定義詞典

  • 字典格式:
    • 一個詞占一行;
    • 每一行分三部分,每個部分使用一個空格分隔,按照下列順序。
      • 詞語
      • 詞頻(可省略)
      • 詞性(可省略)
import jieba
words = """
支持三種分詞模式:
1.精確模式,試圖將句子最精確地切開,適合文本分析;
2.全模式,把句子中所有的可以成詞的詞語都掃描出來, 速度非???,但是不能解決歧義;
3.搜索引擎模式,在精確模式的基礎(chǔ)上,對長詞再次切分,提高召回率,適合用于搜索引擎分詞。
乖乖隆地咚
"""
jieba.load_userdict('jieba/dict.txt')
re_jieba = jieba.cut(words)
print(re_jieba)
print(list(re_jieba))
help(jieba.cut)
<generator object Tokenizer.cut at 0x11b952f10>
['\n', '支持', '三種', '分', '詞模式', ':', '\n', '1', '.', '精確', '模式', ',', '試圖', '將', '句子', '最', '精確', '地', '切開', ',', '適合', '文本', '分析', ';', '\n', '2', '.', '全', '模式', ',', '把', '句子', '中', '所有', '的', '可以', '成詞', '的', '詞語', '都', '掃描', '出來', ',', ' ', '速度', '非常', '快', ',', '但是', '不能', '解決', '歧義', ';', '\n', '3', '.', '搜索引擎', '模式', ',', '在', '精確', '模式', '的', '基礎(chǔ)', '上', ',', '對長', '詞', '再次', '切分', ',', '提高', '召回', '率', ',', '適合', '用于', '搜索引擎', '分詞', '。', '\n', '乖乖隆地咚', '\n']
Help on method cut in module jieba:

cut(sentence, cut_all=False, HMM=True) method of jieba.Tokenizer instance
    The main function that segments an entire sentence that contains
    Chinese characters into seperated words.
    
    Parameter:
        - sentence: The str(unicode) to be segmented.
        - cut_all: Model type. True for full pattern, False for accurate pattern.
        - HMM: Whether to use the Hidden Markov Model.

分詞中符號的處理

import jieba
import re
words = """
支持三種分詞模式:
1.精確模式,試圖將句子最精確地切開,適合文本分析;
2.全模式,把句子中所有的可以成詞的詞語都掃描出來, 速度非??欤遣荒芙鉀Q歧義;
3.搜索引擎模式,在精確模式的基礎(chǔ)上,對長詞再次切分,提高召回率,適合用于搜索引擎分詞。
乖乖隆地咚
"""
# 替換符號
words_no_punctuation = re.sub(r"[0-9\s+\.\!\/_,$%^*()?;;:-【】+\"\']+|[+——!,;:。?、~@#¥%……&*()]+", "", words) #去標(biāo)點符號
# print(words_no_punctuation)
jieba.load_userdict('jieba/dict.txt')
re_jieba = jieba.cut(words_no_punctuation)
print(re_jieba)
print(list(re_jieba))
# help(jieba.cut)
<generator object Tokenizer.cut at 0x11d425048>
['支持', '三種', '分', '詞模式', ':', '精確', '模式', '試圖', '將', '句子', '最', '精確', '地', '切開', '適合', '文本', '分析', '全', '模式', '把', '句子', '中', '所有', '的', '可以', '成詞', '的', '詞語', '都', '掃描', '出來', '速度', '非常', '快', '但是', '不能', '解決', '歧義', '搜索引擎', '模式', '在', '精確', '模式', '的', '基礎(chǔ)', '上', '對', '長詞', '再次', '切分', '提高', '召回', '率', '適合', '用于', '搜索引擎', '分詞', '乖乖隆地咚']

簡歷分類實現(xiàn)代碼

#coding=utf-8
import jieba
import os
import pickle
from numpy import *
from sklearn import feature_extraction
from sklearn.feature_extraction.text import TfidfTransformer  # TF-IDF向量轉(zhuǎn)換類
from sklearn.feature_extraction.text import TfidfVectorizer  # TF_IDF向量生成類
from sklearn.datasets.base import Bunch
from sklearn.naive_bayes import MultinomialNB  # 多項式貝葉斯算法


def readFile(path):
    with open(path, 'r', errors='ignore') as file:  #忽略編碼錯誤
        content = file.read()
        return content


def saveFile(path, result):
    with open(path, 'w', errors='ignore') as file:
        file.write(result)


def segText(inputPath, resultPath):
    fatherLists = os.listdir(inputPath)  # 主目錄
    for eachDir in fatherLists:  # 遍歷主目錄中各個文件夾
        if eachDir.startswith('.'):
            continue
        eachPath = inputPath + eachDir + "/"  # 保存主目錄中每個文件夾目錄,便于遍歷二級文件
        each_resultPath = resultPath + eachDir + "/"  # 分詞結(jié)果文件存入的目錄
        if not os.path.exists(each_resultPath):
            os.makedirs(each_resultPath)
        childLists = os.listdir(eachPath)  # 獲取每個文件夾中的各個文件
        for eachFile in childLists:  # 遍歷每個文件夾中的子文件
            eachPathFile = eachPath + eachFile  # 獲得每個文件路徑
            content = readFile(eachPathFile)  # 調(diào)用上面函數(shù)讀取內(nèi)容
            result = (str(content)).replace("\r\n", "").strip()  # 刪除多余空行與空格
            cutResult = jieba.cut(result)  # 默認(rèn)方式分詞,分詞結(jié)果用空格隔開
            saveFile(each_resultPath + eachFile, " ".join(cutResult))  # 調(diào)用上面函數(shù)保存文件


def bunchSave(inputFile, outputFile):
    catelist = os.listdir(inputFile)
    bunch = Bunch(target_name=[], label=[], filenames=[], contents=[])
    bunch.target_name.extend(catelist)  # 將類別保存到Bunch對象中
    for eachDir in catelist:
        if eachDir.startswith('.'):
            continue
        eachPath = inputFile + eachDir + "/"
        fileList = os.listdir(eachPath)
        for eachFile in fileList:  # 二級目錄中的每個子文件
            fullName = eachPath + eachFile  # 二級目錄子文件全路徑
            bunch.label.append(eachDir)  # 當(dāng)前分類標(biāo)簽
            bunch.filenames.append(fullName)  # 保存當(dāng)前文件的路徑
            bunch.contents.append(readFile(fullName).strip())  # 保存文件詞向量
    with open(outputFile, 'wb') as file_obj:  # 持久化必須用二進制訪問模式打開
        pickle.dump(bunch, file_obj)
        #pickle.dump(obj, file, [,protocol])函數(shù)的功能:將obj對象序列化存入已經(jīng)打開的file中。
        #obj:想要序列化的obj對象。
        #file:文件名稱。
        #protocol:序列化使用的協(xié)議。如果該項省略,則默認(rèn)為0。如果為負(fù)值或HIGHEST_PROTOCOL,則使用最高的協(xié)議版本
def readBunch(path):
    with open(path, 'rb') as file:
        bunch = pickle.load(file)
        #pickle.load(file)
        #函數(shù)的功能:將file中的對象序列化讀出。
    return bunch


def writeBunch(path, bunchFile):
    with open(path, 'wb') as file:
        pickle.dump(bunchFile, file)


def getStopWord(inputFile):
    stopWordList = readFile(inputFile).splitlines()
    return stopWordList


def getTFIDFMat(inputPath, stopWordList, outputPath):  # 求得TF-IDF向量
    bunch = readBunch(inputPath)
    tfidfspace = Bunch(target_name=bunch.target_name,label=bunch.label, filenames=bunch.filenames, tdm=[],
                       vocabulary={})
    # 初始化向量空間
    vectorizer = TfidfVectorizer(stop_words=stopWordList, sublinear_tf=True, max_df=0.5)
    # transformer = TfidfTransformer()  # 該類會統(tǒng)計每個詞語的TF-IDF權(quán)值
    # 文本轉(zhuǎn)化為詞頻矩陣,單獨保存字典文件
    tfidfspace.tdm = vectorizer.fit_transform(bunch.contents)
    tfidfspace.vocabulary = vectorizer.vocabulary_   #獲取詞匯
    writeBunch(outputPath, tfidfspace)

def getTestSpace(testSetPath, trainSpacePath, stopWordList, testSpacePath):
    bunch = readBunch(testSetPath)
    # 構(gòu)建測試集TF-IDF向量空間
    testSpace = Bunch(target_name=bunch.target_name, label=bunch.label, filenames=bunch.filenames, tdm=[],
                      vocabulary={})
    # 導(dǎo)入訓(xùn)練集的詞袋
    trainbunch = readBunch(trainSpacePath)
    # 使用TfidfVectorizer初始化向量空間模型  使用訓(xùn)練集詞袋向量
    vectorizer = TfidfVectorizer(stop_words=stopWordList, sublinear_tf=True, max_df=0.5,
                                 vocabulary=trainbunch.vocabulary)
    # transformer = TfidfTransformer()
    testSpace.tdm = vectorizer.fit_transform(bunch.contents)
    testSpace.vocabulary = trainbunch.vocabulary
    # 持久化
    writeBunch(testSpacePath, testSpace)

def bayesAlgorithm(trainPath, testPath):
    trainSet = readBunch(trainPath)
    testSet = readBunch(testPath)
    clf = MultinomialNB(alpha=0.001).fit(trainSet.tdm, trainSet.label)
    #alpha:0.001 alpha 越小,迭代次數(shù)越多,精度越高
    #print(shape(trainSet.tdm))  #輸出單詞矩陣的類型
    #print(shape(testSet.tdm))
    predicted = clf.predict(testSet.tdm)
    total = len(predicted)
    rate = 0
    for flabel, fileName, expct_cate in zip(testSet.label, testSet.filenames, predicted):
        if flabel != expct_cate:
            rate += 1
            print(fileName, ":實際類別:", flabel, "-->預(yù)測類別:", expct_cate)
    print("erroe rate:", float(rate) * 100 / float(total), "%")


# 分詞,第一個是分詞輸入,第二個參數(shù)是結(jié)果保存的路徑
segText("./dataset/data/", "./dataset/segResult/")   # 分詞
bunchSave("./dataset/segResult/", "./dataset/train_set.dat")  # 輸入分詞,輸出分詞向量
stopWordList = getStopWord("./dataset/stop/stopword.txt")  # 獲取停用詞
getTFIDFMat("./dataset/train_set.dat", stopWordList, "./dataset/tfidfspace.dat")  # 輸入詞向量,輸出特征空間

# 訓(xùn)練集
segText("./dataset/test1/", "./dataset/test_segResult/")  # 分詞
bunchSave("./dataset/test_segResult/", "./dataset/test_set.dat")

getTestSpace("./dataset/test_set.dat", "./dataset/tfidfspace.dat", stopWordList, "./dataset/testspace.dat")
bayesAlgorithm("./dataset/tfidfspace.dat", "./dataset/testspace.dat")

/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/sklearn/feature_extraction/text.py:300: UserWarning: Your stop_words may be inconsistent with your preprocessing. Tokenizing the stop words generated tokens ['ain', 'aren', 'couldn', 'didn', 'doesn', 'don', 'hadn', 'hasn', 'haven', 'isn', 'll', 'mon', 'shouldn', 've', 'wasn', 'weren', 'won', 'wouldn'] not in stop_words.
  'stop_words.' % sorted(inconsistent))


./dataset/test_segResult/10k-18k/3496172.txt :實際類別: 10k-18k -->預(yù)測類別: 10k-20k
./dataset/test_segResult/10k-18k/4543973.txt :實際類別: 10k-18k -->預(yù)測類別: 7k-9k
./dataset/test_segResult/10k-18k/4751316.txt :實際類別: 10k-18k -->預(yù)測類別: 15k-30k
./dataset/test_segResult/10k-20k/326941.txt :實際類別: 10k-20k -->預(yù)測類別: 10k-16k
./dataset/test_segResult/10k-20k/3770831.txt :實際類別: 10k-20k -->預(yù)測類別: 15k-20k
./dataset/test_segResult/10k-20k/3867925.txt :實際類別: 10k-20k -->預(yù)測類別: 15k-25k
./dataset/test_segResult/10k-20k/4072821.txt :實際類別: 10k-20k -->預(yù)測類別: 20k-40k
./dataset/test_segResult/10k-20k/4498906.txt :實際類別: 10k-20k -->預(yù)測類別: 7k-14k
./dataset/test_segResult/10k-20k/4580091.txt :實際類別: 10k-20k -->預(yù)測類別: 15k-25k
./dataset/test_segResult/10k-20k/4715977.txt :實際類別: 10k-20k -->預(yù)測類別: 20k-40k
./dataset/test_segResult/10k-20k/4772554.txt :實際類別: 10k-20k -->預(yù)測類別: 20k-40k
./dataset/test_segResult/10k-20k/4838990.txt :實際類別: 10k-20k -->預(yù)測類別: 25k-50k
./dataset/test_segResult/10k-20k/4875752.txt :實際類別: 10k-20k -->預(yù)測類別: 15k-30k
./dataset/test_segResult/10k-20k/4932878.txt :實際類別: 10k-20k -->預(yù)測類別: 3k-6k
./dataset/test_segResult/10k-20k/4961212.txt :實際類別: 10k-20k -->預(yù)測類別: 13k-26k
./dataset/test_segResult/10k-20k/4967915.txt :實際類別: 10k-20k -->預(yù)測類別: 25k-50k
./dataset/test_segResult/10k-20k/5020579.txt :實際類別: 10k-20k -->預(yù)測類別: 8k-12k
./dataset/test_segResult/10k-20k/5062668.txt :實際類別: 10k-20k -->預(yù)測類別: 15k-30k
./dataset/test_segResult/10k-20k/5083284.txt :實際類別: 10k-20k -->預(yù)測類別: 8k-14k
./dataset/test_segResult/10k-20k/5107023.txt :實際類別: 10k-20k -->預(yù)測類別: 20k-30k
./dataset/test_segResult/10k-20k/5124617.txt :實際類別: 10k-20k -->預(yù)測類別: 12k-24k
./dataset/test_segResult/10k-20k/5143794.txt :實際類別: 10k-20k -->預(yù)測類別: 8k-14k
./dataset/test_segResult/10k-20k/5155415.txt :實際類別: 10k-20k -->預(yù)測類別: 15k-30k
./dataset/test_segResult/10k-20k/5158775.txt :實際類別: 10k-20k -->預(yù)測類別: 15k-30k
./dataset/test_segResult/10k-20k/5179499.txt :實際類別: 10k-20k -->預(yù)測類別: 13k-15k
./dataset/test_segResult/10k-20k/5185464.txt :實際類別: 10k-20k -->預(yù)測類別: 20k-40k
./dataset/test_segResult/10k-20k/5188881.txt :實際類別: 10k-20k -->預(yù)測類別: 17k-25k
./dataset/test_segResult/10k-20k/5209220.txt :實際類別: 10k-20k -->預(yù)測類別: 18k-30k
./dataset/test_segResult/10k-20k/5266604.txt :實際類別: 10k-20k -->預(yù)測類別: 6k-10k
./dataset/test_segResult/10k-20k/5267640.txt :實際類別: 10k-20k -->預(yù)測類別: 15k-25k
./dataset/test_segResult/10k-20k/5268311.txt :實際類別: 10k-20k -->預(yù)測類別: 20k-40k
./dataset/test_segResult/10k-20k/5278296.txt :實際類別: 10k-20k -->預(yù)測類別: 12k-20k
./dataset/test_segResult/10k-20k/5296243.txt :實際類別: 10k-20k -->預(yù)測類別: 15k-30k
./dataset/test_segResult/10k-20k/5297948.txt :實際類別: 10k-20k -->預(yù)測類別: 13k-15k
./dataset/test_segResult/10k-20k/5304000.txt :實際類別: 10k-20k -->預(yù)測類別: 20k-30k
./dataset/test_segResult/小強/4897063.txt :實際類別: 小強 -->預(yù)測類別: 11k-20k
erroe rate: 12.203389830508474 %

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容