赞
踩
周末去长沙玩了一趟,在长沙呆了四年,然后就像真游客一样去爬了岳麓山和逛了橘子洲头,哈哈,和亲近的人一起玩闹的体验很舒服,很庆幸和感恩有那么一群人宠着你~~
当然,游乐之余,我也不忘学习的,在回来的高铁上,学了一下朴素贝叶斯算法,这是机器学习里面的经典的分类算法,也是为数不多的基于概率论的分类算法。
学习:
那么经典统计学遇到什么困难呢,而贝叶斯统计学又能够广泛应用呢。我们先整体了解一下经典统计学的思想和贝叶斯统计学的思想。
其中,总体信息为当前总体样本符合某种分布。比如抛硬币符合二项分布,学生身高符合正态分布。样本信息为通过抽样得到的部分样本的某种分布。
总结:经典统计学(频率派)把需要推断的参数θ看做是固定的未知常数,即概率θ虽然是未知的,但最起码是确定的一个值,同时,样本X 是随机的,所以频率派重点研究样本空间,大部分的概率计算都是针对样本X 的分布;
总结:贝叶斯派认为参数θ是随机变量,而样本X 是固定的,由于样本是固定的,所以他们重点研究的是参数θ的分布。
举个例子:
现在有一杯啤的、一杯白的,让10位同学蒙着眼睛去品酒,那大家实际上都能分辨出来。如果每位同学都是猜测结果,那最终的概率应该为0.5**10,这个结果非常小。
但实际上,基本上每位同学都可以进行分辨,所以不能认为这个结果是猜测而来。而应该是根据往常的经验来得出的结果。而这个经验本身,实际上就是我们的先验信息。
这种思考模式意味着,新观察到的样本信息将修正人们以前对事物的认知。换言之,在得到新的样本信息之前,人们对的认知是先验分布 π(θ),在得到新的样本信息后χ,人们对θ的认知为π(θ|x)。基于这种思维模式,贝叶斯定理也就容易理解了。
先学习或者复习几个定义,在概率论学习中,应该有过接触:
那么有了上述概念后,我们就来介绍贝叶斯定理吧。贝叶斯定理告诉我们如何交换条件概率中的条件与结果。比如,我们已知P(B|A),需要求解P(A|B)。
由此得到公式:
这里有个最经典的例子,n个箱子,去进行摸球。求B的概率则用全概,求A则用贝叶斯。
由此,我们可以发现贝叶斯就是为了解决“逆概率”而提出的,逆概率的意思就如同:我们从袋子里摸球,然后事先并不知道袋子里面黑白球的比例,我们需要知道这个袋子里的黑白球比例。那么我们只能通过摸出一个或者好几个球,观察这些取出来的球的颜色之后,然后反推判断袋子里的的黑白球的比例。
为了便于记住公式,我们也可以把摸出的球作为现象,需要了解里面的球的比例作为规律,把贝叶斯公式简单记为:
然而贝叶斯定理也存在一些小问题,如承接上面邮件,我们要选出带有房地产、产权和贷款词眼的邮件
假设统计结果如下:
此时,每个特征之间是有关联的,那我们需要来计算如下:
P(房地产|垃圾邮件)
P(房地产,产权|垃圾邮件)
P(房地产,产权,贷款|垃圾邮件)
...
P(房地产|垃圾邮件)
P(产权|垃圾邮件)
P(贷款|垃圾邮件)
先简单回顾一下之前学过的可用于分类的算法,有逻辑回归、决策树,还有支持向量机。整体而言,它们实现的原理是存在差异的。
简单举个区分好人和坏人的例子。假设我们现在不知道他们之前的履历,只能根据他们的样貌特征来判断他们是好人还是坏人。如特征有:笑容、纹身、性别等。
那么对于决策树算法进行的好人和坏人分类的话,可能先看性别,因为它发现给定的带标签人群里面男的坏蛋特别多,这个特征眼下最能区分坏蛋和好人,然后按性别把一拨人分成两拨;接着看“笑”这个特征,因为它是接下来最有区分度的特征,然后把两拨人分成四拨;接下来看纹身,以此类推。最后发现好人要么在田里种地,要么在山上砍柴,要么在学堂读书。而坏人呢,要么在大街上溜达,要么在地下买卖白粉,要么在海里当海盗。这些个有次序的特征就像路上的一个个垫脚石(树的节点)一样,构成通往不同地方的路径(树的枝丫),这些不同路径的目的地(叶子)就是一个类别容器,包含了一类人。一个品行未知的人来了,按照其样貌特征顺序及其对应的特征值,不断走啊走,最后走到了农田或山上,那就是好人;走到了地下或大海,
而对于朴素贝叶斯算法而言,它是将特征概率化。举例来说,笑的特征可以区分为好人的笑和坏人的笑,如“甜美的笑”、“儒雅的笑”、“憨厚的笑”、“没心没肺的笑”、“微微一笑”是好人的笑的概率更大,而“阴险的笑”、“不屑的笑”、“色眯眯的笑”、“任我行似的笑”、“冷笑”、“皮笑肉不笑”是坏人的笑概率更大。基于此,朴素贝叶斯就是将特征进行概率化来进行好人和坏人分类的,如果“坏人模型”输出的概率值大一些,那这个人很有可能就是个大坏蛋了。
此处学习自:深入理解朴素贝叶斯(Naive Bayes)
基于上述思想,下面以一个简单的案例,介绍朴素贝叶斯分类的工作原理。
数据如下:
确定特征如下:身高、体重、鞋码
确定目标如下:性别(C1:男、C2:女)
需求:求解以下特征数据的性别是男性还是女性
• A1:身高=高
• A2:体重=中
• A3:鞋码=中
实现:简单来说,我们仅需求解在该特征下是男性的概率,再求解在该特征下是女性的概率。然后进行比较,选择可能性大的作为结果。
首先计算男性概率:
P(A1|C1) = 1/2
p(A2|C1) = 1/2
p(A3|C1) = 1/4
P(A1A2A3|Cj) = 1/16
同理计算女性概率。
数据如下:
需求:求解以下特征数据的性别是男性还是女性
• 身高:180
• 体重:120
• 鞋码:41
实现:
• 假设男性和女性的身高、体重、鞋码都是正态分布
• 通过样本计算出均值和方差,也就是得到正态分布的密度函数
• 有了密度函数,就可以把值代入,算出某一点的密度函数的值
import numpy as np
import pandas as pd
df = pd.read_excel('table_data.xlsx',sheet_name="Sheet3",index_col=0)
df
"""
x 与 均值 与 方差
"""
df2 = df.groupby("性别").agg([np.mean,np.var])
df2
""" 男性 各个特征的 均值 与 方差 """ male_high_mean = df2.loc["男","身高"]["mean"] male_high_var = df2.loc["男","身高"]["var"] male_weight_mean = df2.loc["男","体重"]["mean"] male_weight_var = df2.loc["男","体重"]["var"] male_code_mean = df2.loc["男","鞋码"]["mean"] male_code_var = df2.loc["男","鞋码"]["var"] """ 构建男性特征的正态分布曲线,输入特征值下是男性的概率 """ from scipy import stats male_high_p = stats.norm.pdf(180,male_high_mean,male_high_var) male_weight_p = stats.norm.pdf(120,male_weight_mean,male_weight_var) male_code_p = stats.norm.pdf(41,male_code_mean,male_code_var)
""" 女性 各个特征的 均值 与 方差 """ female_high_mean = df2.loc["女","身高"]["mean"] female_high_var = df2.loc["女","身高"]["var"] female_weight_mean = df2.loc["女","体重"]["mean"] female_weight_var = df2.loc["女","体重"]["var"] female_code_mean = df2.loc["女","鞋码"]["mean"] female_code_var = df2.loc["女","鞋码"]["var"] """ 构建女性特征的正态分布曲线,输入特征值下是女性的概率 """ from scipy import stats female_high_p = stats.norm.pdf(180,female_high_mean,female_high_var) female_weight_p = stats.norm.pdf(120,female_weight_mean,female_weight_var) female_code_p = stats.norm.pdf(41,female_code_mean,female_code_var)
# 比较是男性概率高还是女性的概率高
male_high_p*male_weight_p*male_code_p > female_high_p*female_weight_p*female_code_p # True
朴素贝叶斯分类最适合的场景就是文本分类、情感分析和垃圾邮件识别。其中情感分析和垃圾邮件识别都是通过文本来进行判断。从这里你能看出来,这三个场景本质上都是文本分类,这也是朴素贝叶斯最擅长的地方。所以朴素贝叶斯也常用于自然语言处理 NLP 的工具。
sklearn 的全称叫 Scikit-learn,它给我们提供了 3 个朴素贝叶斯分类算法,分别是高斯朴素贝叶斯(GaussianNB)、多项式朴素贝叶斯(MultinomialNB)和伯努利朴素贝叶斯(BernoulliNB)。
这三种算法适合应用在不同的场景下,我们应该根据特征变量的不同选择不同的算法:
import pandas as pd import numpy as np """ 1 数据描述性统计 """ """ - 样本数据:5000条 5000则新闻 - 字段:4个 - 标签:category-->分类 - 特征:content-->特征。将content进行分词统计出高频词汇再来预测新闻类别。 - 特征:每个高频词汇 - theme-->主题 - URL-->链接 - 有无缺失值:无。 """ df_news = pd.read_table('data.txt',names=['category','theme','URL','content'],encoding='utf-8') df_news.info() df_news.head()
"""
标签分类共多少: 科技、健康、文化、汽车等
"""
df_news.category.value_counts()
""" 2.提取有价值的词汇——特征 """ import jieba """ 需求: jieba.cut(sentence)-->参数需为字符串 问题:df的content列,每一条新闻取出 """ # 取出content-->list content_list = df_news.content.values.tolist() # content_list[1000] # 二维的列表 [[每一条新闻分词后的列表数据],[第二条...]] content_seg = [] # 循环遍历每条content内容 进行分词 for line in content_list: # 分词 seg_line = list(jieba.cut(line)) if len(seg_line)>1: content_seg.append(seg_line) # print(content_seg[1000])
"""
构建df数组
"""
df_content = pd.DataFrame({"content_seg":content_seg})
df_content
""" 3 数据清洗——停用词 每一条分词后的新闻词汇中,每个词汇都对文件分类有意义嘛? 比如常用词"真正"、"意义"、"等下"...这些常用词,可能会大量的出现在你的新闻当中,但是他对你进行文件分类无意义。可能还会干扰你的文件分类。 这些就是停用词!!!所以,接下来就需要清洗停用词。 """ """ 如果新闻当中的词汇在停用词文件中出现-->是否是停用词 - 是:则跳过 - 不是:添加 """ # 注意:加上quoting # 原因:当你用read_csv读文件的时候,如果文本里包含英文双引号,直接读取会导致行数变少或是直接如下报错停止,因此要加入quoting=3 stopwords = pd.read_csv("stopwords.txt",index_col=False,sep="\t",quoting=3,names=['stopword'],encoding='utf8') stopwords.head()
# 取出 分词后 的新闻内容数据 [["词1","词2"],[...]...] # df_content.content_seg.values.tolist()[1000] # 停用词的提取 一维 # stopwords.stopword.values.tolist()[5] # 去除停用词 def drop_stopwords(contents,stopwords): contents_clean = [] # 循环取出每一条新闻内容 for line in contents: line_clean = [] # 取出每一条新闻中 每个词汇 for word in line: # 判断 word是否在停用词列表中 if word in stopwords: # 在,则跳过 continue line_clean.append(word) contents_clean.append(line_clean) return contents_clean
contents = df_content.content_seg.values.tolist() # 二维
stopwords = stopwords.stopword.values.tolist() # 一维
contents_clean = drop_stopwords(contents,stopwords)
contents_clean[1000]
"""
4 构建 特征 与 标签 数据
"""
df_train = pd.DataFrame({"content_clean":contents_clean,"label":df_news["category"]})
df_train.head()
""" 问题:标签还是字符串,做映射为数值。比如:汽车替换为1 财经替换为2... 实现:pandas中的map方法可以实现 - 构建映射字典 {"汽车":1} - 实现映射 """ # 获取唯一的类别列表 df_category = df_train.label.unique() # df_category # {"汽车":1} # dict-->映射 [(汽车,1),(财经,2)] label_mapping = dict(list(zip(df_category,list(range(1,len(df_category)+1))))) # label_mapping df_train["label_d"] = df_train["label"].map(label_mapping) df_train.head()
"""
5 数据分割
"""
from sklearn.model_selection import train_test_split
x_train,x_test,y_train,y_test = train_test_split(df_train["content_clean"].values,df_train["label_d"].values,random_state=1)
"""
问题:特征词汇仍然为字符串,并没有转为频次。怎么实现?
CountVectorizer,就是统计词频。 中文特征提取就需要使用空格分割 如["1文章第1词 1文章第2词","2文章..."]
"""
words = []
for line_index in range(len(x_train)):
# print(x_train[line_index]) # []
words.append(" ".join(x_train[line_index]))
words[0]
from sklearn.feature_extraction.text import CountVectorizer vec = CountVectorizer(analyzer='word',max_features=4000,lowercase=False) # analyzer : 一般使用默认,可设置为string类型,如’word’, ‘char’, ‘char_wb’,还可设置为callable类型,比如函数是一个callable类型 # lowercase: 将所有字符变成小写 # max_features:默认为None,可设为int,对所有关键词的term frequency进行降序排序,只取前max_features个作为关键词集 # 更多的参数详解可以学习:sklearn——CountVectorizer详解 https://blog.csdn.net/liuerin/article/details/91492708 vec_fit = vec.fit_transform(words) print(vec.get_feature_names()) # 列表形式呈现文章生成的词典 print(vec.vocabulary_) # 字典形式呈现,key:词,value:词频 print(vec_fit.toarray()) # 是将结果转化为稀疏矩阵矩阵的表示方式; print(vec_fit.toarray().sum(axis=0)) #每个词在所有文档中的词频
""" 6 模型训练 """ from sklearn.naive_bayes import MultinomialNB # 朴素贝叶斯算法中的多项式朴素贝叶斯(MultinomialNB # 训练 bys_class = MultinomialNB() bys_class.fit(vec_fit,y_train) # 训练集特征词汇,训练集目标 # 测试 test_words = [] for line_index in range(len(x_test)): # print(x_train[line_index]) # [] test_words.append(" ".join(x_test[line_index])) bys_class.predict(vec.transform(test_words)) # 评分 bys_class.score(vec.transform(test_words),y_test) #0.804
"""
7 基于TF-IDF的特征词频计算: geng hao de ci pin te zheng ji suan
"""
from sklearn.feature_extraction.text import TfidfVectorizer
tf_vec = TfidfVectorizer(analyzer='word',max_features=4000,lowercase=False)
tf_vec.fit(words)
bys_class2 = MultinomialNB()
bys_class2.fit(tf_vec.transform(words),y_train)
bys_class2.score(tf_vec.transform(test_words),y_test)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。