07 朴素葉貝斯算法
概率基礎
- 概率: 一件事情發生的可能性
- 聯合概率: 包含多個條件,且所有條件同時成立的概率。P(A,B)
P(A, B) = P(A)P(B) - 條件概率:事件A在另外一個事件B已經發生條件下發生的概率。 P(A|B)
P(A1,A2 | B) = P(A1 | B) * P(A2 | B)
注意: 此條件概率的成立,是由於A1, A2相互獨立的結果
朴素貝葉斯
- 朴素: 特征獨立,常用文檔分類
- 在給定詞比例的基礎上,求各類型文檔的比例
- 貝葉斯公式: (多個條件下一個結果)
- 公式分為3個部分:
- P(C): 每個文檔類別的概率 (某類文檔數/總文檔數)
- P(W | C):給定類別下特征(被預測文檔中出現的詞)的概率:計算方法:P(F1|C) = Ni/N
- Ni : F1詞在C類別文檔所有文檔出現的次數
- N: 所屬C類別下的文檔所有詞出現的次數和
- P(F1,F2,F3) : 預測文檔中每個詞的概率
- 文檔分類: 給定一個文檔的條件下,求文檔所屬於科技、娛樂等類別的概率。哪個類別的概率大,則歸為某個類別。
-
文檔:詞1, 詞2 , 詞3 (詞出現的數量的情況下,判斷類別)
- P(科技|詞1,詞2,詞3) = P(f1,f2,f3 | 科技)*P(科技)/P(W)
- P(娛樂|詞1,詞2,詞3) = P(f1,f2,f3 | 娛樂)*P(娛樂)/P(W)
-
由於是概率大小,則P(W)可以同時約去
文檔分類實例
特征 | 科技(30篇) | 娛樂(60篇) | 匯總(90篇) |
---|---|---|---|
商場 | 9 | 51 | 60 |
影院 | 8 | 56 | 64 |
支付寶 | 20 | 15 | 35 |
雲計算 | 63 | 0 | 63 |
匯總(求和) | 100 | 121 | 221 |
現有一篇預測文檔,出現了影院,支付寶,雲計算,計算屬於科技、娛樂的概率。
- 科技: P(科技 |影院,支付寶,雲計算)= P(影院,支付寶,雲計算| 科技)* P(科技)= P(影院|科技)P(支付寶|科技) P(雲計算|科技)P(科技)= (8/100)* (20/100)* (63/100)*(30/90) = 0.00456109
- 娛樂:P(娛樂 |影院,支付寶,雲計算)= (56/121)(15/121)(0/121)(60/90)= 0
拉普拉斯平滑
- 目的:避免單個特征詞出現次數為0 ,導致最終的計算結果為0 。
- 原因:其他的詞在這個類型文檔中出現過,則還是有可能屬於這個文檔。
- P(F1|C) = (Ni +a) /(N+am)
- a為指定的系數,一般取1
- m為訓練文檔中統計出的特征詞的個數 (上述例子中為4)
sklearn朴素貝葉斯API
sklearn.naive_bayes.MultinomialNB (alpha = 1.0)
朴素貝葉斯算法案例 (sklearn 20類新聞分類)
案例流程
- 加載數據,進行分割
- 生成文章特征詞
- 朴素貝葉斯estimator進行預估
算法總結
- 訓練集誤差大,結果肯定不好
- 不需要調參
- 優點:
- 發源於古典數學理論,有穩定的分類效率
- 對缺失數據不太敏感,算法也比較簡單,常用於文本分類
- 分類准確率高,速度快
- 缺點:
- 由於使用樣本獨立性假設,對樣本屬性有關聯時效果不好
分類模型評估
常見評估方法
-
estimator.score() - 准確率,預測結果正確的百分比
-
精確率(precision) - 預測結果為正例樣本中真實為正例的比例(查的准)
-
召回率(recall) - 真實為正例的樣本中預測結果為正例的比例(查的全)
-
F1-score - 反映了模型的穩定性
混淆矩陣
- 定義:在分類任務中,預測結果(Predicted condition) 與正確標記 (True condition)之間存在四種不同的組合,構成混淆矩陣。
分類評估API
sklearn.metrics.classification_report(y_true, y_pred, target_names=None)
- y_true: 真實目標值
- y_pred: 估計器預測目標值
- target_names: 目標類別名稱
- return: 每個類別精確率和召回率
案例代碼
from sklearn.datasets import fetch_20newsgroups
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.model_selection import train_test_split
from sklearn.naive_bayes import MultinomialNB
from sklearn.metrics import classification_report
def naivebayes():
"""
朴素貝葉斯進行文本分類
:return: None
"""
news = fetch_20newsgroups(subset='all')
# 進行數據分割
x_train, x_test, y_train, y_test = train_test_split(news.data, news.target_names, test_size=0.25 )
# 對數據集進行特征抽取
tf = TfidfVectorizer()
# 以訓練集當中的詞的列表進行每篇文章重要性統計
x_train = tf.fit_transform(x_train)
print(tf.get_feature_names())
x_test = tf.transform(x_test)
# 進行朴素貝葉斯算法的計算
mlt = MultinomialNB(alpha=1.0)
mlt.fit(x_train, y_train)
print(x_train)
y_predict = mlt.predict(x_test)
print("預測的文章類別為:", y_predict)
score = mlt.score(x_test, y_test)
print("分類准確率為:", score)
print("每個類別的精確率和召回率:", classification_report
(y_test,y_predict,target_names=news.target_names))
return None
if __name__ == '__main__':
naivebayes()
模型的選擇與調優
交叉驗證過程
-
定義: 將拿到的訓練數據,氛圍訓練和驗證集。將數據分為5份,其中一份作為驗證集,然后經過5次(組)的測試,每次都更換不同的驗證集。即得到5組模型的結果,取平均值作為最終結果。又稱為5折交叉驗證。
-
圖示:
超參數搜索 - 網格搜索
-
超參數:通常情況下,有很多的參數是需要手動指定的(如K-近鄰算法中的K值),這種參數就是超參數。 (外部可以調整的參數)
-
網格搜索:手動的調參過程繁雜,所以需要對模型預設集中超參數組合,每組超參數都采用交叉驗證來進行評估,最后選擇最優參數組合建立模型。
-
多個參數時:需要進行兩兩組合,或者多多組合。
sklearn API
-
sklearn.model_selection.GridSearchCV(estimator,param_grid=None,cv=None) (CV: cross validation)
- 對估計器的指定參數值進行詳盡搜索
- estimator: 估計器對象
- param_grid: 估計器參數(dict): {"n_neighbors": [1,3,5]}
- cv: 指定幾折交叉驗證
- fit: 輸入訓練數據
- score: 准確率
- best_score_: 在交叉驗證中驗證的最好結果
- best_estimator_: 最好的參數模型
- cv_results_: 每次交叉驗證后的測試集准確率結果和訓練集准確率結果
from sklearn.neighbors import KNeighborsClassifier
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import train_test_split,GridSearchCV
import pandas as pd
def knncls():
"""
K-近鄰預測用戶簽到位置
:return: None
"""
# 讀取數據
data = pd.read_csv('./train.csv')
# print(data.head(10))
# 處理數據
# 1.縮小數據
data = data.query('x >1.0 & x < 1.25 & y > 2.5 & y < 2.75')
# 2. 處理時間數據
time_value = pd.to_datetime(data['time'], unit='s')
# print(time_value)
# 3. 構造一些特征, 把日期格式轉換為字典格式
time_value = pd.DatetimeIndex(time_value)
data['day'] = time_value.day
data['weekday'] = time_value.weekday
data['hour'] = time_value.hour
# 4.把時間戳特征刪除
data = data.drop(['time'],axis=1)
# print(data)
# 5.把簽到數量少於n個的目標位置刪除
place_count = data.groupby('place_id').count() # 統計place_id次數,變成行索引
tf = place_count[place_count.row_id > 3].reset_index() # row_id 具體次數,reset_index 把place_id生成新的一列
data = data[data['place_id'].isin(tf.place_id)] # 篩選place_id
# print(data)
# 6.取出數據中的特征值和目標值
y = data['place_id']
x = data.drop(['place_id', 'row_id'], axis=1) # 去掉row_id 可以增加精度
# 7.分割訓練集和測試集
x_train, x_test, y_train, y_text = train_test_split(x, y, test_size=0.25)
# 8.特征工程(標准化)
std = StandardScaler()
x_train = std.fit_transform(x_train)
x_test = std.transform(x_test)
# 進行算法流程 fit, predict, score #超參數
knn = KNeighborsClassifier() # 使用網格搜索時,不用設定超參數
# knn.fit(x_train, y_train)
#
# # 得出預測結果
# y_predict = knn.predict(x_test)
# print('預測的目標簽到位置為:', y_predict)
#
# # 得出准確率
# print('預測的准確率為:', knn.score(x_test, y_text))
# 9. 進行網格搜索
param = {'n_neighbors': [3,5,10]}
gc = GridSearchCV(knn, param_grid=param, cv=2)
gc.fit(x_train, y_train)
# 10.預測准確率
print("在測試集上的准確率:", gc.score(x_test, y_text))
print("在交叉驗證中最好的結果:", gc.best_score_)
print('選擇的最好的模型:', gc.best_estimator_)
print('每個超參數每次驗證的結果:', gc.cv_results_)
return None
if __name__ == '__main__':
knncls()