<jupyter_start><jupyter_text>Scikit-learn 中的 3 个朴素贝叶斯分类算法 高斯朴素贝叶斯(GaussianNB)特征变量是连续变量，符合高斯分布，如：人的身高，物体的长度。（正态分布） 多项式朴素贝叶斯(MultinomialNB)特征变量是离散变量，符合多项分布，在文档分类中体现在一个单词出现的次数，或者是单词的 TF-IDF 值等。 伯努利朴素贝叶斯(BernoulliNB)特征变量是布尔变量，符合 0/1 分布，在文档分类中特征是单词是否出现。**注：*** 这三个类适用的分类场景各不相同，一般来说，如果样本特征的分布大部分是连续值，使用 GaussianNB 会比较好。* 如果样本特征的分大部分是多元离散值，使用 MultinomialNB 比较合适。* 如果样本特征是二元离散值或者很稀疏的多元离散值，应该使用 BernoulliNB。  TF-IDF 值用于评估某个词语对于一个文件集或文档库中的其中一份文件的重要程度。 词频 TF(Term Frequency)计算了一个单词在文档中的出现次数。认为：**一个单词的重要性和它在文档中出现的次数成正比。** 逆向文档频率 IDF(Inverse Document Frequency)指一个单词在文档中的区分度。认为：**一个单词出现在的文档数越少，越能够通过这个单词把该文档和其它文档区分开。IDF 越大代表该单词的区分度越大。** TF-IDF 实际上是 TF 和 IDF 的乘积倾向于找到某个单词，在一个文档中出现次数多，同时又很少出现在其它文档中。这种单词适合做分类。 计算公式* 词频 TF = 单词出现的次数 / 该文档的总单词数* 逆向文档频率 IDF = log (文档总数 / 该单词出现的文档数 + 1) *注：+1 是为了防止分母为 0，即某些单词不出现在文档中。*  TfidfVectorizer 类的创建sklearn 中的 TfidfVectorizer 类，计算单词的 TF-IDF 值，对数底为 e。```TfidfVectorizer(stop_words=stop_words, token_pattern=token_pattern)```* stop_words：自定义停用词列表（停用词即为分类中没有用的词，TF 高，IDF 低），List 型。* token_pattern：过滤规则，正则表达式。 fit_transform(X)* 拟合模型，返回文本矩阵。* 属性： * vocabulary_：词汇表，字典型。 * idf_：返回 idf 值。 * stop_words_：返回停用词表。<jupyter_code>from sklearn.feature_extraction.text import TfidfVectorizer

tfidf_vec = TfidfVectorizer()

documents = [
    "this is the bayes document",
    "this is the second document",
    "and the third one",
    "is this the document"
]

tfidf_matrix = tfidf_vec.fit_transform(documents)
print("不重复的词: ", tfidf_vec.get_feature_names())
# 输出每个单词对应的 ID
print("每个单词对应的 ID: ", tfidf_vec.vocabulary_)
# 输出每个单词在每个文档中的 TF-IDF 值，向量顺序按词语的 ID 顺序
print("每个单词的 TF-IDF 值: ", tfidf_matrix.toarray())<jupyter_output>每个单词的 TF-IDF 值:  [[0.         0.63314609 0.40412895 0.40412895 0.         0.
  0.33040189 0.         0.40412895]
 [0.         0.         0.40412895 0.40412895 0.         0.63314609
  0.33040189 0.         0.40412895]
 [0.55280532 0.         0.         0.         0.55280532 0.
  0.28847675 0.55280532 0.        ]
 [0.         0.         0.52210862 0.52210862 0.         0.
  0.42685801 0.         0.52210862]]<jupyter_text>文档分类* **基于分词的数据准备**：包括分词、去掉停用词、单词权重计算。* **应用朴素贝叶斯分类进行分类**：通过训练集得到朴素贝叶斯分类器，将分类器应用于测试集，与实际结果对比，得到测试集的分类准确率  对文档进行分词* 英文文档：NLTK 包。* 中文文档：jieba 包。<jupyter_code>import nltk

text = "We all carry fear, and accepting the type of fear you carry is the first step in pushing past it."
word_list = nltk.word_tokenize(text) # 分词
nltk.pos_tag(word_list) # 标注单词的词性
import jieba

text_cn = "大漠孤烟直，长河落日圆。"
word_list = jieba.cut(text_cn) # 中文分词<jupyter_output><empty_output><jupyter_text>加载停用词表* 网上找到中文停用词表 stop_words.txt，利用 Python 读取后保存在 stop_words 数组中<jupyter_code>import os

file_path_zh = "data/stopwords_zh.txt"
stop_words_zh = [line.strip() for line in open(file_path_zh, 'r', encoding='utf-8').readlines()]<jupyter_output><empty_output><jupyter_text>计算单词的权重* 创建 TfidfVectorizer 类，使用 fit_transform() 拟合，得到 TF-IDF 特征空间 features，选出来的分词就是特征。* max_df 用来描述单词在文档中的最高出现率。 * max_df = 0.5，代表一个单词在 50% 的文档中都出现过，那么它只携带非常少的信息，不做分词统计。<jupyter_code>from sklearn.feature_extraction.text import TfidfVectorizer

file_path_en = "data/stopwords_en.txt"
stop_words_en = [line.strip() for line in open(file_path_en, 'r', encoding='utf-8').readlines()]

train_contents = ["Huawei unveils Harmony operating system, won't ditch Android for smartphones.", 
                  "There are the 7 most common types of fear"]
tf = TfidfVectorizer(stop_words=stop_words_en, max_df=0.5)
features = tf.fit_transform(train_contents)<jupyter_output>D:\Anaconda\lib\site-packages\sklearn\feature_extraction\text.py:301: UserWarning: Your stop_words may be inconsistent with your preprocessing. Tokenizing the stop words generated tokens ['ain', 'al', 'couldn', 'didn', 'doesn', 'don', 'hadn', 'hasn', 'haven', 'isn', 'll', 'mon', 'shouldn', 've', 'wasn', 'weren', 'won', 'wouldn'] not in stop_words.
  'stop_words.' % sorted(inconsistent))<jupyter_text>生成朴素贝叶斯分类器* 将特征训练集的特征空间 train_features 和 训练集对应的分类 train_labels 传递给贝叶斯分类器 clf。* 以多项式贝叶斯分类器为例： * alpha：平滑参数，如处理某个未在训练样本中出现的单词。   * alpha=1，Laplace 平滑，即采用 +1 的方式，统计没有出现过的单词的概率，当训练样本很大时，+1 得到的概率变化可以忽略不计，同时避免零概率问题。   * 0<alpha<1，Lidstone 平滑，alpha 越小，迭代次数越多，精度越高，可设置为 0.001。 * 例： 多项式贝叶斯分类器  ```Python from sklearn.naive_bayes import MultinomialNB  clf = MultinomialNB(alpha=0.001).fit(train_features, train_labels) ```  使用生成的分类器做预测* 得到测试集的特征矩阵```Pythontest_tf = TfidfVectorizer(stop_words=stop_words, max_df=0.5, vocabulary=train_vocabulary)test_features=test_tf.fit_transform(test_contents)```* 用训练好的分类器对新数据进行预测：predict()  * 求解所有后验概率，并找到最大的那个```Pythonpredicted_labels=clf.predict(test_features)```  计算准确率* 实际结果与预测结果对比，给出模型的准确率```Pythonfrom sklearn import metricsprint(metrics.accuracy_score(test_labels, predicted_labels))```  实战：中文文档分类* 数据见：data/text_classification。* 文档有 4 类：女性、体育、文学、校园。* train 文件夹：训练集；test 文件夹：测试集；stop 文件夹：停用词。<jupyter_code>import os
import jieba
import warnings
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.naive_bayes import MultinomialNB
from sklearn import metrics

def cut_words(file_path):
    """
    对文本分词
    :param file_path: txt文本路径
    :return: 用空格分词的字符串
    """
    text_with_spaces = ""
    text = open(file_path, "r", encoding="gb18030").read()
    text_cut = jieba.cut(text)
    for word in text_cut:
        text_with_spaces += word + " "
    return text_with_spaces

def load_file(file_dir, label):
    """
    加载路径下的所有文件
    :param file_dir: 保存 txt 文件的目录
    :param label: 文档标签
    :return 分词后的文档列表和标签
    """
    file_list = os.listdir(file_dir)
    words_list = []
    labels_list = []
    for file in file_list:
        file_path = file_dir + "/" + file
        words_list.append(cut_words(file_path))
        labels_list.append(label)
    return words_list, labels_list

# 训练数据
train_words_women, train_labels_women = load_file("data/text_classification/train/女性", "女性")
train_words_sports, train_labels_sports = load_file("data/text_classification/train/体育", "体育")
train_words_literature, train_labels_literature = load_file("data/text_classification/train/文学", "文学")
train_words_campus, train_labels_campus = load_file("data/text_classification/train/校园", "校园")

train_words_list = train_words_women + train_words_sports + train_words_literature + train_words_campus
train_labels = train_labels_women + train_labels_sports + train_labels_literature + train_labels_campus

# 测试数据
test_words_women, test_labels_women = load_file("data/text_classification/test/女性", "女性")
test_words_sports, test_labels_sports = load_file("data/text_classification/test/体育", "体育")
test_words_literature, test_labels_literature = load_file("data/text_classification/test/文学", "文学")
test_words_campus, test_labels_campus = load_file("data/text_classification/test/校园", "校园")

test_words_list = test_words_women + test_words_sports + test_words_literature + test_words_campus
test_labels = test_labels_women + test_labels_sports + test_labels_literature + test_labels_campus

# 停用词
stop_words = open("data/text_classification/stop/stopword.txt", "r", encoding="utf-8").read()
stop_words = stop_words.encode("utf-8").decode("utf-8-sig")
stop_words = stop_words.split("\n")

# 计算单词权重
tf = TfidfVectorizer(stop_words=stop_words, max_df=0.5)

train_features = tf.fit_transform(train_words_list)
test_features = tf.transform(test_words_list)

# 多项式贝叶斯分类器
clf = MultinomialNB(alpha=0.001).fit(train_features, train_labels)
predicted_labels = clf.predict(test_features)

# 计算准确率
metrics.accuracy_score(test_labels, predicted_labels)<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.11654387139986604, 'fraction_numerical': 0.030542531815137306, 'mean_word_length': 6.0037523452157595, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 19, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '5', 'dir': 'jupyter-structured-clean-dedup', 'id': '307681', 'license': 'Apache-2.0', 'n_tokens_mistral': 3815, 'n_tokens_neox': 3997, 'n_words': 499, 'path': 'code/Text Classification.ipynb', 'repo_name': 'YubinLiu/GeekTime_dataAnalysis', 'size': '7465'}