python_sklearn机器学习算法系列之sklearn.naive_bayes朴树贝叶斯算法

       本文主要目的是通过一段及其简单的小程序来快速学习python 中sklearn的naive_bayes这一模块的基本操作和使用,注意不是用python纯粹从头到尾自己构建贝叶斯算法,既然sklearn提供了现成的我们直接拿来用就可以了,当然其原理十分重要,这里做一下简单介绍:

P(A|B)=P(A)×P(B|A)/P(B)
用文字表述:后验概率=先验概率×相似度/标准化常量
而朴素贝叶斯算法要解决的问题就是如何求出相似度即:P(B|A)的值[属性/特征]

所谓朴素就是假设属性之间相互独立即P(B|A)=P(B1|A)P(B2|A)P(B3|A)P(B4|A)

scikit-learn根据不同场景提供了三种常用的朴素贝叶斯算法:
如果样本特征的分布大部分是连续值,使用GaussianNB会比较好。
如果样本特征的分大部分是多元离散值,使用MultinomialNB比较合适。例如文本分类单词统计,以出现的次数作为特征值,https://www.jianshu.com/p/845b16559431
如果样本特征是二元离散值或者很稀疏的多元离散值,应该使用BernoulliNB。

三种算法的详细讲解见https://www.cnblogs.com/pinard/p/6074222.html

好了直接看代码(其中都有详细的注释)

GaussianNB:

#GaussianNB(高斯)类
from sklearn import datasets
from sklearn.naive_bayes import GaussianNB
import numpy as np
iris=datasets.load_iris()

#核心代码:其实fit后面还有一个参数即fit(X, y, sample_weight=None),sample_weight表各样本权重数组,假如一共训练8个样本
#则可以写为clf.fit(iris.data[:8], iris.target[:8],sample_weight=np.array([0.05,0.05,0.1,0.1,0.1,0.2,0.2,0.2]))
clf=GaussianNB()
clf.fit(iris.data,iris.target)


'''
#GaussianNB一个重要的功能是有 partial_fit方法,这个方法的一般用在如果训练集数据量非常大,一次不能全部载入
#内存的时候。这时我们可以把训练集分成若干等分,重复调用partial_fit来一步步的学习训练集,非常方便
#在第一次调用partial_fit函数时,必须制定classes参数,在随后的调用可以忽略
clf.partial_fit(iris.data, iris.target,classes=[0,1,2])

'''

#学习后模型中的一些参数
clf.set_params(priors=[0.333, 0.333, 0.333])#这里要设一下各个类标记对应的先验概率,如果不设置直接clf.priors返回的是None(不知道为什么?)
print(clf.priors)                           #获取各个类标记对应的先验概率
print(clf.class_prior_ )                    #同priors一样,都是获取各个类标记对应的先验概率,区别在于priors属性返回列表,class_prior_返回的是数组
print(clf.get_params(deep=True))            #返回priors与其参数值组成字典

print(clf.class_count_)                     #获取各类标记对应的训练样本数
print(clf.theta_)                           #获取各个类标记在各个特征上的均值
print(clf.sigma_)                           #获取各个类标记在各个特征上的方差



#测试数据
data_test=np.array([6,4,6,2])
data=data_test.reshape(1,-1)
Result_predict=clf.predict(data)
Score=clf.score([[6,8,5,3],[5,3,4,2],[4,6,7,2]],[2,0,1],sample_weight=[0.3,0.5,0.2])

Result_predict_proba=clf.predict_proba(data)
Result_predict_log_proba=clf.predict_log_proba(data)
print(Result_predict)                                                               #预测所属类别
print(Result_predict_proba)                                                         #输出测试样本在各个类标记上预测概率值
print(Result_predict_log_proba)                                                     #输出测试样本在各个类标记上预测概率值对应对数值
print(Score)                                                                        #返回测试样本映射到指定类标记上的得分(准确率)

运行结果:


MultinomialNB:

#详细地址请见:https://www.jianshu.com/p/845b16559431
import warnings
import numpy as np
from sklearn import metrics
from scipy.stats import sem
from sklearn.pipeline import Pipeline
from sklearn.datasets import fetch_20newsgroups
from sklearn.naive_bayes import MultinomialNB
from sklearn.model_selection import train_test_split
from sklearn.feature_extraction.text import TfidfVectorizer, HashingVectorizer, CountVectorizer

#忽略一些版本不兼容等警告
warnings.filterwarnings("ignore")
from sklearn.cross_validation import cross_val_score, KFold


news = fetch_20newsgroups(subset='all')

'''
#测试news,来了解数据集的构成
print (news.keys())
print (type(news.data), type(news.target), type(news.target_names))
print (news.target_names)
print(news.data[0])
print(news.target_names[news.target[0]])
print (len(news.data))
print (len(news.target))

'''

#原样本有18846个,为了运行快这里只抽取了样本中的188个样本进行实验,即用x_Reduced_sample1,y_Reduced_sample1进行实验
x_Reduced_sample1, x_Reduced_sample2 , y_Reduced_sample1, y_Reduced_sample2 = train_test_split(news.data, news.target, test_size = 0.99)

#划分训练集和测试集(76个)
x_train, x_test, y_train, y_test = train_test_split(x_Reduced_sample1, y_Reduced_sample1, test_size = 0.4)


#pipeline来将多个学习器组成流水线,通常流水线的形式为: 
#将数据标准化的学习器---特征提取的学习器---执行预测的学习器
#除了最后一个学习器之外,前面的所有学习器必须提供transform方法,该方法用于数据转化(例如:归一化,正则化,以及特征提取)
# CountVectorizer,HashingVectorizer,TfidfVectorizer是三种构建特征向量的工具
nbc_1 = Pipeline([
    ('vect', CountVectorizer()),
    ('clf', MultinomialNB()),
                ])
warnings.filterwarnings("ignore")
nbc_2 = Pipeline([
    ('vect', HashingVectorizer(non_negative=True)),
    ('clf', MultinomialNB()),
                ])
nbc_3 = Pipeline([
    ('vect', TfidfVectorizer()),
    ('clf', MultinomialNB()),
                ])
nbcs=[nbc_1, nbc_2, nbc_3]


#分类评价机制:k-折叠交叉验证
def evaluate_cross_validation(clf, X, y, K):
    # 最基础的CV算法,也是默认采用的CV策略,地址见http://blog.sina.com.cn/s/blog_7103b28a0102w70h.html
    cv = KFold(len(y), n_folds=K, shuffle=True, random_state=0)
    # k-折叠交叉验证地址见https://blog.csdn.net/evillist/article/details/61912827
    scores = cross_val_score(clf, X, y, cv=cv)
    #换分K组后每组的准确率(是一个数组)
    print(scores)
    #数组中准确率的平均值(越高越好)
    print(np.mean(scores))
    #数组中准确率平的均值标准误差。
    print(sem(scores))

#测试CountVectorizer,HashingVectorizer,TfidfVectorizer是三种构建特征向量的工具的性能
for nbc in nbcs:
    evaluate_cross_validation(nbc, x_train, y_train, 5)


'''

#优化特征提取提高分类的效果系列

#1:TfidfVectorizer的一个参数token_pattern用于指定提取单词的规则
#  默认的正则表达式是ur"\b\w\w+\b",这个正则表达式只匹配单词边界并考虑到了下划线,也可能考虑到了横杠和点。
#  新的正则表达式是ur"\b[a-z0-9_\-\.]+[a-z][a-z0-9_\-\.]+\b"
#2:TfidfVectorizer的一个参数stop_words这个参数指定的词将被省略不计入到标记词的列表中,
#  比如一些出现频率很高的词(英文中的a或者and等),但是这些词对于特定的主题不能提供任何的先验支持。
#3:MultinomialNB有一个alpha参数,该参数是一个平滑参数,默认是1.0,我们将其设为0.01
#!!!!!!!!!!但是1和2方案运行不通过不知道什么原因,去掉就可以
def get_stop_words():
    result = set()
    for line in open('stopwords_en.txt', 'r').readlines():
        result.add(line.strip())
    return result
stop_words= get_stop_words()
print(stop_words)
nbc_4 = Pipeline([
    ('vect', TfidfVectorizer(
                stop_words=stop_words,                                  #运行时去掉才行(不知道为什么?)
                token_pattern='ur\b[a-z0-9_\-\.]+[a-z][a-z0-9_\-\.]+\b',#运行时去掉才行(不知道为什么?)   
    )),
    ('clf', MultinomialNB(alpha=0.01)),
                ])

evaluate_cross_validation(nbc_4,x_train, y_train, 5)

'''
#fit_prior:布尔型,可选项,默认True,表示是否学习先验概率,参数为False表示所有类标记具有相同的先验概率
#class_prior:类似数组,数组大小为(n_classes,),默认None,是先验概率的值
#具体见https://blog.csdn.net/kancy110/article/details/72763276
nbc_5 = Pipeline([
    ('vect', TfidfVectorizer()),
    ('clf', MultinomialNB(alpha=0.01, class_prior=None, fit_prior=True)),
                ])
#核心代码
nbc_5.fit(x_train,y_train)
y_predict = nbc_5.predict(x_test)

print(nbc_5.score(x_test, y_test))                     #预测准确率
print(metrics.classification_report(y_test,y_predict)) #包含准确率,召回率等信息表
print(metrics.confusion_matrix(y_test,y_predict))      #混淆矩阵

'''
正如https://blog.csdn.net/kancy110/article/details/72763276介绍的那样如果有的场景直接用
MultinomialNB()时就可以完成任务,而不是先通过构建特征向量的工具时,学习后的模型还有很多参数可以看
包括:
class_log_prior_:各类标记的平滑先验概率对数值,其取值会受fit_prior和class_prior参数的影响
intercept_:将多项式朴素贝叶斯解释的class_log_prior_映射为线性模型,其值和class_log_propr相同
feature_log_prob_:指定类的各特征概率(条件概率)对数值,返回形状为(n_classes, n_features)数组
等等

'''

运行结果为:



BernoulliNB:

#伯努利朴素贝叶斯算法:类似于多项式朴素贝叶斯,也主要用户离散特征分类,
#和MultinomialNB的区别是:MultinomialNB以出现的次数为特征值,而BernoulliNB的特征值为二进制或布尔型特性
import numpy as np  
from sklearn.naive_bayes import BernoulliNB
x=np.array([[1,2,3,4],[1,3,4,4],[2,4,5,5],[5,6,9,8]])  
y=np.array([1,1,2,3])

#核心代码
clf=BernoulliNB(alpha=2.0,binarize = 3.0,fit_prior=True)
clf.fit(x,y)

'''
#训练后学习模型中的参数
print(np.log(2/4))
print(np.log(1/4))
print(np.log(1/4))
print(clf.class_log_prior_)   #对比上面,这是先验概率对数值,类先验概率等于各类的个数/类的总个数

print(clf.feature_log_prob_ ) #指定类的各特征概率(条件概率)对数值
print(clf.class_count_)       #按类别顺序输出其对应的个数
print(clf.feature_count_)     #各类别各特征值之和,按类的顺序输出,返回形状为[n_classes, n_features] 的数组(不懂?)

'''


#测试数据
x_test=[[1,2,2,5],[7,6,10,9]]                           #数据不能是分数
y_test_predict=clf.predict(x_test)
y_predict_proba=clf.predict_proba(x_test)
y_test_predict_log_proba=clf.predict_log_proba(x_test)
print(y_test_predict)                                   #在测试集x_test上预测,输出x_test对应目标值
print(y_predict_proba)                                  #输出测试样本划分到各个类别的概率值
print(y_test_predict_log_proba)                         #输出测试样本划分到各个类别的概率值的对数
print(clf.score([[3,4,5,4],[1,3,5,6]],[1,3]))           #输出对测试样本的预测准确率的平均值,当然可以加权值这个参数score(X, y, sample_weight=None) 

运行结果:


更多算法可以参看博主其他文章,或者github:https://github.com/Mryangkaitong/python-Machine-learning

猜你喜欢

转载自blog.csdn.net/weixin_42001089/article/details/79952245