首先,贝叶斯公式
这个公式是由联合概率公式推导出来的:
P(A,B)=P(A|B)P(B)=P(B|A)P(A)
P(A)叫做先验概率,P(A|B)叫做后验概率,P(A,B)叫做联合概率
如果在机器学的视角下,我们把A理解成“类别标签”,把B理解成“具有某种特征”。这样贝叶斯公司可以理解为
而应用这个算法最常见的场景就是针对垃圾邮件的分类判断了
即,判断P(‘垃圾邮件’|‘具有某种特征’) 是否大于1/2
例如,我们收到一封邮件,里面的内如是“我司可以办理正规发票(保真)17%增值税发票点数优惠”。那么我们要做的就是
判断P(‘垃圾邮件’|‘我司可以办理正规发票(保真)17%增值税发票点数优惠’)是否大于1/2!
而这里我们又到用了分词技术。(如结巴分词等)
我们可以将这个公式转化成
P(‘垃圾邮件’|‘我司可以办理正规发票(保真)17%增值税发票点数优惠’)=P(‘垃圾邮件’|(‘我’,‘司’,‘可’,‘办理’,‘正规发 票’,‘保真’,‘增值税’,‘发票’,‘点数’,‘优惠’))
这里我们用A标示‘垃圾邮件’,B标示分词词组(‘我’,‘司’,‘可’,‘办理’,‘正规发票’,‘保真’,‘增值税’,‘发票’,‘点数’,‘优惠’)
根据贝叶斯公式可以将上式转换成
P(B|A)P(A)/P(B)形式
这里P(B|A)是P((‘我’,‘司’,‘可’,‘办理’,‘正规发票’,‘保真’,‘增值税’,‘发票’,‘点数’,‘优惠’)|‘垃圾邮件’)
而根据传说中的条件独立假设
可以将P((‘我’,‘司’,‘可’,‘办理’,‘正规发票’,‘保真’,‘增值税’,‘发票’,‘点数’,‘优惠’)|‘垃圾邮件’)转换成
P(‘我’|‘垃圾邮件’)*P(‘司’|‘垃圾邮件’)*....*P(‘点数’|‘垃圾邮件’)*P(‘优惠’|‘垃圾邮件’)
这样,这个例子里面就转换成了对P(‘我’|‘垃圾邮件’)等的概率计算。我们在训练集中,需要进行统计得出这个写概率
例如,P(‘发票’|‘垃圾邮件’)=垃圾邮件中所有‘发票’出现的次数/垃圾邮件中所有词语出现的次数
这样整个判断垃圾邮件的分类问题,就转换成了一个统计概率问题。这种分类问题就能得以解决。
上述这种增加了条件独立假设的贝叶斯方法叫做朴素贝叶斯方法。由上面的例子可以看出,朴素贝叶斯方法是很简单的。
但是,但是,但是
朴素贝叶斯存在这一个问题,就是在它眼里是没有词语之间的顺序的。
如刚才上例。
P((‘我’,‘司’,‘可’,‘办理’,‘正规发票’)|‘垃圾邮件’)=P(‘我’|‘垃圾邮件’)*P(‘司’|‘垃圾邮件’)*...*P(‘正规发票’|‘垃圾邮件’)
由于乘法满足交换律,那么上面可以认为是
P(‘我’|‘垃圾邮件’)*P(‘司’|‘垃圾邮件’)*...*P(‘正规发票’|‘垃圾邮件’) = P(‘正规发票’|‘垃圾邮件’)*...*P(‘司’|‘垃圾邮件’)*P(‘我’|‘垃圾邮件’)=P((‘正规发票’,‘可’,‘办理’,‘我’,‘司’)|‘垃圾邮件’)
这个语句就尴尬了!
不过,朴素贝叶斯在实际应用中的效率是很高的。效果好的出奇。
这里我们继续介绍
朴素贝叶斯的三种模型
1,多项式模型
重复的词语我们视为其出现多次
2,伯努利模型
重复的词语我们只视为出现一次。这种方法更加简洁和简单,但是它丢失了词频信息,最后的效果也差一些。
3,混合模型
在计算句子的概率时,不考虑词语出现的次数,但是在统计计算词语的概率(例如P(‘词语’|‘垃圾邮件’))时,考虑重复词语出现的次数
平滑技术
平滑技术是针对于那些在验证是没有出现过的词,它们的概率是0,在贝叶斯算法中如果乘以0的话就会失去意义。所以要对这些进行平滑处理。
这里的平滑处理就是对分子进行加1处理。即拉普拉斯平滑处理法(使每一个未出现的词语出现一次)。
平滑技术不止这一种方法。还有很多,平滑技术是一种很复杂的处理技术。
还有古德图灵平滑,线性插值法,回退法(K-Z回退)等
最常见应用场景
- 文本分类/垃圾文本过滤/情感判别:这大概会朴素贝叶斯应用做多的地方了,即使在现在这种分类器层出不穷的年代,在文本分类场景中,朴素贝叶斯依旧坚挺地占据着一席之地。因为多分类很简单,同时在文本数据中,分布独立这个假设基本是成立的。而垃圾文本过滤(比如垃圾邮件识别)和情感分析(微博上的褒贬情绪)用朴素贝叶斯也通常能取得很好的效果。
- 多分类实时预测:这个是不是不能叫做场景?对于文本相关的多分类实时预测,它因为上面提到的优点,被广泛应用,简单又高效。
- 推荐系统:是的,你没听错,是用在推荐系统里!!朴素贝叶斯和协同过滤(Collaborative Filtering)是一对好搭档,协同过滤是强相关性,但是泛化能力略弱,朴素贝叶斯和协同过滤一起,能增强推荐的覆盖度和效果。
朴素贝叶斯训练/建模
下面我们提提怎么快速用朴素贝叶斯训练模型吧。scikit-learn里面有3种不同类型的朴素贝叶斯:
- 高斯分布型:用于classification问题,假定属性/特征是服从正态分布的。
- 多项式型:用于离散值模型里。比如文本分类问题里面我们提到过,我们不光看词语是否在文本中出现,也得看出现的次数。如果总词数为n,出现词数为m的话,说起来有点像掷骰子n次出现m次这个词的场景。
- 伯努利型:这种情况下最后得到的特征只有0(没出现)和1(出现过)。
根据你的数据集,可以选择scikit-learn中以上任意一种朴素贝叶斯,我们直接举个简单的例子,用高斯分布型朴素贝叶斯建模:
# 我们直接取iris数据集,这个数据集有名到都不想介绍了...
# 其实就是根据花的各种数据特征,判定是什么花
from sklearn import datasets
iris = datasets.load_iris()
iris.data[:5]
#array([[ 5.1, 3.5, 1.4, 0.2],
# [ 4.9, 3. , 1.4, 0.2],
# [ 4.7, 3.2, 1.3, 0.2],
# [ 4.6, 3.1, 1.5, 0.2],
# [ 5. , 3.6, 1.4, 0.2]])
#我们假定sepal length, sepal width, petal length, petal width 4个量独立且服从高斯分布,用贝叶斯分类器建模
from sklearn.naive_bayes import GaussianNB
gnb = GaussianNB()
y_pred = gnb.fit(iris.data, iris.target).predict(iris.data)
right_num = (iris.target == y_pred).sum()
print("Total testing num :%d , naive bayes accuracy :%f" %(iris.data.shape[0], float(right_num)/iris.data.shape[0]))
# Total testing num :150 , naive bayes accuracy :0.960000
朴素贝叶斯之文本主题分类器
这是朴素贝叶斯最擅长的应用场景之一,对于不同主题的文本,我们可以用朴素贝叶斯训练一个分类器,然后将其应用在新数据上,预测主题类型。
而文本分析则是文本主题分类器的重要前提
下面我们简单介绍一下------文本分类器
停用词
1.语料中大量出现
2.没啥大用
例如
Tf-idf:关键词提取
比如现在我有一篇文章《中国的蜜蜂养殖》首先我们进行一个词频(Term Frequency,缩写为TF)统计。发现出现次数最多的是----“的” 、 “是” 、 “在” ----这一类最常用的词(停用词),我们先去掉停用词,然后再进行词频统计。“中国” 、 “蜜蜂” 、 “养殖” 这三个词的出现次数一样多,重要性是一样的。但是,"中国"是很常见的词,相对而言,"蜜蜂"和"养殖"不那么常见。
这时候使用"逆文档频率"(Inverse Document Frequency,缩写为IDF)
如果某个词比较少见,但是它在这篇文章中多次出现,那么它很可能就反映了这篇文章的特性。正是我们所需要的关键词
我们还是以上面那个文章举例
《中国的蜜蜂养殖》 :假定该文长度为1000个词,"中国"、 "蜜蜂"、 "养殖"各出现20次,则这三个词的"词频"(TF)都为0.02。
搜索Google发现,包含"的"字的网页共有250亿张,假定所有文章都包含‘的’。这就相当于中文网页总数。包含"中国"的网页共有62.3亿张,包含"蜜蜂"的网页为0.484亿张,包含"养殖"的网页为0.973亿张
计算TF-IDF后
相似度
句子A:我喜欢看电视,不喜欢看电影。
句子B:我不喜欢看电视,也不喜欢看电影。
那我们要看这两个句子的相似度
首先我们需要分词
句子A:我/喜欢/看/电视,不/喜欢/看/电影。
句子B:我/不/喜欢/看/电视,也/不/喜欢/看/电影。
语料库:我,喜欢,看,电视,电影,不,也。(所有不重复的词)
词频(出现了多少次):
句子A:我 1,喜欢 2,看 2,电视 1,电影 1,不 1,也 0。
句子B:我 1,喜欢 2,看 2,电视 1,电影 1,不 2,也 1。
词频向量:
句子A:[1, 2, 2, 1, 1, 1, 0]
句子B:[1, 2, 2, 1, 1, 2, 1]
利用计算相似度
下面我们采用一个实际的例子来进行文本分类器
import pandas as pd
import jieba
导入需要的库
数据源我们采用搜狗实验室提供的数据源
http://www.sogou.com/labs/resource/ca.php
我们需要请原数据进行处理,提取出标题,内容,URL等有用信息。
df_news = pd.read_table('./data/val.txt',names=['category','theme','URL','content'],encoding='utf-8')
df_news = df_news.dropna()
df_news.head()
这里为了掩饰,选择小的数据val.txt。
部分数据展示
下面进行分词
content = df_news.content.values.tolist()
print (content[1000])
首先将content里面的内容转换成list的格式。打印一个新闻如下
然后利用结巴分词
content_S = []
for line in content:
current_segment = jieba.lcut(line)
if len(current_segment) > 1 and current_segment != '\r\n': #换行符
content_S.append(current_segment)
分词后我们再次打印刚才的那个新闻信息
content_S[1000]
['阿里巴巴', '集团', '昨日', '宣布', ',', '将', '在', '集团', '管理', '层面', '设立', '首席', '数据', '官', '岗位', '(', 'C', 'h', 'i', 'e', 'f', '\u3000', 'D', 'a', 't', 'a', '\u3000', 'O', 'f', 'f', 'i', 'c', 'e', 'r', ')', ',', '阿里巴巴', 'B', '2', 'B', '公司', 'C', 'E', 'O', '陆兆禧', '将', '会', '出任', '上述', '职务', ',', '向', '集团', 'C', 'E', 'O', '马云', '直接', '汇报', '。', '>', '菹', 'ぃ', '和', '6', '月初', '的', '首席', '风险', '官', '职务', '任命', '相同', ',', '首席', '数据', '官亦为', '阿里巴巴', '集团', '在', '完成', '与', '雅虎', '股权', '谈判', ',', '推进', '“', 'o', 'n', 'e', '\u3000', 'c', 'o', 'm', 'p', 'a', 'n', 'y', '”', '目标', '后', ',', '在', '集团', '决策', '层面', '新增', '的', '管理', '岗位', '。', '0', '⒗', '锛', '团', '昨日', '表示', ',', '“', '变成', '一家', '真正', '意义', '上', '的', '数据', '公司', '”', '已', '是', '战略', '共识', '。', '记者', '刘夏']
之后我们进行dataFrame处理
df_content=pd.DataFrame({'content_S':content_S})
df_content.head()
下面我们要做的就是进行数据清洗,去掉停用词,首先先拿到一个停用词表,停用词表https://pan.baidu.com/s/17-fb6JD0hS1qcBPfDKyGkw 其实停用词表是可以自己总结添加的。每个人有不一样的停用词表。根据实际业务需求修改停用词表。
stopwords=pd.read_csv("stopwords.txt",index_col=False,sep="\t",quoting=3,names=['stopword'], encoding='utf-8')
stopwords.head(20)
下面进行清洗停用词操作
def drop_stopwords(contents,stopwords):
contents_clean = []
all_words = []
for line in contents:
line_clean = []
for word in line:
if word in stopwords:
continue
line_clean.append(word)
all_words.append(str(word))
contents_clean.append(line_clean)
return contents_clean,all_words
#print (contents_clean)
contents = df_content.content_S.values.tolist()
stopwords = stopwords.stopword.values.tolist()
contents_clean,all_words = drop_stopwords(contents,stopwords)
清理完后,再次查看
df_content=pd.DataFrame({'contents_clean':contents_clean})
df_content.head()
df_all_words=pd.DataFrame({'all_words':all_words})
df_all_words.head()
TF-IDF :提取关键词
import jieba.analyse
index = 1000
print (df_news['content'][index])
content_S_str = "".join(content_S[index])
print (" ".join(jieba.analyse.extract_tags(content_S_str, topK=5, withWeight=False)))
阿里巴巴集团昨日宣布,将在集团管理层面设立首席数据官岗位(Chief Data Officer),阿里巴巴B2B公司CEO陆兆禧将会出任上述职务,向集团CEO马云直接汇报。>菹ぃ和6月初的首席风险官职务任命相同,首席数据官亦为阿里巴巴集团在完成与雅虎股权谈判,推进“one company”目标后,在集团决策层面新增的管理岗位。0⒗锛团昨日表示,“变成一家真正意义上的数据公司”已是战略共识。记者刘夏 阿里巴巴 集团 首席 岗位 数据
其中jieba.analyse.extract_tags方法是关键,topK是选取多少个关键词。
下面我们就要用贝叶斯进行分类
首先加入label
df_train=pd.DataFrame({'contents_clean':contents_clean,'label':df_news['category']})
df_train.tail()
查看label有少种类
df_train.label.unique()
array(['汽车', '财经', '科技', '健康', '体育', '教育', '文化', '军事', '娱乐', '时尚'],dtype=object)
上面看到有10个种类,所以我们要做的是10分类
label_mapping = {"汽车": 1, "财经": 2, "科技": 3, "健康": 4, "体育":5, "教育": 6,"文化": 7,"军事": 8,"娱乐": 9,"时尚": 0}
df_train['label'] = df_train['label'].map(label_mapping)
df_train.head()
map转换一下后进行测试集和训练集拆分。
from sklearn.model_selection import train_test_split
x_train, x_test, y_train, y_test = train_test_split(df_train['contents_clean'].values, df_train['label'].values, random_state=1)
之后将每个新闻信息转换成字符串形式
words = []
for line_index in range(len(x_train)):
try:
words.append(' '.join(x_train[line_index]))
except:
print (line_index,word_index)
words[0]
基于词频,构造词组向量
from sklearn.feature_extraction.text import CountVectorizer
vec = CountVectorizer(analyzer='word', max_features=4000, lowercase = False)
vec.fit(words)
之后构建贝叶斯分类器
from sklearn.naive_bayes import MultinomialNB
classifier = MultinomialNB()
classifier.fit(vec.transform(words), y_train)
然后进行测试,不过在测试之前,我们要保证测试集个训练集是一样的,测试集也需要进行字符串的转换
test_words = []
for line_index in range(len(x_test)):
try:
#x_train[line_index][word_index] = str(x_train[line_index][word_index])
test_words.append(' '.join(x_test[line_index]))
except:
print (line_index,word_index)
test_words[0]
再进行测试
classifier.score(vec.transform(test_words), y_test)
这里我的结果是
0.7968
最后,我们还可以进行基于TF-IDF进行词频向量的创建
from sklearn.feature_extraction.text import TfidfVectorizer
vectorizer = TfidfVectorizer(analyzer='word', max_features=4000, lowercase = False)
vectorizer.fit(words)
from sklearn.naive_bayes import MultinomialNB
classifier = MultinomialNB()
classifier.fit(vectorizer.transform(words), y_train)
classifier.score(vectorizer.transform(test_words), y_test)
同样进行预测,结果是
0.8088
可以看出TF-IDF结果要好一些。
到此,贝叶斯算法的介绍就到这里了。