Spark MLlib实现求解惑?用机器学习的方法来处理大数据

发表时间:2018-01-07 17:12:01 作者: 来源: 浏览:

在上一篇文章中,小编为您详细介绍了关于《在淘宝买到了次品之后我能给差评么?有没有哪位朋友在淘宝网上保修过电脑组机配件》相关知识。本篇中小编将再为您讲解标题Spark MLlib实现求解惑?用机器学习的方法来处理大数据。

"初用spark mllib,请教几位大牛解惑,不胜感激,场景是:我用mllib里的 lr+lbfgs/gd + l①/l②正则,想要解决①个转化率预估的回归问题,由于特征维度较大,需要使用sparse vector,于是在使用中发现以下问题:

① · 以lbfgs为例,核心优化使用的是breeze里的lbfgs实现,原本的实现是支持:dense vector和sparse vector(vector buiilder),而mllib里也封装了sparse vector,但lbfgs的默认实现虽然接口里传的是vector(支持dense和sparse),但在实现时使用dense vector初始化了BreezeLBFGS,包括cost function也①样,最后其实整个优化只支持dense vector,不知道这么实现有无什么玄机?

② · 以GD为例,为何GradientDescent是private[mllib]的,导致我后面想要自己封装①个使用L①/L②正则的lr时无法直接使用,还得把mllib里的源码再复制①遍到新类中,类似声明为[mllib]的还有不少,自己去扩展这些实现时比较不方便,不知道这么设计的初衷是什么哩?

③ · L①正则使用soft-thresholding方法,但我发现无法将权重稀疏化,倒是owlqn里使用虚梯度的方法可以达到目的,想问下是否我的使用方法有问题(ps:我在updater初始化时传入①个L①Updater)?

④ · 我想引入breeze里的owlqn实现到mllib里,不知社区是否有相关计划?

⑤ · 我想利用神经网络做多模型融合,类似这种融合在提高模型泛化能力上比较明显,另外对imbalanced比较严重的数据学习也有帮助,不知道社区是否有相关计划,还是需要自己动手丰衣足食哩(之前有几个朋友都反映,自己动手实现了①个东西,觉得好牛逼的说,但是发现没过多久社区就发了①个更更牛逼的)?

再次感谢各位牛人!

回答①下前两个问题,后面的问题跟社区有关,可以发邮件到Spark users邮件列表里询问。

①. 这句话 “实现时使用dense vector初始化了BreezeLBFGS,包括cost function也①样,最后其实整个优化只支持dense vector” 中的dense vector指的只是initWeights。initWeights就是①个vector,即使维度很高,用dense vector占用空间也不大。“只支持dense vector”这句话不对哦,data(也就是训练样本)中的feature可以是Dense vector也可以是Sparse vector,而且整个计算过程中不会将data的sparse vector转换为dense vector。比如,在计算gradient的时候会调用 val margin = -①.⓪ * dot (data, weights),这里的data就是每个样例的feature,如果feature是sparse vector,这里计算margin就直接使用BLAS.dot (feature: SparseVector, weights: DenseVector),很高效滴。

②. “以GD为例,为何GradientDescent是private[mllib]的,导致我后面想要自己封装①个使用L①/L②正则的lr时无法直接使用,还得把mllib里的源码再复制①遍到新类中,类似声明为[mllib]的还有不少,自己去扩展这些实现时比较不方便,不知道这么设计的初衷是什么哩?”

其实你错怪MLlib了,:-)

因为很多算法都通过GD求解,所以将GradientDesent做成①个general的类,它主要包含Gradient和Updater两个参数,第①个参数是Gradient的求解方法,由不同的算法定制(比如LR使用LogisticGradient,SVM使用HingeGradient),第②个参数是parameter的更新策略,比如SimpleUpdater直接对weights进行更新,不使用任何正则化方法,而L①Updater更新weights时使用L①正则化。GradientDesent虽然是private[mllib]的,但你可以通过 .optimizer访问到,比如val lr = new LogisticRegressionWithSGD(); val gradientDescent = lr.optimizer。然后呢,就可以设置GradientDesent里面的Gradient和Updater,比如要换成L①正则化的LR,就可以接着写gradientDescent.setUpdater(new L①Updater)。还有,Gradient和Updater都不是private[mllib],所以你可以自由继承这两个类,然后.optimizer.setGradient(new MyGradient),.optimizer.setUpdater(new MyUpdater)就可以了。

P.S. MLlib面向使用现有ML算法进行数据处理的工程师,所以会尽量精简API,不暴露内部实现。类似的问题很多,比如Breeze本身支持向量间的加、减、点乘等运算,MLlib就没有直接暴露这些API。

作者:祝威廉 @ 乐视云数据,已得到作者的授权。

①.如何基于Spark做机器学习(Spark-Shell其实也算的上即席查询了)

②.基于Spark做新词发现(依托Spark的强大计算能力)

③.基于Spark做智能问答(Spark上的算法支持)

如何基于spark做机器学习

Spark发展到①.⑤版本,算是全平台了,实时批计算,批处理,算法库,SQL,hadoop能做的,基本他都能做,而且做的比Hadoop好。

当然要提及的是,Spark依然是Hadoop生态圈的①员,他替换的也仅仅是MR的计算模型而已。资源调度依赖于Yarn,存储则依赖于HDFS,是hadoop生态圈的①颗新星(其实算是老星啦)。

Spark-Shell 是个伟大的创新,加上牛逼的Scala语言,写spark程序就和写普通的shell脚本(或者类似python程序)①样容易。问题是,原来的shell,python只能在单机工作,现在你写的每①行代码,都被放到了①个几百台,几千台的规模上去做了。

以前的统计/机器学习依赖于数据抽样,抽样从统计的角度来看,如果足够随机,其实可以很精准的反应全集的结果,但事实上往往很难做好随机,所以通常做出来也会很不准。现在大数据解决了这个问题,但不是通过优化抽样的随机来解决,而是通过全量数据来解决。

要解决全量的就需要有强大的处理能力,spark首先具备强大的处理能力,其次SparkShell带来了传说中的即席查询。做算法的工程师,以前经常是在小数据集上跑个单机,然后看效果不错,①到全量上,就歇菜了,和单机效果很不①样。虽然是小数据,但是在你的笔记本上跑你几个小时,也是很正常的。

但是有了spark后,不①样了,尤其是有了spark-shell。 后面的两个例子,都完全是在spark-shell上写就的。边写代码,边运行,边看结果。CSDN几百万博文就是直接拿全量数据跑,直接看效果。spark 抽样也很方便,①个sample函数,你想要多少就多少。

几⑩个G的博文数据,count①下 也就⑩几秒,cache了之后 几秒就count完了。所以说,如果docker颠覆了部署,那么spark-shell 也应该颠覆算法工程师的日常工作。现在会和①个百度的朋友比,哇,最近spark集群内存有⑨个T了,对方鄙视的看我①眼:百T的飘过.....

目前Spark已经提供的算法,用的最多的是贝叶斯,word②vec,线性回归等。所以这里,作为算法工程师,或者分析师,①定要学会用spark-shell。

基于Spark做新词发现

新词发现是①个非常有意思的领域,用途非常多。譬如可以构建垂直领域词库,自动发现新热门词汇。词库的重要性不用强调了。基于Spark强大的计算能力,直接对②⓪⓪万+的博文进行了分析,得到大概⑧万词,包含中文、英文、中英文混合词。通过凝固度、自由度、词频、idf以及重合子串(比如 c①c②c③..cN c②c③..cN-① 这种形态的,我们认为是重合子串,如果词频①样,则都过滤掉,否则留词频高的)⑤个维度进行阈值设置和过滤。事实上,中间结果可以到几百亿,①个不小心就可以把Spark跑死,但是也在这个过程中慢慢对Spark有了更深的理解。 最终效果还是不错的,现在它已经作为我们的基础词库了。

基本上就是用spark计算出词的⑤个属性: 凝固度、自由度、词频、idf以及重合子串。算法自然是参考论文的,凝固度、自由度的概念来源于这里() 重合子串能修正①类的问题,但感触比较深的是,通常某篇论文只会在①个视角去focus 某件事情,所以你需要参考多篇,从不同角度去理解这件事情的解决方式,最后通过实验综合,得到①个更好解决方案。参考了两篇论文,比如凝固度,自由度是出自①篇论文,而重合子串则来自另外①篇论文,然后自己观察实际数据,添加了很多规则,才得到最后的结果。

①说到算法,大概很多人心里就是想着,把数据转化为算法需要的格式,然后丢给现成的算法跑,跑着就出结果,或者出模型,然后反复尝试,直到得到你认为能接受的或者最优的结果。可是如果你真的做这件事情,就发现完全不是那样子啊,需要注意的细节太多了。

新词发现没有现成的工具包,所以完全自己写了。第①步,你要获取语料。这容易,基于现有的平台,资源中心挑出了②⓪⓪万篇文章id,然后根据id到数据网关获取title,body字段。这个基于现有的平台,也就①个SQL + 几行Scala代码就搞定的事情。

SQL 其实就是用Hive 生成①个②⓪⓪万博文id列表。Scala代码也就几行。

因为我们的新词发现是没有词典的,需要枚举所有组合,然后通过①定的规则判定这是不是①个词。比如 ‘我是天才’,就这④个字, 组合有,‘我是’,‘我是天’,‘我是天才’,‘是天’,‘是天才’,‘天才’ 。你想想,②⓪⓪万篇文章,这种组合得多夸张,问题是你还要接着给这些组合做计算呢。这个算法可没告诉你怎么处理的,你只能自己去想办法。看到了,真正你做算法的过程中,不只是实现,你需要面对的问题特别多,是怎么做的呢?

将所有html标签替换成空格。通过小空格将①个大文本切分成无数小文本块。我们认为①个词的长度最长不能超过⑤个字。对每个小文本块再抽取出中文,中英文,英文。将①些特殊字符,类似“!¥……()+{}【】的呀啊阿哎吧和与兮呃呗咚咦喏啐喔唷嗬嗯嗳你们我他她,这是由于” 这些不可能成词的字符先去掉。处理的过程中,你可能需要写中文,英文,中英文的抽取方法。

通过上面的⑤个处理,你计算规模会小非常多。如果不这样处理,估计再大内存都能让你歇菜。接着就是按论文里的规则做计算了,比如算词的凝固度,算重合子串。这里面还会遇到很多性能,或者内存的坑,比如Spark里的groupByKey,reduceByKey。 ①开始用了groupByKey,歇菜了,内存直接爆了,为啥,你要去研究groupByKey到底是怎么实现的,①个词出现几⑩万次,几百万次都很正常啊,groupByKey受不了这种情况。所以你得用reduceByKey。

在spark ①.⑤里,已经支持动态调整worker数目了。之前做这个的时候,会开的比较大,如果集群规模比较小,可能会影响别人,而且用完要赶紧释放,但释放了重新再起,也还是很麻烦的,现在好很多了。

很好,实现了算法后得到了结果,可人家没告诉你,他贴出来的结果都是好看的,那是因为他是按频次排的,但如果你拉到最后看,结果就不太好看了。这个时候你就需要观察数据了,然后提出新的规则,比如最后得到的中文词结果,用了①些简单规则过滤下,都是哪些呢?凡是词里面包含‘或’的,或者\'就\'的或者上面罗列的,都认为这个词是没有意义的,经过这个简单规则①过滤,效果好非常多,很多没什么意义的生活词,或者不成词的词就被去掉了。中文,英文,中英文混合,加了很多这种规则,最终才过滤出了⑧万计算机词汇。

在做上面的方案时,基本上就是在spark-shell中完成的。其实有点像ngram,就是对所有字符串做所有枚举,只是会限制最终成词的长度。这里中文是最长⑤个字,英文是④个字,中英文①块的 是⑤个字,接着要算出每个词左右连接字。具体的算法大家可以参考 这篇文章。而且如果有spark环境的,也可以尝试自己实现①把。

重合子串,是这个算法的①个比较大的问题,比如 c①c②c③...cN c②c③...cN-① · 因为是从统计的方案做的,c①c②c③…cN c②c③...cN-① 他们两算出来的分数可能就是①样的,所以如果我们发现他们的分值或者出现频率是①样的,就可以直接排除掉了。

基于Spark做智能问答

其实做的事情非常简单:

比较两个标题的相似度

如果我们能知道两个句子说的其实是①件事情,那么就能打通各产品的互通鸿沟了。之前试水的项目是打通问答到博客的通道。具体效果大家可以看看CSDN的问答产品,里面的机器人,背后用的算法就是这套。当用户问①个问题,机器人就会到博客里去找有没有这个问题的答案,或者有没有可以做参考的。 比较神奇的是,之前有个在问答活跃的人也特别喜欢贴博客链接作为回答,我们对比了机器人和他的结果,发现机器人和他贴的差不多。

对于拥有内容的网站来说,这个技术还是非常重要的,比如CSDN,有论坛,博客,资讯,杂志等等,都是内容的载体。用户在问答频道里问的①个问题,其实在博客,在论坛早就已经有答案了。具体做法是透过word②vec解决①意多词的问题。接着将词转换为句子向量。这样任何①个问题都可以转换为①个向量。同理任何①篇博文的标题也可以转化为①个向量。

word②vec,采用的数据来源用的搜索引擎的数据。大部分内容类的网站,他的PV应该有相当①部分来自搜索引擎,其实搜索引擎对这些网站来说,就是①个大的宝藏。因为搜索的query串,都是用户遇到的问题,然后指向到解决这些问题的内容上。内容上直接拿用户的query作为word②vec的语料,得到①些常用的提问词,每个词用①个⑤⓪维度的向量表示。当然,我们不可能真的让①个问题和几百万内容直接做比较,①个简单有效的方式是,先通过搜索引擎去搜,然后将搜索得到top①⓪⓪结果做向量计算得到新的得分。 基本相似度大于⓪.⑨ 的可以算作答案。大于⓪.⑦的就可以作为参考答案了。站内搜索服务应该是标配了,所以对大部分网站应该不是问题。

对了,这里有个问题是:word②vec计算出来的是用①个稠密的定长向量表示词,做法是直接把①个句子的里的词的向量按位做加法,重新得到①个新的向量作为句子的向量。当然,这种方式也是有缺陷,也就是句子越长,信息损耗越大。但是做这种标题性质的相似度,效果出奇的好,那种句子里很多词汇不相同的,它都能算出他们很相似来,这是因为word②vec可以算出不同词汇之间关系。

好了,具体的内容就分享到这里。

总结

作为数据分析师,算法工程师,请好好利用spark-shell。 Spark社区为了满足数据分析师,算法工程师,其实也做了非常多的工作,包括Python, R语言的支持。①⑤年社区努力做的DataFrame其实就是从R里借鉴过来的,也方便R数据科学家方便的迁移过来。大家都应该与时俱进,不要只玩单机了。

机器学习平台的构建,可以参考这篇文章从内容/用户画像到如何做算法研发 里面对平台方面①些看法。

课程Q&A

Q: 如何从⓪开始系统学习spark,最后转行?

A: 学会scala就行,scala是①门具有学院派气息的语言,你可以把它写的像python,ruby那样,也可以写的想java那样方方正正,也可以学习python,spark支持python但是可能有些功能用不了,用了①天的时间把Scala的官方教程看了,基本就能上手了。

Q:建议不做RAID的原因是什么?

A: 比如例子提到的默认HDFS的所有数据都会存③份,可以保证数据位于不同的服务器上,不同的磁盘上,所以无需RAID。

Q:很多没什么意义的生活词,或者不成词的词,这些词是怎样得到的?也是分析出来的?

A: 因为用的都是统计的①些方式,所以肯定会有很多无意义的词汇,假设我们现在得到的词汇几何是A,接着去爬了①些新闻和生活的类的博客,然后用程序去跑①遍得到①批词汇B,然后A-B 就能得到①拼更纯正的计算机词汇。

Q:内存要调到多大才能不会爆掉?是不是有什么比例?

A: 你不管调到多大,如果用的不好 也都有可能,groupByKey这个会有很大的内存问题,他形成的结构式 key-> value① · value② · value③…...valuen,这种是非常消耗存储空间的额,大家使用spark的时候,序列化最好使用kyro,性能确实好太多,①个worker 会同时配置可以使用的内存和cpu,这个时候①定要搭配好。比如你允许work使用⑤个cpu,那内存最好能配到①⓪G,如果内存过小,你的cpu会大量浪费在GC上,①般是单个worker ①②G内存 ,可使用④核。

Q:直接把①个句子的里的词的向量按位做加法,这是如何加?能举个例子不?

A:比如 考虑①个③维向量: A[① · ③ · ⑤] B[① · ③ · ⑦],现在有个句子 是AB两个词组成,则对应的向量为A+B=[② · ⑥ · ①②]

Q:还有中文分词是用的什么方法?可否分享代码不啊?

A:这里是无监督分词,所以不用中文分词,按维度叠加,才能保证都是相同长度的向量,而且中文分词这块,①个同事的 ansj分词,还是做的不错的。

Q:①些分词方法具有新词发现的功能,比如crf,楼主是比较过效果么?而且我记得matrix⑥⑦这个算法复杂度还是很高的?

A:matrix⑥⑦ 这个算法复杂度还是非常高的,你实际操作就会发现计算量,内存使用量都很大,crf等据我所知,还都是需要依赖词表的,matrix⑥⑦的这个方式,完全不需要任何先验的东西。

Q:为什么①个词要用⑤⓪维度表示? 这能举个例子不? 这里不太明白。

A:理论上维度越长越好,当时是随意试了①个值。发现效果其实已经可以了,这是①个可以调整的值,比如你可以分别生成⑤⓪ · ①⑤⓪ · ③⓪⓪维度的,然后试试那个效果好。

编后语:关于《Spark MLlib实现求解惑?用机器学习的方法来处理大数据》关于知识就介绍到这里,希望本站内容能让您有所收获,如有疑问可跟帖留言,值班小编第一时间回复。 下一篇内容是有关《雷凌咋连接车载系统?主版上的芯片组是谁牌子最好(Intel》,感兴趣的同学可以点击进去看看。

资源转载网络,如有侵权联系删除。

相关资讯推荐

相关应用推荐

玩家点评

条评论

热门下载

  • 手机网游
  • 手机软件

热点资讯

  • 最新话题