目录
1、数据质量要求
算法 | 机器学习类别 | 缺失值 | 连续值 | 不平衡数据 | 离群点 | 数据归一 | 离散特征处理 | 树形 | 特征选择依据 | spark实现 | 过拟合处理、参数 |
lightGBM | 二分类、多分类、回归 | 不敏感 | 不敏感 | 调参处理 | 敏感 | 不敏感 | K值编码 | 树 | 目标函数增益,方法上加了很多技巧 | 第三方 | |
xgboost | 二分类、多分类、回归 | 不敏感 | 不敏感 | 不敏感 | 敏感 | 不敏感 | one-hot | 树、线性模型 | 目标函数增益 | 第三方 | |
梯度提升决策树(GBDT) | spark支持二分类、回归 | 敏感, spark需处理 | 不敏感 | 分类可能敏感 | 敏感 | 不敏感 | one-hot 或 K值编码 | 二叉树 | mse | yes | 超参数: loss类型、nums、learningrate一般不调 |
随机森林(rf) | 多分类、回归 | 敏感, spark需处理 | 不敏感 | 不敏感 | 不敏感 | 不敏感 | one-hot 或 K值编码 | -- | 树的特征选择依据 | yes | 超参数: 在上述决策树的基础上,增加树的个数nums、featuresaction一般不调 |
决策树-ID3 | 多分类 | 无法处理 | 无法处理 | 不敏感 | 不敏感 | 不敏感 | 可处理 | 多叉树 | 信息增益 | no | |
决策树-C4.5 | 多分类 | 不敏感 | 不敏感 | 不敏感 | 不敏感 | 不敏感 | one-hot 或 K值编码 | 多叉树 | 信息增益率 | no | 后剪枝,计算大 |
决策树-CART | 多分类 | spark中敏感,需处理 | 不敏感 | 不敏感 | 不敏感 | 不敏感 | one-hot 或 K值编码 | 二叉树 | Gini系数 | yes | 超参数: maxdepth、 maxbins、mininfogain、impurity |
决策树-CART | 回归 | spark中敏感,需处理 | 不敏感 | -- | 敏感 | 不敏感 | one-hot 或 K值编码 | 二叉树 | mse | yes | 超参数: 没具体使用,暂不清楚 |
(1)调参
异常值敏感:单颗树回归值、每棵树结果在上一棵树基础上迭代值,异常不会消失,总是存在;
支持类别特征编码;
调参文章转载:https://zhuanlan.zhihu.com/p/39782438(参数介绍)
调参文章转载:lightGBM参数解析及其参数调优_LS_learner的博客-CSDN博客_lightgbm verbose(参数调参思路介绍)
调参文章转载:【白话机器学习】算法理论+实战之LightGBM算法 - 知乎
官网:https://lightgbm.readthedocs.io/en/latest/Parameters-Tuning.html(说明很清晰)
调参是跟原理、算法过程很相关的,所以lightGBM的参数里除了有基本的学习率、迭代次数、特征比例、样本比例这些的,还有跟其本身直方图决策树相关的max-bin,跟leaf-wise算法相关的max-depth、num-leaves,跟GOSS算法相关的top_rate等
2、原理解释
(1)白话原理
看过很多视频课,文字版的原理转载文章:https://zhuanlan.zhihu.com/p/99069186
lightGBM是在xgboost基础上的改进,更快、内存更小:
更快:(大数据意味数据量大和特征数量多,所以更快就是从缩小数据量计算和特征量计算考虑)
更快-特征:
▶基于Histogram的决策树算法
xgboost是特征的所有特征值预排序找切分点,lightgbm是将连续特征离散化即直方图算法,然后根据直方图的值切分,大大减少计算量
▶带深度限制的Leaf-wise的叶子生长策略
▶互斥特征捆绑 Exclusive Feature Bundling(EFB)
特征数量进一步减少
更快-数据量:
▶单边梯度采样
分裂增益计算的时候,倾向于选择梯度大的样本
更小:
▶基于Histogram的决策树算法
不需要进行xgboost的所有特征值和特征值索引的存储了;
(2)场景
二分类、多分类、回归
(3)特点
相比xgboost更快、占用内存更小;
需要调参解决其缺点:限制树生长深度;
需要数据预处理噪点;
3、代码相关
package org.example.practice
import org.apache.spark.ml.evaluation.{BinaryClassificationEvaluator, MulticlassClassificationEvaluator}
import org.apache.spark.ml.feature.VectorAssembler
import org.apache.spark.sql.{DataFrame, SparkSession}
import com.microsoft.ml.spark.lightgbm.{LightGBMBooster, LightGBMClassificationModel, LightGBMClassifier}
import org.apache.spark.ml.Pipeline
import scala.util.Random
object LightGBMTest {
def main(args:Array[String]) :Unit= { //Unit 代表无返回值
val spark = SparkSession.builder().master("local[4]").getOrCreate() //创建1个SparkSession,本地运行加 local,数字跟CPU核数相关
spark.sparkContext.setLogLevel("ERROR") //只展示报错日志
import spark.implicits._
/*
Spark的Scala开发一定要加入以下这一行
它主要是使RDD转化为DataFrame以及支持后续SQL操作
*/
val data = spark.read.
option("inferSchema", true).
option("header", true).
csv("E:\\13data\\archive\\creditcard.csv")
println("*********************************数据读入查看****************************************")
println(data.first)
println("columns_length: "+(data.first.length))
data.printSchema()
println("查看列名: "+(data.schema.fields.map(f =>f.name).toList))//查看列名
println("查看每列类型:"+(data.dtypes.toMap))//查看每列的类型
val total = data.count()
data.groupBy("Class").count()
.orderBy("Class")
.show()//查看样本分布平衡性,样本严重不平衡
// Split into 90% train (+ CV), 10% test
val Array(trainData, testData) = data.randomSplit(Array(0.9, 0.1))
trainData.cache()
testData.cache()
val lgb = new LgbClass(spark)
lgb.lgbFunc(trainData,testData)
trainData.unpersist()
testData.unpersist()
}//完成了数据加载
}
class LgbClass(private val spark: SparkSession){
import spark.implicits._
def lgbFunc(trainData: DataFrame, testData: DataFrame): Unit = {
//step1:spark 数据预处理,合并特征为1列
val inputCols = trainData.columns.filter(_ != "Class")
val assembler = new VectorAssembler().
setInputCols(inputCols).
setOutputCol("featureVector")
val labelCol = "Class"
val assembledTrainData = assembler.transform(trainData)
val assembledTestData = assembler.transform(testData)
//step2:模型建立:模型实例、数据训练、应用预测
val classifier = new LightGBMClassifier()
.setNumIterations(50)
.setNumLeaves(31)
.setBoostFromAverage(false)
.setFeatureFraction(0.8)
.setMaxDepth(4)
.setMaxBin(255)
.setLearningRate(0.1)
.setMinSumHessianInLeaf(0.001)
.setLambdaL1(0.0)
.setLambdaL2(0.0)
.setBaggingFraction(0.8)
.setBaggingFreq(5)
.setBaggingSeed(1)
.setObjective("binary")
.setLabelCol(labelCol)
.setFeaturesCol("featureVector")
//.setVerbosity(-1)
//val pipeline = new Pipeline().setStages(Array(assembler,classifier))
val model = classifier.fit(assembledTrainData)
val predictions = model.transform(assembledTestData)
predictions.show(3,false)
//step3:模型评价:评价实例、评价方法
val evaluator = new BinaryClassificationEvaluator().setLabelCol("Class").setRawPredictionCol("prediction")
println(evaluator.evaluate(predictions))
val auc = evaluator.setMetricName("areaUnderROC").evaluate(predictions)
//val f1 = evaluator.setMetricName("f1").evaluate(predictions)
//println(s"test accuracy=$accuracy")
println(f"test auc=$auc%.2f")//格式化输出
}
}