機器學習之紅樓夢作者判斷(貝葉斯分類)

swensun發表於2018-05-27

上篇文章不帶假設的使用聚類演算法去判斷紅樓夢的作者,這一篇打算使用監督學習方法的貝葉斯分類,假設後四十回不是曹雪芹所寫, 去做個驗證。

關於我讀過比較好的貝葉斯講解:A simple explanation of Naive Bayes Classification

基本過程

先帶入假設,前80回和後40回不是同一人所寫。利用上篇文章構建的詞向量,對資料集進行分層隨機抽樣,比如隨機選取前80中的60回,後40中的30回進行訓練,然後進行預測。如果預測效果很好的話,說明我們的假設正確。 後續可以做個驗證,只使用前80回,對前後40回打上0, 1標籤。進行同樣訓練。由於同一人所寫,預測難度加大, 如果精確度不如上一步,則側面證明假設正確。

準備工作

import os
import numpy as np
import pandas as pd
import re
import sys  
import matplotlib.pyplot as plt

text = pd.read_csv("./datasets/hongloumeng.csv")
import jieba
import jieba.analyse

vorc = [jieba.analyse.extract_tags(i, topK=1000) for i in text["text"]]
vorc = [" ".join(i) for i in vorc]

from  sklearn.feature_extraction.text import CountVectorizer
vertorizer = CountVectorizer(max_features=5000)
train_data_features = vertorizer.fit_transform(vorc)

train_data_features = train_data_features.toarray()

train_data_features.shape
複製程式碼

上述是準備工作,生成詞向量。

標籤生成

labels = np.array([[0] * 80 + [1] * 40]).reshape(-1 ,1) # 目標值
labels.shape
複製程式碼

這一步生成目標labels。

分層隨機抽樣

# 分層抽樣
from sklearn.model_selection import train_test_split
# train_data_features = train_data_features[0:80]
X_train, X_test, Y_train, Y_test = train_test_split(train_data_features, labels, 
                                                    test_size = 0.2, stratify=labels)
複製程式碼

這裡做過多解釋, stratify=labels 表示按照目標類別進行隨機抽樣。

模型訓練和預測

from sklearn.naive_bayes import GaussianNB
from sklearn.linear_model import LogisticRegression

gnb = GaussianNB()
gnb.fit(X_train, Y_train)

y_pred = gnb.predict(X_test)
複製程式碼

對得到的預測值進行精確度計算:

from sklearn.metrics import accuracy_score
accuracy_score(Y_test, y_pred)
# 0.875
複製程式碼

分層交叉驗證

from sklearn.model_selection import StratifiedShuffleSplit
sss = StratifiedShuffleSplit(n_splits=10,test_size=0.2)
for train_index, test_index in sss.split(train_data_features, labels):
    X_train, X_test = train_data_features[train_index], train_data_features[test_index]
    Y_train, Y_test = labels[train_index], labels[test_index]
    gnb = GaussianNB()
    gnb.fit(X_train, Y_train)
    Y_pred = gnb.predict(X_test)
    scores.append(accuracy_score(Y_test, Y_pred))
print(scores)
print(np.array(scores).mean())
複製程式碼

輸出結果如下:

[0.9166666666666666, 0.8333333333333334, 1.0, 0.875, 0.75, 0.8333333333333334, 0.8333333333333334, 0.9583333333333334, 0.875, 0.8333333333333334]
0.8708333333333333
複製程式碼

如上,可以對文章剛開始的假設做個解釋,初步判斷我們的假設正確。

交叉驗證

labels_val = np.array([[0] * 40 + [1] * 40]).reshape(-1 ,1) # 目標值
sss_val = StratifiedShuffleSplit(n_splits=5,test_size=0.2)#分成5組,測試比例為0.25,訓練比例是0.75
scores = []
train_data_features_val = train_data_features[0:80]
for train_index, test_index in sss_val.split(train_data_features_val, labels_val):
    X_train, X_test = train_data_features_val[train_index], train_data_features_val[test_index]
    Y_train, Y_test = labels_val[train_index], labels_val[test_index]
    gnb = GaussianNB()
    gnb.fit(X_train, Y_train)
    Y_pred = gnb.predict(X_test)
    scores.append(accuracy_score(Y_test, Y_pred))
print(scores)
print(np.array(scores).mean())
複製程式碼

輸出結果如下:

[0.8125, 0.875, 0.75, 0.875, 0.75]
0.8125
複製程式碼

經過多次計算求平均值,後者得到的平均分數都低於前者, 文章開頭的假設正確。

完整程式碼:github

相關文章