1.相关参数设置:
<1> setMaxIter():设置最大迭代次数
<2> setRegParam(): 设置正则项的参数,控制损失函数与惩罚项的比例,防止整个训练过程过拟合
<3> setElasticNetParam():使用L1范数还是L2范数
setElasticNetParam=0.0 为L2正则化;
setElasticNetParam=1.0 为L1正则化;
setElasticNetParam=(0.0,1.0) 为L1,L2组合
<4> setFeaturesCol():指定特征列的列名,传入Array类型
<5>setLabelCol():指定标签列的列名,传入String类型
<6>setPredictionCol():指定预测列的列名
<7>setFitIntercept(value:Boolean):是否需要偏置,默认为true(即是否需要y=wx+b中的b)
<8>setStandardization(value:Boolean):模型训练时,是否对各特征值进行标准化处理,默认为true
<9>setSolver(value:String):设置用于优化求解器。线性回归支持的有l-bfgs(有限内存拟牛顿法),normal(加权最小二乘法)和auto(自动选择)。
<10>setTol(value:Double):设置迭代的收敛公差。值越小准确性越高但是迭代成本增加。默认值为1E-6。(即损失函数)
<11>setWeightCol(value:String):设置某特征列的权重值,如果不设置或者为空,默认所有实例的权重为1。
<12>setAggregationDepth:建议深度大于或等于2,默认为2。如果特征维度较大或者数据的分区量大的时候,可以调大该值。
<13>fit:基于训练街训练出模型
<14>transform:基于训练出的模型对测试集进行预测
2.demo
class LinearRegressionDemo {
def train(): Unit = {
val spark = SparkSession.builder()
.master("local[2]")
.appName("LinearRegression")
.getOrCreate()
//local模式下,加上file:/// 表示读取本地文件
//header为true,表示要设置第一行为列名
val file = spark.read.format("csv").option("header", "true")
.option("sep", ";").load("src/main/resources/house.csv")
file.show(false)
import spark.implicits._
//数据集是有序的,对训练效果不好,添加1列
val random = new Random()
//经过map操作变成DataSet[(Double,Double)]类型,要通过toDF转成DataFrame
val data = file.select("square", "price").map(
row => (row.getAs[String](0).toDouble, row.getAs[String](1).toDouble, random.nextDouble())
).toDF("square", "price", "random")
.sort("random")
data.show(false)
//将多个列或单列合并成Vector
val assembler = new VectorAssembler()
.setInputCols(Array("square"))
.setOutputCol("features")
val dataset = assembler.transform(data)
val Array(train, test) = dataset.randomSplit(Array(0.8, 0.2), 1234L)
val regression = new LinearRegression()
.setMaxIter(10)
.setRegParam(0.3)
.setElasticNetParam(0.8)
//在train数据集上训练fit
val model = regression.setLabelCol("price").setFeaturesCol("features").fit(train)
//transform 预测
model.transform(test).show(false)
}
}
transform的结果:
会多一列预测值(prediction)
image.png
最终打印出训练模型的参数,就是w向量和b值:
println("Cofficients:"+model.coefficients)
println("Intercept:"+model.intercept)
image.png
例子中特征列只有1项,所以w向量也只有1个维度。
那么如何查看预测结果信息:
test_predict.select("features","price","prediction").collect().foreach{
case Row(features:org.apache.spark.ml.linalg.Vector,label:Double,prediction:Double)=>
println(s"($features,$label)-> prediction=$prediction")
}
image.png
如何打印模型摘要:
val trainingSummary=model.summary
//每次迭代的目标值
val objectiveHistory=trainingSummary.objectiveHistory
//迭代次数
println(s"numIterations:${trainingSummary.totalIterations}")
//每次迭代的目标值,即损失函数+正则化项
println(s"objectiveHistory:[${trainingSummary.objectiveHistory.mkString(",")}]")
//每个样本的误差值(即label值减去预测值)
trainingSummary.residuals.show(false)
//均方误差
println(s"RMSE:${trainingSummary.rootMeanSquaredError}")
//最终的决定系数,0-1之间,值越大拟合程度越高
println(s"r2:${trainingSummary.r2}")
结果显示:
image.png
image.png
trainingSummary中还有许多别的参数,详细可以看源码。
最后一步,保存和加载训练模型:
model.save("hdfs://")
val load_model=LinearRegressionModel.load("hdfs://")
补充:
1.正则化(在特征较多时比较有效)
比如说下图,就是过拟合的情况
image.png
直观上来讲。解决这个例子中的过拟合问题,最好就是消除x4,x5,x^6的影响,也就是让theta4,theta5,theta6约等于0,一个简单的办法就是给原有的cost函数加上略大惩罚项,如:
image.png
这样在最小化cost函数的时候,theta4,theta5,theta6约等于0
=====》 加上正则化项的损失函数:
image.png
正则化项就是权重(即theta1或者theta2等)的L1或者L2范数乘以一个正则系数
正则系数的作用:用来控制损失函数和正则化项的比重
image.png
2.ElasticNet
被定义为L1和L2的正则化项的凸组合:
image.png
参数为0时,采用L2正则化参数,则训练的模型相当于ridge回归模型;参数为1时,采用L1正则化参数,相当于Lasso模型。










网友评论