什么是机器学习
百度:
机器学习是一门多学科交叉专业,涵盖概率论知识,统计学知识,近似理论知识和复杂算法知识,使用计算机作为工具并致力于真实实时的模拟人类学习方式,并将现有内容进行知识结构划分来有效提高学习效率。
在我看来机器学习就是给你的计算机一套逻辑(建模训练),让他根据这套逻辑去对数据进行处理(测试)。
Spark ML
Spark MLlib是Spark的机器学习(ML)库。它的目标是使实用的机器学习可扩展且容易
数据处理
- spark ML有2种类型局部向量:dense和sparse。 稠密型向量(dense)表示为一个数组,如[4500,41000, 4] 。
- 稀疏型向量(sparse)则由两个平行数组构成,其中一个表示索引,另一个表示元素值,如(3, [0, 1, 2],[4500.0, 41000.0, 4.0])。其中‘3’代表有3个特征值;‘[0, 1, 2]’代表特征值索引,第0个,第1个,第2个不为0或者null;‘[4500.0, 41000.0, 4.0]’代表对应索引位置的特征值。
但是我们平时遇到的数据,大多都不是这两种格式,所以我们需要将我们的数据经过一系列处理才能交给spark处理。
基本流程:
相关性表示两个变量的统计上的关系,如当一个变量发生变化,另一个变量也会变化。相关性分为如下两种:
正相关:一个变量的增加导致另一个变量的增加
负相关:一个变量的增加导致另一个变量的减少
如果一个列的变化对最终结果影响不大,那说明这一列和结果的相关性低,属于无用列,会影响模型的准确性,我们需要将其删除
spark可以直接使用drop删除无用列
对于非数字数据这种,我们可以有两种办法解决
第一种:直接给他们设置不同的值,比如yes设为0,no设为1。这种办法很简单,但是也有一个致命的缺点,实际上yes和no是大小相同的,1却是实实在在比0大的,所以计算机也会认为yes比no大,这对最后模型是有影响的。
第二种:将这些数据映射为字典里面的数据,比如yes为[0,1],no为[1,0],这样相比第一种是更适合的,对计算机来说没有大小之分,只代表两种情况。
spark提供了StringIndexer()方法将字符串映射为字典数据
val scaler = new StringIndexer().setInputCol(col).setOutputCol(col+"_num").fit(df)
df = scaler.transform(df).drop(col)
将向量创建为dense或sparse,依赖于数据中有多少null或0。当10000个数据中有9000个数据均为0,若使用稠密型向量,则会浪费空间。
spark提供了VectorAssembler方法,将多列合并为一个稀疏向量。
val vec_assembler = new VectorAssembler().setInputCols(Array("TotalCharges","SeniorCitizen","tenure","MonthlyCharges","Partner_num","Dependents_num","MultipleLines_num","InternetService_num","OnlineSecurity_num","OnlineBackup_num","DeviceProtection_num","TechSupport_num","Contract_num","PaperlessBilling_num","PaymentMethod_num"))
.setOutputCol("features").setHandleInvalid("skip")
var final_data = vec_assembler.transform(df).select("features","label_num")
建模过程其实就是根据根据数据的经过公式处理得到一个结果,所以数据数值大小对最终模型影响很大,这也是数据标准化的必要性。比如在电信客户流失预测案例中,客户是否开通某个业务和月花费这两个特征,是否开通是0和1,月花费可能非常大,那再计算时受月花费的影响就会非常大,基本上只会受月花费的影响,那这样的模型的预测效果就不会很好。那数据标准化是什么呢?就是将每一个特征值进行缩放处理,让他们大部分在一个区间呢,但又不会影响同一个特征不同值之间的比例。
spark提供了StandardScaler进行数据标准化
val scalerModel = new StandardScaler().setInputCol("features").setOutputCol("scaledFeatures").fit(final_data)
final_data = scalerModel.transform(final_data)
监督属性就是结果属性,比如在电信客户流失预测案例中,客户最终是否流失就是监督属性,根据这个特征来分类,流失客户特征和非流失客户特征。
特征分类后,有时候我们会发现不同特征的数据量差距很大,数据量的差距会导致我们模型不准确。
对此我们有两种办法解决:
过采样:将数据量少的特征分类复制几分,使不同特征的两份数据量大致相同
欠采样:在数据量多的特征分类中抽取部分,使不同特征的两份数据量大致相同
//分类和欠采样
val df_class_0 = final_data.where("label_num=0.0")
val df_class_1 = final_data.where("label_num=1.0")
val df_class_0_over = df_class_0.sample(false,fraction=df_class_1.count()/df_class_0.count())
val res = df_class_1.union(df_class_0_over)
到这一步说明数据集基本上已经处理完毕,可以直接交给spark进行建模了,但是为了验证我们最终模型的效果,我们要抽出一部分数据进行测试,剩下的数据进行训练模型,这里划分的关键就是随机取样(其中时序模型最好是按照时间排序后,将最后的抽出当作测试集,这样更清楚明了)。
spark提供了随机划分数据集的方法randomSplit
val train_test = final_data.randomSplit(Array(0.7, 0.3))