有些特征可能是连续型变量,比如说人的身高,物体的长度,这些特征可以转换成离散型的值,比如如果身高在160cm以下,特征值为1;在160cm和170cm之间,特征值为2;在170cm之上,特征值为3。也可以这样转换,将身高转换为3个特征,分别是f1、f2、f3,如果身高是160cm以下,这三个特征的值分别是1、0、0,若身高在170cm之上,这三个特征的值分别是0、0、1。不过这些方式都不够细腻,高斯模型可以解决这个问题。高斯模型假设这些一个特征的所有属于某个类别的观测值符合高斯分布,也就是:
from sklearn.naive_bayes import GaussianNB
#高斯贝叶斯
def train_model_GaussianNB():
pass
clf3 = GaussianNB()
clf3.fit(X[499:], y[499:])#训练模型
predict_labels = clf3.predict(X[0:499])
# 预测对了几个?
n = 0
for i in range(len(predict_labels)):
if (predict_labels[i] == y[i]):
n = n + 1
print("高斯贝叶斯:")
# 正确率
print n / 499.0
# 混淆矩阵
confusion_matrix(y[0:499], predict_labels)
return
在多项式模型中,设某文档d=(t1,t2,…,tk),tk是该文档中出现过的单词,允许重复,则先验概率P(c)= 类c下单词总数/整个训练样本的单词总数。类条件概率P(tk|c)=(类c下单词tk在各个文档中出现过的次数之和+1)/(类c下单词总数+|V|)。
其中V是训练样本的单词表(即抽取单词,单词出现多次,只算一个),|V|则表示训练样本包含多少种单词。P(tk|c)可以看作是单词tk在证明d属于类c上提供了多大的证据,而P(c)则可以认为是类别c在整体上占多大比例(有多大可能性)。
from sklearn.naive_bayes import MultinomialNB
#多项式贝叶斯
def train_model_MultinomialNB():
pass
clf = MultinomialNB()
#训练模型
clf.fit(X[499:],y[499:])
#预测训练集
predict_labels = clf.predict(X[0:499])
#预测对了几个?
n = 0
for i in range(len(predict_labels)):
if(predict_labels[i] == y[i]):
n = n + 1
print("多项式贝叶斯:")
#正确率
print n/499.0
#混淆矩阵
confusion_matrix(y[0:499], predict_labels)
return
P(c)= 类c下文件总数/整个训练样本的文件总数
P(tk|c)=(类c下包含单词tk的文件数+1)/(类c下包含的文件+2)
from sklearn.naive_bayes import BernoulliNB
#伯努利贝叶斯
def train_model_BernoulliNB():
pass
clf2 = BernoulliNB()
clf2.fit(X[499:], y[499:])
predict_labels = clf2.predict(X[0:499])
# 预测对了几个?
n = 0
for i in range(len(predict_labels)):
if (predict_labels[i] == y[i]):
n = n + 1
print("伯努利贝叶斯:")
# 正确率
print n / 499.0
# 混淆矩阵
confusion_matrix(y[0:499], predict_labels)
return
文本分类是作为离散型数据的。朴素贝叶斯用于很多方面,数据就会有连续和离散的,连续型时可用正态分布,还可用区间,将数据的各属性分成几个区间段进行概率计算,测试时看其属性的值在哪个区间就用哪个条件概率。再有TF、TDIDF,这些只是描述事物属性时的不同计算方法,例如文本分类时,可以用单词在本文档中出现的次数描述一个文档,可以用出现还是没出现即0和1来描述,还可以用单词在本类文档中出现的次数与这个单词在剩余类出现的次数(降低此属性对某类的重要性)相结合来表述。
以上参见原文:https://blog.csdn.net/u013710265/article/details/72780520
搜狗新闻数据源:http://www.sogou.com/labs/resource/ca.php
从搜狗下载的数据是类似XML的带标签对的数据,因此需要使用正则表达式或者BeautifulSoup等工具处理为dataframe格式
import pandas as pd
import jieba
from sklearn.model_selection import train_test_split
from sklearn.naive_bayes import MultinomialNB
#从本地读取数据集,并切分训练、测试集
data = pd.read_table('news_data/news_data.txt')
x_train, x_test, y_train, y_test = train_test_split(data['新闻内容'], data['类别'], random_state=1)
#分词
def fenci(train_data):
words_df = train_data.apply(lambda x:' '.join(jieba.cut(x)))
return words_df
x_train_fenci = fenci(x_train)
x_train_fenci[:5]
#引入停用词
infile = open("stopwords.txt",encoding='utf-8')
stopwords_lst = infile.readlines()
stopwords = [x.strip() for x in stopwords_lst]
#文本特征提取(词库表示法)
vectorizer = CountVectorizer(stop_words=stopwords, max_features=5000)
vectorizer.fit(x_train_fenci)
#建模
classifier = MultinomialNB()
#模型训练
classifier.fit(vectorizer.transform(x_train_fenci), y_train)
#使用训练好的模型进行预测
classifier.score(vectorizer.transform(fenci(x_test)), y_test)
PS:(在文本特征提取中CountVectorizer旨在通过计数来将一个文档转换为向量。当不存在先验字典时,Countvectorizer作为Estimator提取词汇进行训练,并生成一个CountVectorizerModel用于存储相应的词汇向量空间。该模型产生文档关于词语的稀疏表示。)下面举个例子:
#用于转词向量的语料
yuliao = ['dog cat fish dog dog dog','cat eat fish','i like eat fish']
#sklearn库CountVectorizer转词向量
from sklearn.feature_extraction.text import CountVectorizer
cv = CountVectorizer()
vector = cv.fit_transform(yuliao)
vector.todense()
接下来我们看下提取到的特征分别是
{'cat': 0, 'dog': 1, 'eat': 2, 'fish': 3, 'like': 4}
从上面的例子可以看出,语料中每个词作为一个特征,词频数作为特征的值,如第一句中dog出现了4次,因此特征值为4。
一个词语在一篇文章中出现次数越多, 同时在所有文档中出现次数越少, 越能够代表该文章.
下面直接给出一个词x的IDF的基本公式如下:
其中,N代表语料库中文本的总数,而N(x)代表语料库中包含词x的文本总数
TF−IDF(x)=TF(x)∗IDF(x) 其中TF(x)指词x在当前文本中的词频
词库表示法的缺点:一些普遍出现的词,词频较高,看起来似乎是更重要的特征,但因为这个词普遍出现,这个词可能不是非常的重要。如果我们的向量化特征仅仅用词频表示就无法反应这一点。因此我们需要进一步的预处理来反应文本的这个特征,而这个预处理就是TF-IDF。
用scikit-learn进行TF-IDF预处理
from sklearn.feature_extraction.text import TfidfVectorizer
#使用tf-idf把文本转为向量
tv = TfidfVectorizer(stop_words=stopwords, max_features=5000, lowercase = False)
tv.fit(x_train_fenci)
#模型训练
classifier.fit(tv.transform(fenci(x_train)), y_train)
#利用训练好的模型测试
classifier.score(tv.transform(fenci(x_test)), y_test)
N-gram模型
在朴素贝叶斯算法中,为了避免维度灾难,有一个大胆的假设,即X的n个维度之间相互独立:
这个假设下,条件分布大大的简化了,但是这也可能带来预测的不准确性。n个维度相互独立,就是完全没有考虑上下文语境,把每个词拆开单独看,这么看的话,猫吃鱼、鱼吃猫得到的特征向量是完全一样的。
N-gram模型就是假设与附近n个词是相关的,比如当n=(1,2)时,猫吃鱼提取到的特征就是[‘猫’,‘吃’,‘鱼’,‘猫吃’,‘吃鱼’],为了平衡计算量和上下文关系,N一般取2或者3。朴素贝叶斯n个维度之间完全相互独立的假设,就是N-gram的n=1时的情况
#转词向量
tv_2gram = TfidfVectorizer(stop_words=stopwords, max_features=5000, ngram_range=(1,2),lowercase = False)
tv_2gram.fit(x_train_fenci)
#训练模型
clf_2gram = MultinomialNB()
clf_2gram.fit(tv_2gram.transform(fenci(x_train)), y_train)
#预测
clf_2gram.score(tv_2gram.transform(fenci(x_test)), y_test)