MLlib分类算法实战演练--Spark学习(机器学习)

因为自身原因最近再学习Spark MLlib,看的教材是《Spark机器学习》,感觉这本书偏入门并且有很多实操,非常适合新手。下面就是我在学习到第五章关于分类算法的一些要点,最要是通过代码实操,具体算法原理就不介绍。

一、数据来源及开发环境

开发环境:为了方便代码管理这里使用了IDEA集成开发环境,单机进行代码调试感觉很方便嘛,主要环境与我前两篇博客中部署的环境一致。
数据源:机器学习实在中数据的获取很重要,互联网上要找到类似数据非常容易。本实例使用的是Kaggle竞赛数据(相信学习机器学习的都知道这个比赛)。数据是关于网站点击数据,主要用于推荐的页面是短暂流行还是长久流行。下载地址,下载train.tsv的文件,需要注册才能下载。

二、数据预处理

大家下载好数据以后可以通过相应的工具打开看看数据构成。由于数据中第一行为列名,在算法中是用不到的,因此将其删除并存为train_noheader.tsv,linux命令如下:
[html]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. sed 1d train.tsv >train_noheader.tsv  


三、代码解析

使用IDEA新建一个Scala class,键入如下代码:

[html]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. /导入各种类  
  2. import org.apache.spark.mllib.classification.LogisticRegressionWithSGD  
  3. import org.apache.spark.mllib.linalg.Vectors  
  4. import org.apache.spark.mllib.regression.LabeledPoint  
  5. import org.apache.spark.{SparkContext, SparkConf}  
  6.   
  7. /**  
  8.   * Created by luo on 12/12/15.  
  9.   */  
  10. object ML_Classification {  
  11.   
  12.   def main(args:Array[String]){  
  13.   
  14. //代码初始化的一些步骤  
  15.     val conf=new SparkConf().setAppName("classification").setMaster("local[2]")  
  16.     val sc=new SparkContext(conf)  
  17.   
  18.     val rawData=sc.textFile("/home/luo/sparkLearning/MLData/train_noheader.tsv")  
  19.     val records=rawData.map(_.split("\t"))//数据是以\t分割  
  20.   
  21.     val data=records.map{point=>  
  22.     //将数据中的引号全部替换为空  
  23.       val replaceData=point.map(_.replaceAll("\"",""))  
  24.     //本数据的头四个字段不会用到,数据的一个字段代表分类的结果,1为长久,0为短暂    
  25.       val label=replaceData(replaceData.size-1).toInt  
  26.       val features=replaceData.slice(4,replaceData.size-1).map(x=>if(x=="?") 0.0 else x.toDouble)  
  27.     //label存分类结果,features存特征,将其转换为LabeledPoint类型,此类型主要用于监督学习。    
  28.       LabeledPoint(label,Vectors.dense(features))  
  29.     }  
  30.   
  31. //使用逻辑回归算法,此算法使用的是随机梯度下降算法进行优化,  
  32. //当然也可以使用其他的优化算法,对于算法原理推荐看看Andrew Ng的视频  
  33.     val lrModel=LogisticRegressionWithSGD.train(data,10)//迭代次数10次  
  34.   
  35.   
  36. //预测并查看有多少预测正确,这里的测试集与训练数据集相同,  
  37.     val predictrueData=data.map{point=>  
  38.         if(lrModel.predict(point.features)==point.label) 1 else 0  
  39.     }.sum()  
  40.   
  41. //求正确率  
  42.     val accuracy=predictrueData/data.count()  
  43.     println(accuracy)  
  44.   }  
  45. }  


运行之后可以看到正确率为0.5146720757268425(各次计算结果不相同属于正常情况),这个正确率也太低了吧。接下来介绍优化模型的方法用于提高预测的正确率。

三、特征标准化

当各类特征取值大小差距比较大时对预测结果会产生不好的影响。于是采用特征标准化会提高预测精度,这里的特征标准化就是我们常说的归一化。完成归一化的工作可以自己编写代码计算,公式就是(x-u)/sqrt(variance)。另外一种方法是采用MLlib内置的方法来标准化,我这里肯定采用的是后者。

特征标准化的方法如下:

[html]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. val vectors=data.map(p=>p.features)  
  2.  //调用初始化一个StandardScaler对象,具体使用方法查看Spark api  
  3.     val scaler=new StandardScaler(withMean = true,withStd = true).fit(vectors)  
  4.  //重新标准化特征变量  
  5.     val scalerData=data.map(point=>  
  6.     LabeledPoint(point.label,scaler.transform(point.features))  
  7.     )  


进行特征标准化以后的完整代码如下:

[html]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. import org.apache.spark.mllib.classification.LogisticRegressionWithSGD  
  2. import org.apache.spark.mllib.feature.StandardScaler  
  3. import org.apache.spark.mllib.linalg.Vectors  
  4. import org.apache.spark.mllib.regression.LabeledPoint  
  5. import org.apache.spark.{SparkContext, SparkConf}  
  6.   
  7. /**  
  8.   * Created by luo on 12/12/15.  
  9.   */  
  10. object ML_Classification {  
  11.   
  12.   def main(args:Array[String]){  
  13.   
  14.     val conf=new SparkConf().setAppName("classification").setMaster("local[2]")  
  15.     val sc=new SparkContext(conf)  
  16.   
  17.     val rawData=sc.textFile("/home/luo/sparkLearning/MLData/train_noheader.tsv")  
  18.     val records=rawData.map(_.split("\t"))  
  19.   
  20.     val data=records.map{point=>  
  21.       val replaceData=point.map(_.replaceAll("\"",""))  
  22.       val label=replaceData(replaceData.size-1).toInt  
  23.       val features=replaceData.slice(4,replaceData.size-1).map(x=>if(x=="?") 0.0 else x.toDouble)  
  24.       LabeledPoint(label,Vectors.dense(features))  
  25.     }  
  26.   
  27.     val vectors=data.map(p=>p.features)  
  28.     val scaler=new StandardScaler(withMean = true,withStd = true).fit(vectors)  
  29.     val scalerData=data.map(point=>  
  30.       LabeledPoint(point.label,scaler.transform(point.features))  
  31.     )  
  32.   
  33.     val lrModel=LogisticRegressionWithSGD.train(scalerData,10)  
  34.   
  35.     val predictrueData=scalerData.map{point=>  
  36.       if(lrModel.predict(point.features)==point.label) 1 else 0  
  37.     }.sum()  
  38.   
  39.     val accuracy=predictrueData/data.count()  
  40.     println(accuracy)  
  41.   }  
  42. }  


在IDEA中运行查看结果为0.6204192021636241,结果比之前要好一些,但是然并卵,还要继续优化。

四、添加类别特征

如果有详细看每一行数据的话会发现每行的第四个特征为网页类别,例如“weather”、“sports”、“unkown”等,由于此列数据为文字,在之前的训练之中我们人为舍弃掉了这一列的数据,但是每一个类别可以考虑的因素不一样,所以类别对预测精度的影响还是蛮大的。通过一个1×n的向量来表示,属于哪个类别向量的对应位置为1,其余为0。代码如下:

[html]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. //数据第三列是类别,先计算总类数,然后建立一个类别到序号的map  
  2. val category=records.map(r=>r(3)).distinct().collect().zipWithIndex.toMap  
  3.   
  4. //与之前不同的是添加了一个向量categoryFeatures用于标识类别  
  5.     val data=records.map{point=>  
  6.       val replaceData=point.map(_.replaceAll("\"",""))  
  7.       val label=replaceData(replaceData.size-1).toInt  
  8.       val categoriesIndex=category(point(3))  
  9.       val categoryFeatures=Array.ofDim[Double](category.size)  
  10.       categoryFeatures(categoriesIndex)=1.0  
  11.       val otherfeatures=replaceData.slice(4,replaceData.size-1).map(x=>if(x=="?") 0.0 else x.toDouble)  
  12.  //RDD之间的加运算使用"++",构建添加了类别标识以后的特征向量  
  13.       val features=otherfeatures++categoryFeatures  
  14.       LabeledPoint(label,Vectors.dense(features))  
  15.     }  


添加了类别标识特征以后完整代码如下:

[html]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. import org.apache.spark.mllib.classification.LogisticRegressionWithSGD  
  2. import org.apache.spark.mllib.feature.StandardScaler  
  3. import org.apache.spark.mllib.linalg.Vectors  
  4. import org.apache.spark.mllib.regression.LabeledPoint  
  5. import org.apache.spark.{SparkContext, SparkConf}  
  6.   
  7. /**  
  8.   * Created by luo on 12/12/15.  
  9.   */  
  10. object ML_Classification {  
  11.   
  12.   def main(args:Array[String]){  
  13.   
  14.     val conf=new SparkConf().setAppName("classification").setMaster("local[2]")  
  15.     val sc=new SparkContext(conf)  
  16.   
  17.     val rawData=sc.textFile("/home/luo/sparkLearning/MLData/train_noheader.tsv")  
  18.     val records=rawData.map(_.split("\t"))  
  19.   
  20.     val category=records.map(r=>r(3)).distinct().collect().zipWithIndex.toMap  
  21.   
  22.     val data=records.map{point=>  
  23.       val replaceData=point.map(_.replaceAll("\"",""))  
  24.       val label=replaceData(replaceData.size-1).toInt  
  25.       val categoriesIndex=category(point(3))  
  26.       val categoryFeatures=Array.ofDim[Double](category.size)  
  27.       categoryFeatures(categoriesIndex)=1.0  
  28.       val otherfeatures=replaceData.slice(4,replaceData.size-1).map(x=>if(x=="?") 0.0 else x.toDouble)  
  29.       val features=otherfeatures++categoryFeatures  
  30.       LabeledPoint(label,Vectors.dense(features))  
  31.     }  
  32.   
  33.     val vectors=data.map(p=>p.features)  
  34.     val scaler=new StandardScaler(withMean = true,withStd = true).fit(vectors)  
  35.     val scalerData=data.map(point=>  
  36.       LabeledPoint(point.label,scaler.transform(point.features))  
  37.     )  
  38.   
  39.     val lrModel=LogisticRegressionWithSGD.train(scalerData,10)  
  40.   
  41.     val predictrueData=scalerData.map{point=>  
  42.       if(lrModel.predict(point.features)==point.label) 1 else 0  
  43.     }.sum()  
  44.   
  45.     val accuracy=predictrueData/data.count()  
  46.     println(accuracy)  
  47.   }  
  48. }  


运行之后查看正确率为0.6657200811359026,在之前的优化基础之上又有一定的提升。

总结:本篇博客介绍的内容到这里就结束了,主要是介绍了MLlib中分类算法的应用以及一些算法优化的思路。当然为了提高算法准确度还需要完成的一项重要工作就是参数调优,对于这方面的内容本篇博客未涉及,有兴趣的朋友可以自行查阅相关资料试试不同的参数对正确率的影响。另外这里举例用到的是逻辑回归分类算法,其他大部分分类算法的使用方法类似。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值