美文网首页Python机器学习
机器学习笔记 - 22. 主题模型LDA实践(讲师:邹博)

机器学习笔记 - 22. 主题模型LDA实践(讲师:邹博)

作者: blade_he | 来源:发表于2019-02-12 18:38 被阅读0次

    课前问答

    问:在22.6代码中往LDA中喂数据的时候,为什么要计算TF/ IDF?
    答:一会解释,不算也可以

    主要内容

    2019-02-12 10_33_11-机器学习第七期升级版.png

    做LDA的时候,可以用TF-IDF做一个变换。
    在给LDA喂数据的时候,我们认为整个LDA是一个词袋模型,每一个词是独立的,将该词出现的次数数出来,其实就是各个词的强度。

    提到通过爬虫爬数据,获取数据源

    朴素贝叶斯

    2019-02-12 11_29_11-机器学习第七期升级版.png 2019-02-12 14_41_23-机器学习第七期升级版.png

    比如鸢尾花数据,有四个特征,即花萼长度,花萼宽度,花瓣长度,花瓣宽度,利用这四个特征,进行分类,分类结果为y(零散的0,1, 2三个值)。
    利用贝叶斯公式可得:
    P(y|花萼长度,花萼宽度,花瓣长度,花瓣宽度) = P(y)P(花萼长度,花萼宽度,花瓣长度,花瓣宽度|y) / P(花萼长度,花萼宽度,花瓣长度,花瓣宽度)

    2019-02-12 14_49_46-机器学习第七期升级版.png
    P(y)的含义:决定了y到底是0,1, 2哪一个的发生概率。
    比如在150个鸢尾花数据中,有:
    100: 0
    30: 1
    20: 2
    假定从这个150个数据,随机拿出一条数据,是0的概率是2/3, 1的概率是1/5, 2的概率是2/15
    即P(y)是先验概率。
    P(xi|y)的含义,假定y是女生,xi是身高,且假定符合高斯分布,假定女生的身高均值是1.62米,如果xi是1.86米,则P(xi|y)的值就会低一些。
    一般来说P(y)的概率,可以简单计算可得;
    但是P(xi|y)就需要建模,但是需要建模成什么样的分布(高斯分布,多项分布,伯努利分布。。。)
    2019-02-12 15_03_25-机器学习第七期升级版.png 2019-02-12 15_04_38-机器学习第七期升级版.png
    对于多项式分布来说,如果xi的个数是n,y的类别离散值为k,则有Kxn个参数
    比如,P(x=3|y=0),表示(y=0时,x=3出现了多少次)/ (y=0一共出现多少次),这个值就是频率,即用频率估计概率。
    分子加上α, 分母加上α x n(为了保证加和为1),因此公式有可能是这样子的,对于文档做LDA的意义:第一,为了防止过拟合;第二,为了避免出现未登录词,分母为0.
    即,如上图的公式。
    附注:拉普拉斯平滑
    2019-02-12 15_22_17-机器学习第七期升级版.png

    通过高斯朴素贝叶斯,对鸢尾花做分类
    以下代码,对邹博原有的代码做了一些修正:

    • feature_names加入了“类别”,修正串列的问题
    • features修改为花瓣长度与花瓣宽度,因为鸢尾花数据的花瓣长度起到分类决定性的作用

    问答
    问:朴素贝叶斯,朴素的点在哪?
    答:之所以朴素,因为我们认为特征是相对条件独立的。但对于现实世界的认识,说实话是不对的。比如用身高、体重、腰围,推断某人性别,用朴素贝叶斯的话,根据公式:

    2019-02-12 15_25_43-机器学习第七期升级版.png
    可以推导,如果y是男性,其身高的概率密度,体重的概率密度,腰围的概率密度,但是根据朴素贝叶斯的定义,身高,体重,腰围应该是独立的,但从实际情况出发,从来不是。比如体重如果比较重,腰围一般粗一些;身高如果比较高,体重一般不会太轻,比如身高1米9,体重80斤的概率就非常非常小。
    但是我们又可以通过假设的发散性,来解释朴素贝叶斯的应用: 2019-02-12 15_29_52-机器学习第七期升级版.png
    此外,还有假设的内涵型: 2019-02-12 15_31_17-机器学习第七期升级版.png
    假设的简化性: 2019-02-12 15_31_58-机器学习第七期升级版.png
    朴素贝叶斯,还有一个特性是特征是均衡的。即它认为这些数是直接相乘的出来的: 2019-02-12 15_25_43-机器学习第七期升级版.png
    问:朴素贝叶斯与贝叶斯有什么不同?
    答:完全是两个东西啊。朴素贝叶斯是应用贝叶斯公式得出结论的。贝叶斯,我们往往指贝叶斯先验,就是说我们想求取参数,并不认为参数是未知或定知,而是认为其实随机变量,那么就是属于贝叶斯了。
    问:如果有新词会不会就有某个p(x)=0?
    答:是的,多项式朴素贝叶斯公式中的分子加α,分母加上α x n就是为了处理这种情况的。
    问:如果考虑相关性呢?
    答:如果考虑相关性,我们就退化为普通的贝叶斯网络了,特征间有连接了。所以朴素贝叶斯,就是贝叶斯网络的一个特殊情况,没有边,只有y与xi的连接,弧段的简单的贝叶斯网络。
    问:如何去训练那个beta参数呢?
    答:是有可能的。可以先验去训练一个beta参数,我们认为beta本身是服从一个分布,就可以训练。
    问:有些独立假设在各个分类之间的分布都是均匀的,所以对于似然的相对大小不产生影响。即便不是如此,也有很大可能性,各个独立假设所产生的消极影响或积极影响互相抵消,最终导致结果受到的影响不大?
    答:前面一句没什么问题。但是后面一句,不能说相互抵消,不一定这么乐观的去想,不能说相互抵消,而是发生震荡。对于复杂模型,需要验证是否能够做独立假设的前提。

    在scikit-learn中,一共有3个朴素贝叶斯的分类算法类。分别是GaussianNB,MultinomialNB和BernoulliNB。其中GaussianNB就是先验为高斯分布的朴素贝叶斯,MultinomialNB就是先验为多项式分布的朴素贝叶斯,而BernoulliNB就是先验为伯努利分布的朴素贝叶斯。

    这三个类适用的分类场景各不相同,一般来说,如果样本特征的分布大部分是连续值,使用GaussianNB会比较好。如果样本特征的分布大部分是多元离散值,使用MultinomialNB比较合适。而如果样本特征是二元离散值或者很稀疏的多元离散值,应该使用BernoulliNB。

    #!/usr/bin/python
    # -*- coding:utf-8 -*-
    
    import numpy as np
    import pandas as pd
    import matplotlib.pyplot as plt
    import matplotlib as mpl
    from sklearn.preprocessing import StandardScaler, MinMaxScaler, PolynomialFeatures
    # GaussianNB, 先验为高斯分布的朴素贝叶斯
    # MultinomialNB, 先验为多项式分布的朴素贝叶斯
    from sklearn.naive_bayes import GaussianNB, MultinomialNB
    from sklearn.pipeline import Pipeline
    from sklearn.metrics import accuracy_score
    from sklearn.model_selection import train_test_split
    from sklearn.neighbors import KNeighborsClassifier
    
    
    def iris_type(s):
        it = {'Iris-setosa': 0, 'Iris-versicolor': 1, 'Iris-virginica': 2}
        return it[s]
    
    
    if __name__ == "__main__":
        data_type = 'iris'  # iris
    
        if data_type == 'car':
            colmun_names = 'buying', 'maint', 'doors', 'persons', 'lug_boot', 'safety', 'acceptability'
            data = pd.read_csv('car.data', header=None, names=colmun_names)
            for col in colmun_names:
                data[col] = pd.Categorical(data[col]).codes
            x = data[list(colmun_names[:-1])]
            y = data[colmun_names[-1]]
            x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.25, random_state=0)
            model = MultinomialNB(alpha=1)
            model.fit(x_train, y_train)
            y_train_pred = model.predict(x_train)
            print('CAR训练集准确率:', accuracy_score(y_train, y_train_pred))
            y_test_pred = model.predict(x_test)
            print('CAR测试集准确率:', accuracy_score(y_test, y_test_pred))
        else:
            feature_names = '花萼长度', '花萼宽度', '花瓣长度', '花瓣宽度', '类别'
            data = pd.read_csv('..\\9.Regression\\iris.data', header=None, names=feature_names)
            x, y = data[list(feature_names[:-1])], data[feature_names[-1]]
            y = pd.Categorical(values=data['类别']).codes
            # features = ['花萼长度', '花萼宽度']
            # 鸢尾花数据,花瓣长度起到决定性的作用
            features = ['花瓣长度', '花瓣宽度']
            x = x[features]
            x, x_test, y, y_test = train_test_split(x, y, test_size=0.3, random_state=0)
    
            priors = np.array((1,2,4), dtype=float)
            priors /= priors.sum()
            gnb = Pipeline([
                ('sc', StandardScaler()),
                ('poly', PolynomialFeatures(degree=1)),
                ('clf', GaussianNB(priors=priors))])    # 由于鸢尾花数据是样本均衡的,其实不需要设置先验值
            # gnb = KNeighborsClassifier(n_neighbors=3).fit(x, y.ravel())
            gnb.fit(x, y.ravel())
            y_hat = gnb.predict(x)
            print('IRIS训练集准确度: %.2f%%' % (100 * accuracy_score(y, y_hat)))
            y_test_hat = gnb.predict(x_test)
            print('IRIS测试集准确度:%.2f%%' % (100 * accuracy_score(y_test, y_test_hat)))  # 画图
    
            N, M = 500, 500     # 横纵各采样多少个值
            x1_min, x2_min = x.min()
            x1_max, x2_max = x.max()
            t1 = np.linspace(x1_min, x1_max, N)
            t2 = np.linspace(x2_min, x2_max, M)
            x1, x2 = np.meshgrid(t1, t2)                    # 生成网格采样点
            x_grid = np.stack((x1.flat, x2.flat), axis=1)   # 测试点
    
            mpl.rcParams['font.sans-serif'] = ['simHei']
            mpl.rcParams['axes.unicode_minus'] = False
            cm_light = mpl.colors.ListedColormap(['#77E0A0', '#FF8080', '#A0A0FF'])
            cm_dark = mpl.colors.ListedColormap(['g', 'r', 'b'])
            y_grid_hat = gnb.predict(x_grid)                  # 预测值
            y_grid_hat = y_grid_hat.reshape(x1.shape)
            plt.figure(facecolor='w')
            plt.pcolormesh(x1, x2, y_grid_hat, cmap=cm_light)     # 预测值的显示
            plt.scatter(x[features[0]], x[features[1]], c=y, edgecolors='k', s=30, cmap=cm_dark)
            plt.scatter(x_test[features[0]], x_test[features[1]], c=y_test, marker='^', edgecolors='k', s=40, cmap=cm_dark)
    
            plt.xlabel(features[0], fontsize=13)
            plt.ylabel(features[1], fontsize=13)
            plt.xlim(x1_min, x1_max)
            plt.ylim(x2_min, x2_max)
            plt.title('GaussianNB对鸢尾花数据的分类结果', fontsize=18)
            plt.grid(True, ls=':', color='#202020')
            plt.show()
    

    结果如下:
    IRIS训练集准确度: 96.19%
    IRIS测试集准确度:97.78%


    2019-02-12 11_27_42-Figure 1.png

    LDA的实现

    2019-02-12 15_44_43-机器学习第七期升级版.png

    VBEM:变分期望最大化
    Gensim:LDA的实现,是改进了David Blei的LDA-C的算法,并且使用了在线变分。


    2019-02-12 18_20_03-机器学习第七期升级版.png

    LSI/ LFM/ ICA本质都可以看做一个矩阵的分解。
    只要求出语料的LDA,就能计算出任意两个语料之间的相似度


    2019-02-12 18_22_28-机器学习第七期升级版.png
    我们使用余弦相似度的话,其实余弦相似度0~180,取值范围是1~-1的,负值的概念是不止不相似,甚至相反,即背道而驰的两个方向。
    类似于:终结者 与 武侠两个词,一个属于科幻,一个属于传统,它们的套路与想法完全不同。也许就是负的。
    2019-02-12 18_25_52-机器学习第七期升级版.png
    不管用LDA还是LSA,都能算出任何一个文档,属于某个主题的概率

    以及某主题,前n个重要的词


    2019-02-12 18_28_10-机器学习第七期升级版.png

    通过爬虫爬出新闻语料


    2019-02-12 18_29_27-机器学习第七期升级版.png

    通过TF/ IDF模型得到文档的每一个词的向量,然后喂给LDA,就能够做每一个文档的主题分布,以及观察每个主题分布在哪


    2019-02-12 18_30_41-机器学习第七期升级版.png
    2019-02-12 18_31_37-机器学习第七期升级版.png
    图形化主题与主题分布。

    如图,可以观察各个文档,最突出的主题是什么
    也可以观察每个主题的词分布情况


    2019-02-12 18_32_30-机器学习第七期升级版.png

    示例:


    2019-02-12 18_36_09-机器学习第七期升级版.png
    2019-02-12 18_37_27-机器学习第七期升级版.png

    相关文章

      网友评论

        本文标题:机器学习笔记 - 22. 主题模型LDA实践(讲师:邹博)

        本文链接:https://www.haomeiwen.com/subject/yluheqtx.html