LDA and CRF的资料,写得超级棒

李新春 发表了文章 • 0 个评论 • 79 次浏览 • 2017-09-06 14:56 • 来自相关话题

    近期看了一些自然语言处理方面的资料,就拿常用算法来说分为三大块。第一块基于词袋模型,不考虑序列性,其中代表模型有LSA,PLSA,LDA。第二块内容基于序列性质,也是一个大家族,包括HMM、MeMM、CRF。第三块内容基于深度学习,包括Word2Vector、SentenceEmbedding,以及其它很多利用深度网络来做翻译、聊天系统的资料。
    这里给出一个网盘链接,里面有两份资料。一份是大名鼎鼎的Rickjin(靳志辉)写得LDA数学八卦,内容循序渐进,重点是“科普”LDA的数学内容,之所以加引号是因为大牛眼里的科普对我们来说也很难,里面涉及了太多知识点,就只拿MCMC和Gibbs Sampling来说,这两个就很难弄明白。正因为其全面详细,才是一份入门好资料,全文52页,内有诸多“上帝的游戏”,有趣味性。结合这篇文章再加上上面给出的一些链接(主要是heinrich的Parameter Estimation for Text Analysis一文),可以对LDA有个深入的认识与了解。
    此外第二篇文章是Classical-Probabilistic-Models-and-Conditional-Random-Filelds。主要介绍了贝叶斯模型到隐马尔科夫模型,最大熵模型到条件随机场。其中一幅图把四者紧密联系起来,顿时觉得“一目了然”,加引号是因为这张图背后有太多太多东西。HMM与CRF里面涉及的三个问题,每个问题都涉及到大量数学公式,很难掌握。文章中有介绍。
    总之,LDA和CRF可以说是机器学习里面比较难的算法了,当然也是很重要的算法,掌握它们并非一朝一夕之功。将材料分享出来,是想多加探讨,以更深入了解。笔者这两篇文章都看过了,但是仍有很多不解之处,欢迎探讨。
 
附上链接 : 资料网盘http://pan.baidu.com/s/1pLRvUDP 查看全部
    近期看了一些自然语言处理方面的资料,就拿常用算法来说分为三大块。第一块基于词袋模型,不考虑序列性,其中代表模型有LSA,PLSA,LDA。第二块内容基于序列性质,也是一个大家族,包括HMM、MeMM、CRF。第三块内容基于深度学习,包括Word2Vector、SentenceEmbedding,以及其它很多利用深度网络来做翻译、聊天系统的资料。
    这里给出一个网盘链接,里面有两份资料。一份是大名鼎鼎的Rickjin(靳志辉)写得LDA数学八卦,内容循序渐进,重点是“科普”LDA的数学内容,之所以加引号是因为大牛眼里的科普对我们来说也很难,里面涉及了太多知识点,就只拿MCMC和Gibbs Sampling来说,这两个就很难弄明白。正因为其全面详细,才是一份入门好资料,全文52页,内有诸多“上帝的游戏”,有趣味性。结合这篇文章再加上上面给出的一些链接(主要是heinrich的Parameter Estimation for Text Analysis一文),可以对LDA有个深入的认识与了解。
    此外第二篇文章是Classical-Probabilistic-Models-and-Conditional-Random-Filelds。主要介绍了贝叶斯模型到隐马尔科夫模型,最大熵模型到条件随机场。其中一幅图把四者紧密联系起来,顿时觉得“一目了然”,加引号是因为这张图背后有太多太多东西。HMM与CRF里面涉及的三个问题,每个问题都涉及到大量数学公式,很难掌握。文章中有介绍。
    总之,LDA和CRF可以说是机器学习里面比较难的算法了,当然也是很重要的算法,掌握它们并非一朝一夕之功。将材料分享出来,是想多加探讨,以更深入了解。笔者这两篇文章都看过了,但是仍有很多不解之处,欢迎探讨。
 
附上链接 : 资料网盘http://pan.baidu.com/s/1pLRvUDP

韩韬带领H&M团队在前海征信“好信杯”大数据算法竞赛斩获学生团队冠军奖

郜梦蕊 发表了文章 • 0 个评论 • 187 次浏览 • 2017-06-30 13:56 • 来自相关话题

1.比赛概览
    作为平安旗下专业第三方商业征信机构,前海征信有着丰富的数据资源。本次赛事中主办方前海征信开放业务数据,设计国内首个迁移学习赛题:参赛选手需依据给定的4万条业务A数据及4千条业务B数据,建立业务B的信用评分模型。其中业务A为信用贷款, 其特征就是债务人无需提供抵押品,仅凭自己的信誉就能取得贷款,并以借款人信用程度作为还款保证的;业务B为现金贷,即发薪日贷款(payday loan),与一般的消费金融产品相比,现金贷主要具有以下五个特点:额度小、周期短、无抵押、流程快、利率高,这也是与其借贷门槛低的特征相适应的。由于业务A、B存在关联性,选手如何将业务A的知识迁移到业务B,以此增强业务B的信用评分模型,是本次比赛的重点。
    6月3日,历时近2个月的前海征信“好信杯”大数据算法大赛落下帷幕。本次大赛由前海征信主办,由科赛网承办。大赛吸引242支队伍共600多位选手参赛,选手们共提交145份模型作品、17份算法方案,最终 10支团队入围决赛。
    其中韩韬、刘伙玉组成的H&M团队在决赛中排名第二,荣获学生团队冠军奖,全体亚军的佳绩!
2.赛题回顾 
    自2006年Hinton等人提出“深度学习”概念至今,深度学习在海量数据的挖掘分析中发挥了巨大的价值。然而对于越来越多的任务来说,特定垂直领域的数据并不足以支持系统建构,而迁移学习正是克服这一限制的重要思路。
    微软全球资深副总裁Peter Lee博士在近期的采访中提出,如果所有的网络信息都成为机器学习系统的基础,那么系统就将通过迁移学习获得更个性化的信息,人工智能普及化将又迈出一大步。正是看准了迁移学习的巨大潜能,本次前海征信大数据算法赛事将赛题锁定在迁移学习方向,参赛选手需依据给定的4万条业务A数据及2千条业务B数据(均作脱敏处理),建立业务B的信用评分模型。
    在这篇专访中,队长韩韬将代表H&M团队,向大家展示他们解决本次迁移学习赛题的详细思路,并与大家分享他个人在数据分析领域学习过程中的心得体会。
3.团队介绍
    我们团队分工比较明确,贺敏做的是极限学习机ELM、韩东升做的是JDA概率适配,刘伙玉和肖聪在单模型调参和特征上进行探索,韩韬负责的是tradaboost以及最后的模型融合。




    接下来,我将从问题定义、特征工程、样本空间泛化、算法性能泛化、迁移模型介绍、模型融合和反思五方面来分享我们比赛的方法和经验。
4.问题定义
    首先阐述一下我们对迁移学习(Transfer Learning)问题的定义:
迁移学习或称归纳迁移、领域适配,是机器学习中的一个重要研究问题,其目标是将某个领域或任务上学习到的知识或模式应用到不同的但相关的领域或问题中。主要思想是从相关的辅助领域中迁移标注数据或知识结构、完成或改进目标领域或任务的学习效果。而通过本次赛题所给出的业务数据我们可以看出,A、B为相似信贷业务。A业务数据相对丰富,为源数据。B业务数据较少,为目标数据。





5.特征工程
    此次赛题的数据脱敏,因此特征工程部分相对粗糙。主要使用统计特征和一些特征选择的技巧,对空值填-1,连续值取对数再取整。在特征选择上简单采用了xgb的feature_importances的属性对特征进行评分,选取了约400维度特征。在特征这部分具体优化能做得到多少我们并没有再去尝试。










6.样本空间泛化
    Garbage in garbage out,我们首先从数据分布上进行调整。在群里也有人反应smote效果并不好,估计一个是因为smote本身是用KNN,从距离的角度对数据进行扰动,但是这份数据过于稀疏,且更多的是category型的变量,所以效果并不明显,但是我们还是保留了这个做法,因为后期会对数据再次进行过滤。在过滤数据时,原本数据集之间差异比较大,而且A_train比B_train大太多,所以tradaboost的权重调整基本没有什么效果。因此我们做了一些适当调整,对A_train更严格,丢掉的更多。





7.算法性能泛化
    调整样本权重和样本分布,降低Bias将B_test做伪标记,融合在训练数据中多模型投票,降低variance。










8.迁移模型介绍
    我们的想法是通过最小化边缘和条件分布显式降低两个不同但相关邻域之间差异。
    首先最小化边缘分布之间的距离,判别面就可以对进行更为准确地预测;其次最小化条件分布差异,将领域间与标注数据相关的判别结构更好得对应起来。










    上面两个ppt,我们是从特征的边缘概率分布上进行调整,算法如上可以看出边缘概率调整后近似一致。这种方法的实验效果在最右侧,可以看出使用的数据量越大,线上效果越好,但是限于计算能力,仅用了一半A_train数据。




    算法框架中我们规定A_train为源域,B_train为辅助域,B_test为目标域,源域数据有大量的前业务数据,并且有对应的标注。B_train为新业务数据,特点是数少。B_test为目前的业务数据,需要建模预测的数据。 
    这一部分是我们从模型角度进行迁移,极限学习机(Extreme Learning Machine) ELM,是由黄广斌提出来的求解单隐层神经网络的算法,利用迁移思想对此算法进行调整,利用损失函数中的B_train和B_test的修正神经网络的参数。
9.模型融合与反思
    模型融合:
    Tradaboost组合模型主要针对减小领域迁移过程出现的较大偏差问题而提出,利用Tradaboost来选择更合适的样本。
    概率适配模型是通过同时降低领域间的边缘分布和条件分布使得领域数据更加相似。
    极限迁移学习机模型主要侧重通过辅助域数据来调整模型参数,使得模型更加适用于目标领域。 
    总之,不同的模型侧重不同的角度,为了更全面的考虑问题,因此将不同的模型进行融合。
10.反思与总结:
    优势:
    逻辑思路与基础理论知识清晰扎实
    框架扩展性强,选择性广对模型要求低
    将不同的迁移学习思路所得模型进行融合,优势互补
    缺点:
    概率适配方法造成计算开销较大
    数据脱敏,特征工程部分做的相对粗糙
 
这是我们关于本次赛题的整体思路展示,希望能对大家解决类似问题有所帮助。
后面转载自科赛对韩韬的采访~
 
    小科:韩韬你好,首先祝贺你取得了这么好的成绩,据我所知这是国内第一次迁移类的赛题,在完成的过程中你觉得最大得难点在哪里?你和你的团队又是怎么去处理?
    韩韬:第一个是迁移辅助样本和目标域差距太大。盲目迁移太容易伤害模型,我们团队从样本、特征和模型,三个角度迁移多样化考虑。尽量使得融合模型差异性最化。其实遇到的一个很尴尬的问题就是不迁移的模型有时候反而表现比迁移更容易表好。但是,我们在做的时候,还是坚持从迁移的要求来。
第二个问题是数据脱敏。这对数据的分析和业务理解难度就很大了。很多团队都发现了有一些特征之间数据上表现出很强的关联性比如很多特征会出现批量的空缺。但是这个我们也没有办法去验证,只能做一些常用的特征工程,主要精力放在模型上。 
 
    小科: 这次现场决赛中,有没有其他选手的解题思路让你们觉得印象深刻值得学习的?
    韩韬:当然有啊,第一个当然是罗远飞啦。他答辩把我们绝杀了不过服气的,他在做模型的时候自己对数学的原理很清晰,他自己优化损失函数的那一手特别的惊艳。还有就是星合动力和龙樱他们吧,前者对数据哲学和业务理解讲的很多,后者模型简单实用。
 
    小科:我看本次比赛你们,包括很多其他队伍你们都选择了选择使用TrAdaBoost学习框架,你个人觉得TrAdaBoost和AdaBoost比区别在哪里?
    韩韬:我个人认为这两个本身就是针对不同任务的算法。虽然思想很相似。TrAdaboost会针对辅助样本做不同考虑,Adaboost没有这层考虑。如果用Adaboost会发现Atrain的比重会更占优势,毕竟大量的样本是a业务,但是这是和我们的目标是不一致的不过在应用TrAdaboost的时候也要根据实际问题调整,我觉得单纯调包的话上限不大。
 
    小科:你个人有没有什么好的有效学习方式可以和大家分享的?
    韩韬:第一个是学习上不要过分挑拣。现在网上课程资源很丰富。我在当一门课助教时,有很多人一直在问,什么书好?什么资料好?什么课好?我觉得过分问这些问题本身就是蛮浪费时间的。不过可能我目前水平有限吧,正处于野蛮生长的阶段,所以不用太挑。当然,到了更高阶的学习层次,就要斟酌了。
    综上所有,我觉得最重要的还是对基本原理的把握吧,不论做什么,都要能潜心看一看这个领域基础是什么,这一点我本身也要能坚持。我本身也很局限,跟大多数人的情景一样。并不是因为我们团队做出一些成绩所以说的话有价值。希望大家自行斟酌取舍啦。
 
 
  查看全部
  • 1.比赛概览

    作为平安旗下专业第三方商业征信机构,前海征信有着丰富的数据资源。本次赛事中主办方前海征信开放业务数据,设计国内首个迁移学习赛题:参赛选手需依据给定的4万条业务A数据及4千条业务B数据,建立业务B的信用评分模型。其中业务A为信用贷款, 其特征就是债务人无需提供抵押品,仅凭自己的信誉就能取得贷款,并以借款人信用程度作为还款保证的;业务B为现金贷,即发薪日贷款(payday loan),与一般的消费金融产品相比,现金贷主要具有以下五个特点:额度小、周期短、无抵押、流程快、利率高,这也是与其借贷门槛低的特征相适应的。由于业务A、B存在关联性,选手如何将业务A的知识迁移到业务B,以此增强业务B的信用评分模型,是本次比赛的重点。
    6月3日,历时近2个月的前海征信“好信杯”大数据算法大赛落下帷幕。本次大赛由前海征信主办,由科赛网承办。大赛吸引242支队伍共600多位选手参赛,选手们共提交145份模型作品、17份算法方案,最终 10支团队入围决赛。
    其中韩韬、刘伙玉组成的H&M团队在决赛中排名第二,荣获学生团队冠军奖,全体亚军的佳绩!
  • 2.赛题回顾 

    自2006年Hinton等人提出“深度学习”概念至今,深度学习在海量数据的挖掘分析中发挥了巨大的价值。然而对于越来越多的任务来说,特定垂直领域的数据并不足以支持系统建构,而迁移学习正是克服这一限制的重要思路。
    微软全球资深副总裁Peter Lee博士在近期的采访中提出,如果所有的网络信息都成为机器学习系统的基础,那么系统就将通过迁移学习获得更个性化的信息,人工智能普及化将又迈出一大步。正是看准了迁移学习的巨大潜能,本次前海征信大数据算法赛事将赛题锁定在迁移学习方向,参赛选手需依据给定的4万条业务A数据及2千条业务B数据(均作脱敏处理),建立业务B的信用评分模型。
    在这篇专访中,队长韩韬将代表H&M团队,向大家展示他们解决本次迁移学习赛题的详细思路,并与大家分享他个人在数据分析领域学习过程中的心得体会。
  • 3.团队介绍

    我们团队分工比较明确,贺敏做的是极限学习机ELM、韩东升做的是JDA概率适配,刘伙玉和肖聪在单模型调参和特征上进行探索,韩韬负责的是tradaboost以及最后的模型融合。

1团队介绍.jpg
    接下来,我将从问题定义、特征工程、样本空间泛化、算法性能泛化、迁移模型介绍、模型融合和反思五方面来分享我们比赛的方法和经验。
  • 4.问题定义

    首先阐述一下我们对迁移学习(Transfer Learning)问题的定义:
迁移学习或称归纳迁移、领域适配,是机器学习中的一个重要研究问题,其目标是将某个领域或任务上学习到的知识或模式应用到不同的但相关的领域或问题中。主要思想是从相关的辅助领域中迁移标注数据或知识结构、完成或改进目标领域或任务的学习效果。而通过本次赛题所给出的业务数据我们可以看出,A、B为相似信贷业务。A业务数据相对丰富,为源数据。B业务数据较少,为目标数据。

2.问题定义_.jpg

  • 5.特征工程

    此次赛题的数据脱敏,因此特征工程部分相对粗糙。主要使用统计特征和一些特征选择的技巧,对空值填-1,连续值取对数再取整。在特征选择上简单采用了xgb的feature_importances的属性对特征进行评分,选取了约400维度特征。在特征这部分具体优化能做得到多少我们并没有再去尝试。

特征工程1.jpg


特征工程2.jpg

  • 6.样本空间泛化

    Garbage in garbage out,我们首先从数据分布上进行调整。在群里也有人反应smote效果并不好,估计一个是因为smote本身是用KNN,从距离的角度对数据进行扰动,但是这份数据过于稀疏,且更多的是category型的变量,所以效果并不明显,但是我们还是保留了这个做法,因为后期会对数据再次进行过滤。在过滤数据时,原本数据集之间差异比较大,而且A_train比B_train大太多,所以tradaboost的权重调整基本没有什么效果。因此我们做了一些适当调整,对A_train更严格,丢掉的更多。

样本空间泛化.jpg

  • 7.算法性能泛化

    调整样本权重和样本分布,降低Bias将B_test做伪标记,融合在训练数据中多模型投票,降低variance。

算法性能泛化1.jpg


算法性能泛化2.jpg

  • 8.迁移模型介绍

    我们的想法是通过最小化边缘和条件分布显式降低两个不同但相关邻域之间差异。
    首先最小化边缘分布之间的距离,判别面就可以对进行更为准确地预测;其次最小化条件分布差异,将领域间与标注数据相关的判别结构更好得对应起来。

迁移模型介绍1.jpg


迁移模型介绍2.jpg

    上面两个ppt,我们是从特征的边缘概率分布上进行调整,算法如上可以看出边缘概率调整后近似一致。这种方法的实验效果在最右侧,可以看出使用的数据量越大,线上效果越好,但是限于计算能力,仅用了一半A_train数据。

迁移模型介绍3.jpg
    算法框架中我们规定A_train为源域,B_train为辅助域,B_test为目标域,源域数据有大量的前业务数据,并且有对应的标注。B_train为新业务数据,特点是数少。B_test为目前的业务数据,需要建模预测的数据。 
    这一部分是我们从模型角度进行迁移,极限学习机(Extreme Learning Machine) ELM,是由黄广斌提出来的求解单隐层神经网络的算法,利用迁移思想对此算法进行调整,利用损失函数中的B_train和B_test的修正神经网络的参数。
  • 9.模型融合与反思

    模型融合:
    Tradaboost组合模型主要针对减小领域迁移过程出现的较大偏差问题而提出,利用Tradaboost来选择更合适的样本。
    概率适配模型是通过同时降低领域间的边缘分布和条件分布使得领域数据更加相似。
    极限迁移学习机模型主要侧重通过辅助域数据来调整模型参数,使得模型更加适用于目标领域。 
    总之,不同的模型侧重不同的角度,为了更全面的考虑问题,因此将不同的模型进行融合。
  • 10.反思与总结:

    优势:
    逻辑思路与基础理论知识清晰扎实
    框架扩展性强,选择性广对模型要求低
    将不同的迁移学习思路所得模型进行融合,优势互补
    缺点:
    概率适配方法造成计算开销较大
    数据脱敏,特征工程部分做的相对粗糙
 
这是我们关于本次赛题的整体思路展示,希望能对大家解决类似问题有所帮助。
  • 后面转载自科赛对韩韬的采访~

 
    小科:韩韬你好,首先祝贺你取得了这么好的成绩,据我所知这是国内第一次迁移类的赛题,在完成的过程中你觉得最大得难点在哪里?你和你的团队又是怎么去处理?
    韩韬:第一个是迁移辅助样本和目标域差距太大。盲目迁移太容易伤害模型,我们团队从样本、特征和模型,三个角度迁移多样化考虑。尽量使得融合模型差异性最化。其实遇到的一个很尴尬的问题就是不迁移的模型有时候反而表现比迁移更容易表好。但是,我们在做的时候,还是坚持从迁移的要求来。
第二个问题是数据脱敏。这对数据的分析和业务理解难度就很大了。很多团队都发现了有一些特征之间数据上表现出很强的关联性比如很多特征会出现批量的空缺。但是这个我们也没有办法去验证,只能做一些常用的特征工程,主要精力放在模型上。 
 
    小科: 这次现场决赛中,有没有其他选手的解题思路让你们觉得印象深刻值得学习的?
    韩韬:当然有啊,第一个当然是罗远飞啦。他答辩把我们绝杀了不过服气的,他在做模型的时候自己对数学的原理很清晰,他自己优化损失函数的那一手特别的惊艳。还有就是星合动力和龙樱他们吧,前者对数据哲学和业务理解讲的很多,后者模型简单实用。
 
    小科:我看本次比赛你们,包括很多其他队伍你们都选择了选择使用TrAdaBoost学习框架,你个人觉得TrAdaBoost和AdaBoost比区别在哪里?
    韩韬:我个人认为这两个本身就是针对不同任务的算法。虽然思想很相似。TrAdaboost会针对辅助样本做不同考虑,Adaboost没有这层考虑。如果用Adaboost会发现Atrain的比重会更占优势,毕竟大量的样本是a业务,但是这是和我们的目标是不一致的不过在应用TrAdaboost的时候也要根据实际问题调整,我觉得单纯调包的话上限不大。
 
    小科:你个人有没有什么好的有效学习方式可以和大家分享的?
    韩韬:第一个是学习上不要过分挑拣。现在网上课程资源很丰富。我在当一门课助教时,有很多人一直在问,什么书好?什么资料好?什么课好?我觉得过分问这些问题本身就是蛮浪费时间的。不过可能我目前水平有限吧,正处于野蛮生长的阶段,所以不用太挑。当然,到了更高阶的学习层次,就要斟酌了。
    综上所有,我觉得最重要的还是对基本原理的把握吧,不论做什么,都要能潜心看一看这个领域基础是什么,这一点我本身也要能坚持。我本身也很局限,跟大多数人的情景一样。并不是因为我们团队做出一些成绩所以说的话有价值。希望大家自行斟酌取舍啦。
 
 
 

矩阵的几个疑难点

李新春 发表了文章 • 0 个评论 • 91 次浏览 • 2017-06-13 23:18 • 来自相关话题

     临近期末,总结自己这个学期学到的东西,感觉很多时间还是花费在了矩阵论、概率统计和最优化方法等数学方法上,所以应该好好做个总结,否则过一段时间就忘了。以后忘记时再来翻翻看。这是对矩阵这一块最后一篇文章了,比较杂,也比较充实。不过一个学期下来,感觉对Latex的确熟悉了很多,之前也有试过cmdmarkdown,感觉还是先用Latex吧,以后用到贴代码的文章再去用cmdmarkdown。
    下面两端是文章的导言,这里贴出来。
    在机器学习的理论推导中,几乎处处离不开矩阵和向量。之前已经总结了矩阵的奇异值分解和矩阵求导等公式,现在来整理一下自己在学习过程中认为比较有趣的,同时也是很重要的几个疑难点。分别是谱分解、范数、谱半径、条件数、广义特征值、矩阵直积、广义逆矩阵和矩阵分解。
    本文涉及很多公式定理,大多数参考自文献《矩阵论》chap[8],广义逆处参考《非线性最优化理论与方法》chap[8]。本文之所以大费周章地将公式定理从书中摘录下来,原因有二,一是可以当做一个整理思路的过程,如何把矩阵论的知识贯穿起来并和机器学习里面的知识挂钩,这是一个锻炼的过程;同时,将重要的公式自己敲一遍,可以加深印象,增强对里面知识点的理解。
    下面是文档截图。










  查看全部
     临近期末,总结自己这个学期学到的东西,感觉很多时间还是花费在了矩阵论、概率统计和最优化方法等数学方法上,所以应该好好做个总结,否则过一段时间就忘了。以后忘记时再来翻翻看。这是对矩阵这一块最后一篇文章了,比较杂,也比较充实。不过一个学期下来,感觉对Latex的确熟悉了很多,之前也有试过cmdmarkdown,感觉还是先用Latex吧,以后用到贴代码的文章再去用cmdmarkdown。
    下面两端是文章的导言,这里贴出来。
    在机器学习的理论推导中,几乎处处离不开矩阵和向量。之前已经总结了矩阵的奇异值分解和矩阵求导等公式,现在来整理一下自己在学习过程中认为比较有趣的,同时也是很重要的几个疑难点。分别是谱分解、范数、谱半径、条件数、广义特征值、矩阵直积、广义逆矩阵和矩阵分解。
    本文涉及很多公式定理,大多数参考自文献《矩阵论》chap[8],广义逆处参考《非线性最优化理论与方法》chap[8]。本文之所以大费周章地将公式定理从书中摘录下来,原因有二,一是可以当做一个整理思路的过程,如何把矩阵论的知识贯穿起来并和机器学习里面的知识挂钩,这是一个锻炼的过程;同时,将重要的公式自己敲一遍,可以加深印象,增强对里面知识点的理解。
    下面是文档截图。

jvzhen1.png


jvzhen2.png

 

估计

李新春 发表了文章 • 3 个评论 • 82 次浏览 • 2017-06-05 21:04 • 来自相关话题

 

估计1.png


估计2.png

 

支持向量机几何解释

李新春 发表了文章 • 0 个评论 • 74 次浏览 • 2017-05-23 20:26 • 来自相关话题

 
svm.png

 

机器学习常用数学公式(二):数理统计

李新春 发表了文章 • 0 个评论 • 81 次浏览 • 2017-05-20 21:31 • 来自相关话题

 

formula2.png

 

机器学习常用数学公式汇总(一)

李新春 发表了文章 • 2 个评论 • 104 次浏览 • 2017-05-07 10:47 • 来自相关话题

    这次分享的是数学公式的总结,同之前的一样,由于公式的不容易编辑,采用了Latex生成了pdf文件,附件里面可以下载。而博客内容就只贴出了pdf转换的图片文件,放大之后就可以清楚看到其中内容。




 
    这次分享的是数学公式的总结,同之前的一样,由于公式的不容易编辑,采用了Latex生成了pdf文件,附件里面可以下载。而博客内容就只贴出了pdf转换的图片文件,放大之后就可以清楚看到其中内容。
formula1.png

 

文本分类

李新春 发表了文章 • 0 个评论 • 115 次浏览 • 2017-04-30 21:24 • 来自相关话题

    由于之前在做文本分类的有关项目,这儿对文本分类的基本流程稍作总结。之前的项目是将十六万篇从WOS上下载的题录数据(包括AU、TI、ID、AB、SO、WC等字段),由于从WOS上下载数据时尽量保证了查全率,而查准率不太高,所以需要再从中挑出的确和研究主题相关的那部分题录数据。所以利用人工标注的数据当做训练集,这里的标注是指根据作者、主题、摘要等字段进行人工判断某一篇题录数据是否属于要研究的主题明确相关,所以这是个二分类问题。从这儿可以看出,其和垃圾邮件分类的基本形式差不多,自然而然就会想到文本分类的基本流程。所以下面介绍文本分类的几步操作,先说明一下,以下是对英文文本进行分类,某些地方不适合中文,但是基本流程类似(汉语难点在于分词操作)。
    文本分类有基于规则的分类和基于机器学习算法的分类两种。基于规则的大概可以理解为,通过该行业的专家制定一套规则,比如选取某些单词共现或频率高于阈值作为一个判断的依据,举个例子,比如某篇文献的题名出现了“soil”、“water”、“pollution”这三个单词,那么可以以60\%的概率断定这是一篇归为水污染主题的文章。这种基于规则的文本分类需要大量的专业知识和专业术语储备,并且费时费力。而基于机器学习的文本分类算法的主要思路则是将文本以某种方式转换为数值,然后利用朴素贝叶斯、支持向量机、决策树、集成学习、神经网络等算法进行训练。然而基于机器学习进行文本分类也是需要训练集作为支撑的,这就引发了文本分类的瓶颈--标注瓶颈问题,即需要专家事先进行人工标注数据集,这无疑也是非常耗时耗力的。当然标注瓶颈问题可以由半监督学习(Semi-supervised Learning)解决。除此之外,文本分类的另一难点就是文本到数值的转换过程和特征的提取了。
    文本分类首先要解决的是文本表示的问题,在信息检索领域,文本表示有布尔逻辑模型、向量空间模型、概率模型、潜在语义索引等表示方法。这里先给出几个名词:词(term)、文档(document)、文档集(document set)、词汇表(vocabulary)、文档向量、文档向量矩阵。词是经过分词、预处理后得到的文档最小单位,比如“dog”、“machin”,注意这里的“machin”为“machine”进行提取词干(stemming)预处理后得到的
结果;文档是一段文本或由几个字段里的文本拼凑在一起的文本进过预处理后得到的一个单词列表,比如[“cat”,“is”,“lovely”,...];文档集是所有文档的集合,可以看作是二维的矩阵;词汇表是从文档集中获取所有不重复的词构成的一个列表;文档向量是利用某种规则将文档转换为一个和词汇表一样大小的数值向量;文档向量矩阵是文档集里每一篇文档转换为文档向量之后得到的矩阵。这里个人称为文档向量和文档向量矩阵,或许有不准确之处,欢迎批评指正。下面据此,先简单介绍一下信息检索领域的几个模型:
    布尔逻辑模型: 词在文档里面出现则在构建文档向量时记为1,否则记为0。这样得到的文档向量的每一个分量全是0,1。比如词汇表为[“cat”,“dog”,“machin”,“learn”,“hard”],文档为[“machin”,“cat”],那么其转换的文档向量为[1,0,1,0,0]。在进行检索时,比如检索内容为“cat AND dog”,那么将文档向量代入得到“1 AND 0”,结果为False,所以此文档不匹配。由此可以看出布尔逻辑模型操作起来简单,但是效果不理想。
    向量空间模型(Vector Space Model): 相比于布尔逻辑模型,在构建文档向量时不仅仅只是判断其是否出现,而是利用了词在文档中出现的频次(词文档频率)、词逆向文档频率法(TF-IDF)等构建文档向量。在进行检索时,也不仅仅只是布尔操作,而是进行计算文档相似度,比如余弦相似度等。
    概率模型: 概率模型引入了贝叶斯分类,在检索时实质上是二元分类,相关或是不相关。但实际操作也没有分类的过程,而是对相关条件概率和非相关条件概率的比值进行排序,选择其排序前K个。
    潜在语义索引(Latent Semantic Indexing): 实质上是利用了奇异值分解对文档向量矩阵进行分解,选择其最大的几个奇异值对应的U和V进行分解,可以达到减少计算量和存储、降低噪声干扰等效果。关于奇异值分解,详细推导过程参见矩阵分解(一):奇异值分解。
    上面简单介绍了信息检索领域的文本表示方法。在文本分类中常用的就是词集模型(set-of-words)和词袋模型(bag-of-words),词集模型可以简单理解为布尔逻辑模型里面的文档向量表示方法,出现则为1,不出现则为0,不考虑频次等信息;词袋模型就相当于向量空间模型的文档向量表示法,最简单的就是统计词在文档中出现的频次。
    接下来便是文本分类的操作了,主要分为预处理、构建文档向量矩阵、特征选择、训练测试四个部分。
    预处理: 预处理操作包括分词、去除低频词、去除停用词(stop words)、提取词干(stemming)。在英文里面,分词主要是利用空格进行切分,同时还可考虑以分号、连字符等进行切分,当然也可以利用正则表达式进行匹配。去除低频词主要是为了提高分类效果、减少稀疏性、降低噪声影响,其主要思想是去除那些在所有文档出现频次小于某个阈值的单词,出现频次太小的单词对分类贡献不大,如不去除则会导致很多文档向量的分量为0,
另外还可以去除拼写错误的单词,降低噪声。去除停用词,即去除掉“is”、“he”等对分类无意义的词,停用词表可由网站http://www.ranks.nl/resources/stopwords.html获得;提取词干就是将“cat”,“cats”都统一变为“cat”等操作,降低数据之间的相关性。
    构建文档向量矩阵: 进过预处理操作,就得到了文档和文档集,将文档集里所有文档取并集,得到词汇表,也就是初步的特征集。根据特征集进行构建文档向量矩阵,如果只是简单采用词频法,则对每一篇文档,遍历词汇表,将词在文档中出现的频次作为文档向量对应分量的值即可。如果采用TF-IDF,其计算思想主要是:对于第i篇文档,如果词j在这个文档中出现的频次高,那么赋予其较大的权值,如果其在大部分文档中都出现了,那么其携带的分类信息就少了,那么赋予其较小的权值。用词在该文档中出现的次数即词频当作tf,用总的文档数量除以
包含该词的文档数量,再取对数,当作idf。文档i的文档向量的第j个分量w计算公式如下:






    特征选择:构建文档向量矩阵的同时也得到了词汇表,即特征集,很多时候,文档数量即样本数目很少,但是特征数量却很多。虽然经过了去除停用词、去除低频、提取词干等操作,但是仍然会有很多词汇被选入特征。特征选择是机器学习里面对预测结果影响很大的一块内容,有时通过优化算法、调参得到的模型改善却不如进行特征选择带来的改进大,由此也导致了特征选择是比较难以处理的一块内容。可以说,深度学习网络在全连接层之前进行的卷积、池化等操作就是特征提取的过程。这里,特征选择和特征提取并不是相同的概念,但二者目的相同,都是为了减少特征维数,避免维数灾难(Curse of Dimensionality)。文本特征选择的方法主要有:对于单个特征采用信息增益、ROC曲线、互信息、期望交叉熵、统计检验等,对于多个特征的选择包括顺序前向选择、顺序后向选择、浮动搜索技术等。
        信息增益:记D位标签列,对每个特征A基于以下公式进行计算,最后对每个特征的信息增益进行排序可得到前K个特征:






        ROC曲线:对每个特征A和标签D,对特征A取值的范围进行取阈值,然后以此阈值分类,计算分类结果的召回率和假阳率,得到ROC曲线上的一个点,逐步将所有的阈值得到的点进行计算得到AUC。最后对AUC进行排序,得到特征的重要性排序。
        统计检验:主要是利用卡方检验、t检验等操作判断类的可分性等。
        顺序前向选择:这是对特征子集的选取,假设现在先选择了k个特征,下面对剩下的特征进行遍历,将特征加入k个特征构成k+1维的特征集。选择使得评价函数最优的那个特征作为第k+1个特征,这里的评价函数主要包括filter和wrapper两种(目前尚未接触过这部分内容,这里先省略对其的叙述)。逐步选择,直到选择K个特征。
    其余特征选择算法不再详细叙述。特征提取算法主要包括主成分分析,即利用PCA进行降维等。
    训练测试:当文档向量矩阵构建完成以及特征提取也完成之后,就可以利用算法进行训练测试了,贝叶斯分类器、支持向量机、随机森林、集成学习算法等都是文本分类领域适用的算法,个人项目中支持向量机结果最好,随机森林次之。
    最后就是编程实现了,还好sklearn包提供了很多便捷的工具可以很快搭建出来一个小型的文本分类器。
    先贴出来代码,代码文件见附件text.py(打包在text.zip),版本是python3.5,环境是Anaconda,需要调用的包有sklearn.feature_extraction.text里的CountVectorizer、TfidfVectorizer、numpy、nltk.stem。其中nltk.stem是进行词干提取的包,在anaconda里面没有集成,下载官网为http://www.nltk.org/install.html。官网上说在windows下安装需要Python3.5并且只适用于32位,还有的博客说不能直接用pip install安装,但是实际上,在anaconda命令行下直接conda install nltk即可成功。
    程序测试用数据为['This is a book about machine learning.',  'It\'s a cat classified by manual labeling.',  'A newspaper about machine learning.',  'Cats are lovely,while dogs are not.',  'Reading books about machine learning,with a cat at hand.'],这是一个包括五篇文献的文档集。
    关键代码展示如下:其具体内容和其余实验代码以及输出结果可参考博客代码内容(代码展示效果不好)或附件text.py。
    # 综合了去除低频词、去除停用词、词干提取、tfidf的文档向量构建函数,只需传入原始文档即可
    def tfidf_stem_stop_words_vector(text_data):
    # 利用sklearn提供的TfidfVectorizer构造词向量提取器,这个类在上述函数中用到
    class StemmedTfidfVectorizer(TfidfVectorizer):
   
代码文件text.py内容:   
#coding: UTF-8
#encoding: UTF-8
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.feature_extraction.text import TfidfVectorizer
import numpy as np
import nltk.stem as ns


def get_simple_data():
    text_data = ['This is a book about machine learning.',
                 'It\'s a cat classified by manual labeling.',
                 'A newspaper about machine learning.',
                 'Cats are lovely,while dogs are not.',
                 'Reading books about machine learning,with a cat at hand.']
    return text_data
# 先不做任何处理,只是简单对文档进行分词
def simple_text_preprocess(text_data):
    vectorizer = CountVectorizer(min_df=1)                 # min_df代指单词在所有文档中出现的频率小于min_df的都被过滤掉;如果是分数,则按频率计算
    print(vectorizer)
    words_vector = vectorizer.fit_transform(text_data)     # 在文本集中进行提取词向量
    words_feature_names = vectorizer.get_feature_names()   # 得到选取的特征
    print('feature_names:',words_feature_names)
    print('words_vector:',words_vector.toarray())          # 输出词向量,不用toarray()则输出稀疏矩阵;有toarray()则输出完整矩阵
    
    new_text = ['Machine learning is hard to learn for a cat.',
                 'Cat is lazy.']
    new_words_vector = vectorizer.transform(new_text)      # 对新的文本数据进行转换
    print('new_text_words_vector:',new_words_vector.toarray())
# 去除停用词进行分词
def stop_words_text_preprocess(text_data):    
    # 去除停用词之后再进行以便操作
    vectorizer = CountVectorizer(min_df=1,stop_words='english')   # 简单加入"stop_words"即可
    words_vector = vectorizer.fit_transform(text_data)     # 在文本集中进行提取词向量
    words_feature_names = vectorizer.get_feature_names()   # 得到选取的特征
    print('remove_stopwords,feature_names:',words_feature_names)
    print('remove_stopwords,words_vector:',words_vector.toarray())          # 输出词向量,不用toarray()则输出稀疏矩阵;有toarray()则输出完整矩阵
    
    new_text = ['Machine learning is hard to learn for a cat.',
                 'Cat is lazy.']
    new_words_vector = vectorizer.transform(new_text)      # 对新的文本数据进行转换
    print('remove_stopwords,new_text_words_vector:',new_words_vector.toarray())
# 再加上提取词干
def stem_stop_text_preprocess(text_data):
    # stemming提取词干
    st = ns.SnowballStemmer('english')    # 构造提取器
    print('imaging->',st.stem('imaging'),'machine->',st.stem('machine'),'learning->',st.stem('learning'))
    
    # 根据自己构造的StemmedCountVectorizer进行对文本集提取词干
    vectorizer = StemmedCountVectorizer(min_df=1,stop_words='english')
    words_vector = vectorizer.fit_transform(text_data)     # 在文本集中进行提取词向量
    words_feature_names = vectorizer.get_feature_names()   # 得到选取的特征
    print('remove_stopwords,feature_names:',words_feature_names)
    print('remove_stopwords,words_vector:',words_vector)          # 输出词向量,不用toarray()则输出稀疏矩阵;有toarray()则输出完整矩阵
                                
    new_text = ['Machine learning is hard to learn for a cat.',
                 'Cat is lazy.']
    new_words_vector = vectorizer.transform(new_text)      # 对新的文本数据进行转换
    print('remove_stopwords,new_text_words_vector:',new_words_vector)
# 去除停用词的词向量提取器
class StemmedCountVectorizer(CountVectorizer):
    def build_analyzer(self):
        english_stemmer = ns.SnowballStemmer('english')
        analyzer = super(StemmedCountVectorizer,self).build_analyzer()
        return lambda doc: (english_stemmer.stem(w) for w in analyzer(doc))

# 自己实现TFIDF,输入参数为某个要求tfidf的单词,其所在的文档,所有文档集合
def tfidf(term,doc,corpus):
    tf = doc.count(term)/len(doc)                    # 文档频率,单词在其所属文档中出现的频率
    num_docs_with_term = len([d for d in corpus if term in d]) # 包含这个单词的文档总数
    idf = np.log(len(corpus)/num_docs_with_term)     # 文档逆频率,总的文档数除以包含这个单词的文档总数,再取对数
    return tf*idf     
# 测试自己实现的tfidf
def test_tfidf():
    doc = ['cat','cat','dog','dog','machin','learn']
    corpus = [['cat','machin','learn'],
              ['machin','learn'],
              ['cat','learn'],
              ['dog','machin','learn'],
              ['cat','cat','dog','dog','machin','learn']]
    for term in set(doc):
        print('term,tfidf:',term,tfidf(term,doc,corpus))
# 再加入tfidf进行处理
def tfidf_stem_stop_words_vector(text_data):
    # stemming提取词干
    st = ns.SnowballStemmer('english')    # 构造提取器
    print('imaging->',st.stem('imaging'),'machine->',st.stem('machine'),'learning->',st.stem('learning'))
    
    # 根据自己构造的StemmedTfidfVectorizer构造tfidf词向量
    vectorizer = StemmedTfidfVectorizer(min_df=1,stop_words='english',decode_error='ignore') # 忽略编码错误
    words_vector = vectorizer.fit_transform(text_data)     # 在文本集中进行提取词向量
    words_feature_names = vectorizer.get_feature_names()   # 得到选取的特征
    print('remove_stopwords,feature_names:',words_feature_names)
    print('remove_stopwords,words_vector:',words_vector)          # 输出词向量,不用toarray()则输出稀疏矩阵;有toarray()则输出完整矩阵
                                
    new_text = ['Machine learning is hard to learn for a cat.',
                 'Cat is lazy.']
    new_words_vector = vectorizer.transform(new_text)      # 对新的文本数据进行转换
    print('remove_stopwords,new_text_words_vector:',new_words_vector)
# 利用sklearn提供的TfidfVectorizer构造词向量提取器
class StemmedTfidfVectorizer(TfidfVectorizer):
    def build_analyzer(self):
        english_stemmer = ns.SnowballStemmer('english')
        analyzer = super(TfidfVectorizer,self).build_analyzer()
        return lambda doc: (english_stemmer.stem(w) for w in analyzer(doc))

# 简单计算欧氏距离
def dist_raw(v1,v2):
    delta = v1 - v2
    return np.linalg.norm(delta.toarray())


if __name__ == "__main__":
    text_data_1 = get_simple_data()
    #simple_text_preprocess(text_data_1)
    #stop_words_text_preprocess(text_data_1)
    #stem_stop_text_preprocess(text_data_1)
    #test_tfidf()
    tfidf_stem_stop_words_vector(text_data_1)
  
    代码文件到此结束,下面是实例输出结果:
'''
    text_preprocess(text_data_1)输出结果:
    
    CountVectorizer的详细用法:
        analyzer是表示基于word进行分词、并且以token_pattern为正则进行分词这里的u'(?u)\\b\\w\\w+\\b'
        stop_words指是否使用停用词
        lowercase是先将所有变成小写
        
    CountVectorizer(analyzer=u'word', binary=False, decode_error=u'strict',
        dtype=<type 'numpy.int64'>, encoding=u'utf-8', input=u'content',
        lowercase=True, max_df=1.0, max_features=None, min_df=1,
        ngram_range=(1, 1), preprocessor=None, stop_words=None,
        strip_accents=None, token_pattern=u'(?u)\\b\\w\\w+\\b',
        tokenizer=None, vocabulary=None)
    ('feature_names:', [u'about', u'are', u'at', u'book', u'books', u'by', u'cat', u'cats', u'classified', u'dogs', u'hand', u'is', u'it', u'labeling', u'learning', u'lovely', u'machine', u'manual', u'newspaper', u'not', u'reading', u'this', u'while', u'with'])
    ('words_vector:', array([[1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1,
        0, 0],
       [0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0,
        0, 0],
       [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0,
        0, 0],
       [0, 2, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0,
        1, 0],
       [1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0,
        0, 1]], dtype=int64))
    ('new_text_words_vector:', array([[0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0,
        0, 0],
       [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0]], dtype=int64))
    
    stop_words_text_preprocess(text_data_1)输出结果:
    ('remove_stopwords,feature_names:', [u'book', u'books', u'cat', u'cats', u'classified', u'dogs', u'hand', u'labeling', u'learning', u'lovely', u'machine', u'manual', u'newspaper', u'reading'])
    ('remove_stopwords,words_vector:', array([[1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0],
       [0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0],
       [0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0],
       [0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0],
       [0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1]], dtype=int64))
    ('remove_stopwords,new_text_words_vector:', array([[0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0],
       [0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]], dtype=int64))
    
    stem_stop_text_preprocess(text_data_1)输出结果:
    imaging-> imag machine-> machin learning-> learn
    remove_stopwords,feature_names: ['book', 'cat', 'classifi', 'dog', 'hand', 'label', 'learn', 'love', 'machin', 'manual', 'newspap', 'read']
    remove_stopwords,words_vector:   (0, 6) 1
      (0, 8)        1
      (0, 0)        1
      (1, 5)        1
      (1, 9)        1
      (1, 2)        1
      (1, 1)        1
      (2, 10)       1
      (2, 6)        1
      (2, 8)        1
      (3, 3)        1
      (3, 7)        1
      (3, 1)        1
      (4, 4)        1
      (4, 11)       1
      (4, 1)        1
      (4, 6)        1
      (4, 8)        1
      (4, 0)        1
    remove_stopwords,new_text_words_vector:   (0, 1)        1
      (0, 6)        2
      (0, 8)        1
      (1, 1)        1
    
    text_tfidf()输出结果:
    term,tfidf: learn 0.0
    term,tfidf: machin 0.0371905918857
    term,tfidf: cat 0.170275207922
    term,tfidf: dog 0.305430243958
    
    tfidf_stem_stop_words_vector(text_data_1)输出结果:
    imaging-> imag machine-> machin learning-> learn
    remove_stopwords,feature_names: ['book', 'cat', 'classifi', 'dog', 'hand', 'label', 'learn', 'love', 'machin', 'manual', 'newspap', 'read']
    remove_stopwords,words_vector:   (0, 0) 0.648462625687
      (0, 8)        0.538282557346
      (0, 6)        0.538282557346
      (1, 1)        0.36063832635
      (1, 2)        0.538497910106
      (1, 9)        0.538497910106
      (1, 5)        0.538497910106
      (2, 8)        0.486240416592
      (2, 6)        0.486240416592
      (2, 10)       0.726044430146
      (3, 1)        0.427992922683
      (3, 7)        0.639070441396
      (3, 3)        0.639070441396
      (4, 0)        0.40357561577
      (4, 8)        0.335004217566
      (4, 6)        0.335004217566
      (4, 1)        0.335004217566
      (4, 11)       0.500221573402
      (4, 4)        0.500221573402
    remove_stopwords,new_text_words_vector:   (0, 8)        0.408248290464
      (0, 6)        0.816496580928
      (0, 1)        0.408248290464
      (1, 1)        1.0
'''

  查看全部
    由于之前在做文本分类的有关项目,这儿对文本分类的基本流程稍作总结。之前的项目是将十六万篇从WOS上下载的题录数据(包括AU、TI、ID、AB、SO、WC等字段),由于从WOS上下载数据时尽量保证了查全率,而查准率不太高,所以需要再从中挑出的确和研究主题相关的那部分题录数据。所以利用人工标注的数据当做训练集,这里的标注是指根据作者、主题、摘要等字段进行人工判断某一篇题录数据是否属于要研究的主题明确相关,所以这是个二分类问题。从这儿可以看出,其和垃圾邮件分类的基本形式差不多,自然而然就会想到文本分类的基本流程。所以下面介绍文本分类的几步操作,先说明一下,以下是对英文文本进行分类,某些地方不适合中文,但是基本流程类似(汉语难点在于分词操作)。
    文本分类有基于规则的分类和基于机器学习算法的分类两种。基于规则的大概可以理解为,通过该行业的专家制定一套规则,比如选取某些单词共现或频率高于阈值作为一个判断的依据,举个例子,比如某篇文献的题名出现了“soil”、“water”、“pollution”这三个单词,那么可以以60\%的概率断定这是一篇归为水污染主题的文章。这种基于规则的文本分类需要大量的专业知识和专业术语储备,并且费时费力。而基于机器学习的文本分类算法的主要思路则是将文本以某种方式转换为数值,然后利用朴素贝叶斯、支持向量机、决策树、集成学习、神经网络等算法进行训练。然而基于机器学习进行文本分类也是需要训练集作为支撑的,这就引发了文本分类的瓶颈--标注瓶颈问题,即需要专家事先进行人工标注数据集,这无疑也是非常耗时耗力的。当然标注瓶颈问题可以由半监督学习(Semi-supervised Learning)解决。除此之外,文本分类的另一难点就是文本到数值的转换过程和特征的提取了。
    文本分类首先要解决的是文本表示的问题,在信息检索领域,文本表示有布尔逻辑模型、向量空间模型、概率模型、潜在语义索引等表示方法。这里先给出几个名词:词(term)、文档(document)、文档集(document set)、词汇表(vocabulary)、文档向量、文档向量矩阵。词是经过分词、预处理后得到的文档最小单位,比如“dog”、“machin”,注意这里的“machin”为“machine”进行提取词干(stemming)预处理后得到的
结果;文档是一段文本或由几个字段里的文本拼凑在一起的文本进过预处理后得到的一个单词列表,比如[“cat”,“is”,“lovely”,...];文档集是所有文档的集合,可以看作是二维的矩阵;词汇表是从文档集中获取所有不重复的词构成的一个列表;文档向量是利用某种规则将文档转换为一个和词汇表一样大小的数值向量;文档向量矩阵是文档集里每一篇文档转换为文档向量之后得到的矩阵。这里个人称为文档向量和文档向量矩阵,或许有不准确之处,欢迎批评指正。下面据此,先简单介绍一下信息检索领域的几个模型:
    布尔逻辑模型: 词在文档里面出现则在构建文档向量时记为1,否则记为0。这样得到的文档向量的每一个分量全是0,1。比如词汇表为[“cat”,“dog”,“machin”,“learn”,“hard”],文档为[“machin”,“cat”],那么其转换的文档向量为[1,0,1,0,0]。在进行检索时,比如检索内容为“cat AND dog”,那么将文档向量代入得到“1 AND 0”,结果为False,所以此文档不匹配。由此可以看出布尔逻辑模型操作起来简单,但是效果不理想。
    向量空间模型(Vector Space Model): 相比于布尔逻辑模型,在构建文档向量时不仅仅只是判断其是否出现,而是利用了词在文档中出现的频次(词文档频率)、词逆向文档频率法(TF-IDF)等构建文档向量。在进行检索时,也不仅仅只是布尔操作,而是进行计算文档相似度,比如余弦相似度等。
    概率模型: 概率模型引入了贝叶斯分类,在检索时实质上是二元分类,相关或是不相关。但实际操作也没有分类的过程,而是对相关条件概率和非相关条件概率的比值进行排序,选择其排序前K个。
    潜在语义索引(Latent Semantic Indexing): 实质上是利用了奇异值分解对文档向量矩阵进行分解,选择其最大的几个奇异值对应的U和V进行分解,可以达到减少计算量和存储、降低噪声干扰等效果。关于奇异值分解,详细推导过程参见矩阵分解(一):奇异值分解
    上面简单介绍了信息检索领域的文本表示方法。在文本分类中常用的就是词集模型(set-of-words)和词袋模型(bag-of-words),词集模型可以简单理解为布尔逻辑模型里面的文档向量表示方法,出现则为1,不出现则为0,不考虑频次等信息;词袋模型就相当于向量空间模型的文档向量表示法,最简单的就是统计词在文档中出现的频次。
    接下来便是文本分类的操作了,主要分为预处理、构建文档向量矩阵、特征选择、训练测试四个部分。
    预处理: 预处理操作包括分词、去除低频词、去除停用词(stop words)、提取词干(stemming)。在英文里面,分词主要是利用空格进行切分,同时还可考虑以分号、连字符等进行切分,当然也可以利用正则表达式进行匹配。去除低频词主要是为了提高分类效果、减少稀疏性、降低噪声影响,其主要思想是去除那些在所有文档出现频次小于某个阈值的单词,出现频次太小的单词对分类贡献不大,如不去除则会导致很多文档向量的分量为0,
另外还可以去除拼写错误的单词,降低噪声。去除停用词,即去除掉“is”、“he”等对分类无意义的词,停用词表可由网站http://www.ranks.nl/resources/stopwords.html获得;提取词干就是将“cat”,“cats”都统一变为“cat”等操作,降低数据之间的相关性。
    构建文档向量矩阵: 进过预处理操作,就得到了文档和文档集,将文档集里所有文档取并集,得到词汇表,也就是初步的特征集。根据特征集进行构建文档向量矩阵,如果只是简单采用词频法,则对每一篇文档,遍历词汇表,将词在文档中出现的频次作为文档向量对应分量的值即可。如果采用TF-IDF,其计算思想主要是:对于第i篇文档,如果词j在这个文档中出现的频次高,那么赋予其较大的权值,如果其在大部分文档中都出现了,那么其携带的分类信息就少了,那么赋予其较小的权值。用词在该文档中出现的次数即词频当作tf,用总的文档数量除以
包含该词的文档数量,再取对数,当作idf。文档i的文档向量的第j个分量w计算公式如下:

tfidf.png


    特征选择:构建文档向量矩阵的同时也得到了词汇表,即特征集,很多时候,文档数量即样本数目很少,但是特征数量却很多。虽然经过了去除停用词、去除低频、提取词干等操作,但是仍然会有很多词汇被选入特征。特征选择是机器学习里面对预测结果影响很大的一块内容,有时通过优化算法、调参得到的模型改善却不如进行特征选择带来的改进大,由此也导致了特征选择是比较难以处理的一块内容。可以说,深度学习网络在全连接层之前进行的卷积、池化等操作就是特征提取的过程。这里,特征选择和特征提取并不是相同的概念,但二者目的相同,都是为了减少特征维数,避免维数灾难(Curse of Dimensionality)。文本特征选择的方法主要有:对于单个特征采用信息增益、ROC曲线、互信息、期望交叉熵、统计检验等,对于多个特征的选择包括顺序前向选择、顺序后向选择、浮动搜索技术等。
        信息增益:记D位标签列,对每个特征A基于以下公式进行计算,最后对每个特征的信息增益进行排序可得到前K个特征:

infogain.png


        ROC曲线:对每个特征A和标签D,对特征A取值的范围进行取阈值,然后以此阈值分类,计算分类结果的召回率和假阳率,得到ROC曲线上的一个点,逐步将所有的阈值得到的点进行计算得到AUC。最后对AUC进行排序,得到特征的重要性排序。
        统计检验:主要是利用卡方检验、t检验等操作判断类的可分性等。
        顺序前向选择:这是对特征子集的选取,假设现在先选择了k个特征,下面对剩下的特征进行遍历,将特征加入k个特征构成k+1维的特征集。选择使得评价函数最优的那个特征作为第k+1个特征,这里的评价函数主要包括filter和wrapper两种(目前尚未接触过这部分内容,这里先省略对其的叙述)。逐步选择,直到选择K个特征。
    其余特征选择算法不再详细叙述。特征提取算法主要包括主成分分析,即利用PCA进行降维等。
    训练测试:当文档向量矩阵构建完成以及特征提取也完成之后,就可以利用算法进行训练测试了,贝叶斯分类器、支持向量机、随机森林、集成学习算法等都是文本分类领域适用的算法,个人项目中支持向量机结果最好,随机森林次之。
    最后就是编程实现了,还好sklearn包提供了很多便捷的工具可以很快搭建出来一个小型的文本分类器。
    先贴出来代码,代码文件见附件text.py(打包在text.zip),版本是python3.5,环境是Anaconda,需要调用的包有sklearn.feature_extraction.text里的CountVectorizer、TfidfVectorizer、numpy、nltk.stem。其中nltk.stem是进行词干提取的包,在anaconda里面没有集成,下载官网为http://www.nltk.org/install.html。官网上说在windows下安装需要Python3.5并且只适用于32位,还有的博客说不能直接用pip install安装,但是实际上,在anaconda命令行下直接conda install nltk即可成功。
    程序测试用数据为['This is a book about machine learning.',  'It\'s a cat classified by manual labeling.',  'A newspaper about machine learning.',  'Cats are lovely,while dogs are not.',  'Reading books about machine learning,with a cat at hand.'],这是一个包括五篇文献的文档集。
    关键代码展示如下:其具体内容和其余实验代码以及输出结果可参考博客代码内容(代码展示效果不好)或附件text.py。
    # 综合了去除低频词、去除停用词、词干提取、tfidf的文档向量构建函数,只需传入原始文档即可
    def tfidf_stem_stop_words_vector(text_data):
    # 利用sklearn提供的TfidfVectorizer构造词向量提取器,这个类在上述函数中用到
    class StemmedTfidfVectorizer(TfidfVectorizer):
   
代码文件text.py内容:   
#coding: UTF-8
#encoding: UTF-8
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.feature_extraction.text import TfidfVectorizer
import numpy as np
import nltk.stem as ns


def get_simple_data():
    text_data = ['This is a book about machine learning.',
                 'It\'s a cat classified by manual labeling.',
                 'A newspaper about machine learning.',
                 'Cats are lovely,while dogs are not.',
                 'Reading books about machine learning,with a cat at hand.']
    return text_data
# 先不做任何处理,只是简单对文档进行分词
def simple_text_preprocess(text_data):
    vectorizer = CountVectorizer(min_df=1)                 # min_df代指单词在所有文档中出现的频率小于min_df的都被过滤掉;如果是分数,则按频率计算
    print(vectorizer)
    words_vector = vectorizer.fit_transform(text_data)     # 在文本集中进行提取词向量
    words_feature_names = vectorizer.get_feature_names()   # 得到选取的特征
    print('feature_names:',words_feature_names)
    print('words_vector:',words_vector.toarray())          # 输出词向量,不用toarray()则输出稀疏矩阵;有toarray()则输出完整矩阵
    
    new_text = ['Machine learning is hard to learn for a cat.',
                 'Cat is lazy.']
    new_words_vector = vectorizer.transform(new_text)      # 对新的文本数据进行转换
    print('new_text_words_vector:',new_words_vector.toarray())
# 去除停用词进行分词
def stop_words_text_preprocess(text_data):    
    # 去除停用词之后再进行以便操作
    vectorizer = CountVectorizer(min_df=1,stop_words='english')   # 简单加入"stop_words"即可
    words_vector = vectorizer.fit_transform(text_data)     # 在文本集中进行提取词向量
    words_feature_names = vectorizer.get_feature_names()   # 得到选取的特征
    print('remove_stopwords,feature_names:',words_feature_names)
    print('remove_stopwords,words_vector:',words_vector.toarray())          # 输出词向量,不用toarray()则输出稀疏矩阵;有toarray()则输出完整矩阵
    
    new_text = ['Machine learning is hard to learn for a cat.',
                 'Cat is lazy.']
    new_words_vector = vectorizer.transform(new_text)      # 对新的文本数据进行转换
    print('remove_stopwords,new_text_words_vector:',new_words_vector.toarray())
# 再加上提取词干
def stem_stop_text_preprocess(text_data):
    # stemming提取词干
    st = ns.SnowballStemmer('english')    # 构造提取器
    print('imaging->',st.stem('imaging'),'machine->',st.stem('machine'),'learning->',st.stem('learning'))
    
    # 根据自己构造的StemmedCountVectorizer进行对文本集提取词干
    vectorizer = StemmedCountVectorizer(min_df=1,stop_words='english')
    words_vector = vectorizer.fit_transform(text_data)     # 在文本集中进行提取词向量
    words_feature_names = vectorizer.get_feature_names()   # 得到选取的特征
    print('remove_stopwords,feature_names:',words_feature_names)
    print('remove_stopwords,words_vector:',words_vector)          # 输出词向量,不用toarray()则输出稀疏矩阵;有toarray()则输出完整矩阵
                                
    new_text = ['Machine learning is hard to learn for a cat.',
                 'Cat is lazy.']
    new_words_vector = vectorizer.transform(new_text)      # 对新的文本数据进行转换
    print('remove_stopwords,new_text_words_vector:',new_words_vector)
# 去除停用词的词向量提取器
class StemmedCountVectorizer(CountVectorizer):
    def build_analyzer(self):
        english_stemmer = ns.SnowballStemmer('english')
        analyzer = super(StemmedCountVectorizer,self).build_analyzer()
        return lambda doc: (english_stemmer.stem(w) for w in analyzer(doc))

# 自己实现TFIDF,输入参数为某个要求tfidf的单词,其所在的文档,所有文档集合
def tfidf(term,doc,corpus):
    tf = doc.count(term)/len(doc)                    # 文档频率,单词在其所属文档中出现的频率
    num_docs_with_term = len([d for d in corpus if term in d]) # 包含这个单词的文档总数
    idf = np.log(len(corpus)/num_docs_with_term)     # 文档逆频率,总的文档数除以包含这个单词的文档总数,再取对数
    return tf*idf     
# 测试自己实现的tfidf
def test_tfidf():
    doc = ['cat','cat','dog','dog','machin','learn']
    corpus = [['cat','machin','learn'],
              ['machin','learn'],
              ['cat','learn'],
              ['dog','machin','learn'],
              ['cat','cat','dog','dog','machin','learn']]
    for term in set(doc):
        print('term,tfidf:',term,tfidf(term,doc,corpus))
# 再加入tfidf进行处理
def tfidf_stem_stop_words_vector(text_data):
    # stemming提取词干
    st = ns.SnowballStemmer('english')    # 构造提取器
    print('imaging->',st.stem('imaging'),'machine->',st.stem('machine'),'learning->',st.stem('learning'))
    
    # 根据自己构造的StemmedTfidfVectorizer构造tfidf词向量
    vectorizer = StemmedTfidfVectorizer(min_df=1,stop_words='english',decode_error='ignore') # 忽略编码错误
    words_vector = vectorizer.fit_transform(text_data)     # 在文本集中进行提取词向量
    words_feature_names = vectorizer.get_feature_names()   # 得到选取的特征
    print('remove_stopwords,feature_names:',words_feature_names)
    print('remove_stopwords,words_vector:',words_vector)          # 输出词向量,不用toarray()则输出稀疏矩阵;有toarray()则输出完整矩阵
                                
    new_text = ['Machine learning is hard to learn for a cat.',
                 'Cat is lazy.']
    new_words_vector = vectorizer.transform(new_text)      # 对新的文本数据进行转换
    print('remove_stopwords,new_text_words_vector:',new_words_vector)
# 利用sklearn提供的TfidfVectorizer构造词向量提取器
class StemmedTfidfVectorizer(TfidfVectorizer):
    def build_analyzer(self):
        english_stemmer = ns.SnowballStemmer('english')
        analyzer = super(TfidfVectorizer,self).build_analyzer()
        return lambda doc: (english_stemmer.stem(w) for w in analyzer(doc))

# 简单计算欧氏距离
def dist_raw(v1,v2):
    delta = v1 - v2
    return np.linalg.norm(delta.toarray())


if __name__ == "__main__":
    text_data_1 = get_simple_data()
    #simple_text_preprocess(text_data_1)
    #stop_words_text_preprocess(text_data_1)
    #stem_stop_text_preprocess(text_data_1)
    #test_tfidf()
    tfidf_stem_stop_words_vector(text_data_1)
  
    代码文件到此结束,下面是实例输出结果:
'''
    text_preprocess(text_data_1)输出结果:
    
    CountVectorizer的详细用法:
        analyzer是表示基于word进行分词、并且以token_pattern为正则进行分词这里的u'(?u)\\b\\w\\w+\\b'
        stop_words指是否使用停用词
        lowercase是先将所有变成小写
        
    CountVectorizer(analyzer=u'word', binary=False, decode_error=u'strict',
        dtype=<type 'numpy.int64'>, encoding=u'utf-8', input=u'content',
        lowercase=True, max_df=1.0, max_features=None, min_df=1,
        ngram_range=(1, 1), preprocessor=None, stop_words=None,
        strip_accents=None, token_pattern=u'(?u)\\b\\w\\w+\\b',
        tokenizer=None, vocabulary=None)
    ('feature_names:', [u'about', u'are', u'at', u'book', u'books', u'by', u'cat', u'cats', u'classified', u'dogs', u'hand', u'is', u'it', u'labeling', u'learning', u'lovely', u'machine', u'manual', u'newspaper', u'not', u'reading', u'this', u'while', u'with'])
    ('words_vector:', array([[1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1,
        0, 0],
       [0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0,
        0, 0],
       [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0,
        0, 0],
       [0, 2, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0,
        1, 0],
       [1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0,
        0, 1]], dtype=int64))
    ('new_text_words_vector:', array([[0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0,
        0, 0],
       [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0]], dtype=int64))
    
    stop_words_text_preprocess(text_data_1)输出结果:
    ('remove_stopwords,feature_names:', [u'book', u'books', u'cat', u'cats', u'classified', u'dogs', u'hand', u'labeling', u'learning', u'lovely', u'machine', u'manual', u'newspaper', u'reading'])
    ('remove_stopwords,words_vector:', array([[1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0],
       [0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0],
       [0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0],
       [0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0],
       [0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1]], dtype=int64))
    ('remove_stopwords,new_text_words_vector:', array([[0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0],
       [0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]], dtype=int64))
    
    stem_stop_text_preprocess(text_data_1)输出结果:
    imaging-> imag machine-> machin learning-> learn
    remove_stopwords,feature_names: ['book', 'cat', 'classifi', 'dog', 'hand', 'label', 'learn', 'love', 'machin', 'manual', 'newspap', 'read']
    remove_stopwords,words_vector:   (0, 6) 1
      (0, 8)        1
      (0, 0)        1
      (1, 5)        1
      (1, 9)        1
      (1, 2)        1
      (1, 1)        1
      (2, 10)       1
      (2, 6)        1
      (2, 8)        1
      (3, 3)        1
      (3, 7)        1
      (3, 1)        1
      (4, 4)        1
      (4, 11)       1
      (4, 1)        1
      (4, 6)        1
      (4, 8)        1
      (4, 0)        1
    remove_stopwords,new_text_words_vector:   (0, 1)        1
      (0, 6)        2
      (0, 8)        1
      (1, 1)        1
    
    text_tfidf()输出结果:
    term,tfidf: learn 0.0
    term,tfidf: machin 0.0371905918857
    term,tfidf: cat 0.170275207922
    term,tfidf: dog 0.305430243958
    
    tfidf_stem_stop_words_vector(text_data_1)输出结果:
    imaging-> imag machine-> machin learning-> learn
    remove_stopwords,feature_names: ['book', 'cat', 'classifi', 'dog', 'hand', 'label', 'learn', 'love', 'machin', 'manual', 'newspap', 'read']
    remove_stopwords,words_vector:   (0, 0) 0.648462625687
      (0, 8)        0.538282557346
      (0, 6)        0.538282557346
      (1, 1)        0.36063832635
      (1, 2)        0.538497910106
      (1, 9)        0.538497910106
      (1, 5)        0.538497910106
      (2, 8)        0.486240416592
      (2, 6)        0.486240416592
      (2, 10)       0.726044430146
      (3, 1)        0.427992922683
      (3, 7)        0.639070441396
      (3, 3)        0.639070441396
      (4, 0)        0.40357561577
      (4, 8)        0.335004217566
      (4, 6)        0.335004217566
      (4, 1)        0.335004217566
      (4, 11)       0.500221573402
      (4, 4)        0.500221573402
    remove_stopwords,new_text_words_vector:   (0, 8)        0.408248290464
      (0, 6)        0.816496580928
      (0, 1)        0.408248290464
      (1, 1)        1.0
'''

 

矩阵分解(一):奇异值分解

李新春 发表了文章 • 2 个评论 • 120 次浏览 • 2017-04-29 12:40 • 来自相关话题

    由于涉及到大量数学公式,用Latex生成pdf文件,这里贴出pdf转换出来的png图片。附件里面有完整的pdf和代码文件。



















  pdf里面并没有贴出代码,这里贴出源文件的代码,代码很简单,只是简单地对svd进行了测试。下面是代码文件和输出结果:
  svd.py文件:
import numpy as np
import time
# 利用numpy包自带的svd实现,第二个参数表示是否打印出矩阵
def np_svd(matrix,printInfo=True):
    print('np_svd:')
    start = time.clock()
    u,sigma,v = np.linalg.svd(matrix)
    end = time.clock()
    print('shape:',matrix.shape,'=',u.shape,'*',sigma.shape,'*',v.shape)
    print('time:',end-start)
    if(printInfo):
        print(matrix)
        print(u)
        print(sigma)
        print(v)
if __name__ == "__main__":
    # 测试矩阵秩为行满秩或列满秩的情况
    a = np.array([[-1,3,4],
                  [2,-5,8],
                  [-3,-7,-2],
                  [2,4,-3]])
    np_svd(a)
    
    # 测试秩小于行数和列数的矩阵
    b = np.array([[-1,3,4],
                  [2,-5,8],
                  [-2,6,8],
                  [0,1,16]])
    np_svd(b)
    
    # 测试矩阵分解的时间
    for ex in range(1,4):
        m = 3 * 10 ** ex         # 3乘以10的ex次方
        n = 4 * 10 ** ex         # 4乘以10的ex次方
        matrix = np.random.normal(size=(m,n))  # 正态分布
        np_svd(matrix,False)
    测试结果:       
'''
# 满秩情况下的测试:输入矩阵为4*3
np_svd:
shape: (4, 3) = (4, 4) * (3,) * (3, 3)
time: 0.001563813577831752
[[-1  3  4]
 [ 2 -5  8]
 [-3 -7 -2]
 [ 2  4 -3]]
[[ 0.03492724  0.50564699 -0.74831887  0.42792532]
 [ 0.80692855  0.38784734  0.40536499  0.18471597]
 [ 0.37135366 -0.7637849  -0.22588836  0.47718292]
 [-0.45797693  0.10260697  0.47399636  0.74502107]]
[ 11.06047807   8.73915881   3.36049521]
[[-0.0407835  -0.75595687  0.65334977]
 [ 0.31657696  0.61042791  0.72605564]
 [ 0.94768968 -0.23644657 -0.21442314]]
# 不满秩的分解,可以看出sigma矩阵[  2.00999029e+01   8.71744817e+00   2.11044410e-16](由于是对角矩阵,采用向量存储),可以看出第三个奇异值已经趋于零了,可以说就是零
np_svd:
shape: (4, 3) = (4, 4) * (3,) * (3, 3)
time: 0.0001338945396582858
[[-1  3  4]
 [ 2 -5  8]
 [-2  6  8]
 [ 0  1 16]]
[[ 0.21486784  0.31094848  0.90774033 -0.18207238]
 [ 0.3668635  -0.71292939  0.03774797 -0.59642095]
 [ 0.42973567  0.62189696 -0.41612219 -0.50538476]
 [ 0.79659917 -0.09103243 -0.03774797  0.59642095]]
[  2.00999029e+01   8.71744817e+00   2.11044410e-16]
[[-0.01694596  0.10872188  0.99392776]
 [-0.34191212  0.93351191 -0.10794265]
 [-0.93957913 -0.34166514  0.02135407]]
# 测试30*40 300*400 3000*4000 30000*40000矩阵的分解时间(s),分别为0.0011336715375591666、 0.03374235704779949、37.49550263636945。可见3000*4000已经用了半分钟,当测试30000*40000时,计算机全卡了,结果等了大概五分钟没有出结果,所以直接强制关机。可见矩阵分解操作计算了特别大。
np_svd:
shape: (30, 40) = (30, 30) * (30,) * (40, 40)
time: 0.0011336715375591666
np_svd:
shape: (300, 400) = (300, 300) * (300,) * (400, 400)
time: 0.03374235704779949
np_svd:
shape: (3000, 4000) = (3000, 3000) * (3000,) * (4000, 4000)
time: 37.49550263636945
'''

  查看全部
    由于涉及到大量数学公式,用Latex生成pdf文件,这里贴出pdf转换出来的png图片。附件里面有完整的pdf和代码文件。
奇异值分解1.png


奇异值分解2.png


奇异值分解3.png


奇异值分解4.png

  pdf里面并没有贴出代码,这里贴出源文件的代码,代码很简单,只是简单地对svd进行了测试。下面是代码文件和输出结果:
  svd.py文件:
import numpy as np
import time
# 利用numpy包自带的svd实现,第二个参数表示是否打印出矩阵
def np_svd(matrix,printInfo=True):
    print('np_svd:')
    start = time.clock()
    u,sigma,v = np.linalg.svd(matrix)
    end = time.clock()
    print('shape:',matrix.shape,'=',u.shape,'*',sigma.shape,'*',v.shape)
    print('time:',end-start)
    if(printInfo):
        print(matrix)
        print(u)
        print(sigma)
        print(v)
if __name__ == "__main__":
    # 测试矩阵秩为行满秩或列满秩的情况
    a = np.array([[-1,3,4],
                  [2,-5,8],
                  [-3,-7,-2],
                  [2,4,-3]])
    np_svd(a)
    
    # 测试秩小于行数和列数的矩阵
    b = np.array([[-1,3,4],
                  [2,-5,8],
                  [-2,6,8],
                  [0,1,16]])
    np_svd(b)
    
    # 测试矩阵分解的时间
    for ex in range(1,4):
        m = 3 * 10 ** ex         # 3乘以10的ex次方
        n = 4 * 10 ** ex         # 4乘以10的ex次方
        matrix = np.random.normal(size=(m,n))  # 正态分布
        np_svd(matrix,False)
    测试结果:       
'''
# 满秩情况下的测试:输入矩阵为4*3
np_svd:
shape: (4, 3) = (4, 4) * (3,) * (3, 3)
time: 0.001563813577831752
[[-1  3  4]
 [ 2 -5  8]
 [-3 -7 -2]
 [ 2  4 -3]]
[[ 0.03492724  0.50564699 -0.74831887  0.42792532]
 [ 0.80692855  0.38784734  0.40536499  0.18471597]
 [ 0.37135366 -0.7637849  -0.22588836  0.47718292]
 [-0.45797693  0.10260697  0.47399636  0.74502107]]
[ 11.06047807   8.73915881   3.36049521]
[[-0.0407835  -0.75595687  0.65334977]
 [ 0.31657696  0.61042791  0.72605564]
 [ 0.94768968 -0.23644657 -0.21442314]]
# 不满秩的分解,可以看出sigma矩阵[  2.00999029e+01   8.71744817e+00   2.11044410e-16](由于是对角矩阵,采用向量存储),可以看出第三个奇异值已经趋于零了,可以说就是零
np_svd:
shape: (4, 3) = (4, 4) * (3,) * (3, 3)
time: 0.0001338945396582858
[[-1  3  4]
 [ 2 -5  8]
 [-2  6  8]
 [ 0  1 16]]
[[ 0.21486784  0.31094848  0.90774033 -0.18207238]
 [ 0.3668635  -0.71292939  0.03774797 -0.59642095]
 [ 0.42973567  0.62189696 -0.41612219 -0.50538476]
 [ 0.79659917 -0.09103243 -0.03774797  0.59642095]]
[  2.00999029e+01   8.71744817e+00   2.11044410e-16]
[[-0.01694596  0.10872188  0.99392776]
 [-0.34191212  0.93351191 -0.10794265]
 [-0.93957913 -0.34166514  0.02135407]]
# 测试30*40 300*400 3000*4000 30000*40000矩阵的分解时间(s),分别为0.0011336715375591666、 0.03374235704779949、37.49550263636945。可见3000*4000已经用了半分钟,当测试30000*40000时,计算机全卡了,结果等了大概五分钟没有出结果,所以直接强制关机。可见矩阵分解操作计算了特别大。
np_svd:
shape: (30, 40) = (30, 30) * (30,) * (40, 40)
time: 0.0011336715375591666
np_svd:
shape: (300, 400) = (300, 300) * (300,) * (400, 400)
time: 0.03374235704779949
np_svd:
shape: (3000, 4000) = (3000, 3000) * (3000,) * (4000, 4000)
time: 37.49550263636945
'''

 

[转载]降维方法t-SNE

王开新 发表了文章 • 0 个评论 • 104 次浏览 • 2017-04-16 20:43 • 来自相关话题

http://lvdmaaten.github.io/tsne/
 
第一眼就被MNIST上的效果震撼住了 查看全部
http://lvdmaaten.github.io/tsne/
 
第一眼就被MNIST上的效果震撼住了