有关在madlib和MLlib上逻辑回归算法的探讨

from zengxiaosen

1,逻辑回归和多重线性回归的最大区别是因变量不同,其他基本差不多,因此两者同属于一个家族:广义线性模型。


这一家族中的模型形式基本差不多,不同的是因变量不同:

如果是连续的,就是多重线性回归;

如果是二项分布,就是逻辑回归;

如果是Poisson分布,就是Poisson回归;

如果是负二项分布,就是负二项回归。


逻辑回归主要的应用场景:

寻找危险因素:例如寻找某疾病的危险因素;

预测:根据模型预测不同的自变量情况下某病或某情况的发生概率;

判别:实际上跟预测有些类似,也是根据模型,判断某人属于某病或属于某种情况的概率有多大,也就是看一下这个人有多大可能是属于某病。


逻辑回归的常规步骤:

寻找H函数(假设函数);

构造J函数(损失函数);

想办法使得J函数最小并求得回归参数a

====

构造预测函数H:

逻辑回归是用于分类(主要用于二分类)问题;

它利用了Logistic函数(也叫作Sigmoid函数):

对于现行边界的情况,边界形式为:

所以构造预测函数为:


其中函数H(x)的值就是便是该变量x分类为类别1和0的概率分别为:

====

构造损失函数J:

====

利用梯度下降法求参数最小值:

正规化解决过度拟合......



2,在madlib上利用psql语句进行逻辑回归算法的应用:

所用到的思想就是利用标签数据训练一个模型,然后利用这个模型去预测病人第二次心脏病的发生。

第一步:

  1. DROP TABLE IF EXISTS patients, patients_logregr, patients_logregr_summary;


  1. CREATE TABLE patients( id INTEGER NOT NULL,
  1.                         second_attack INTEGER,
  1.                         treatment INTEGER,
  1.                         trait_anxiety INTEGER);
  1.                           
  1. INSERT INTO patients VALUES                                                     
  1. (1,     1,      1,      70),
  1. (3,     1,      1,      50),
  1. (5,     1,      0,      40),
  1. (7,     1,      0,      75),
  1. (9,     1,      0,      70),
  1. (11,    0,      1,      65),
  1. (13,    0,      1,      45),
  1. (15,    0,      1,      40),
  1. (17,    0,      0,      55),
  1. (19,    0,      0,      50),
  1. (2,     1,      1,      80),
  1. (4,     1,      0,      60),
  1. (6,     1,      0,      65),
  1. (8,     1,      0,      80),
  1. (10,    1,      0,      60),
  1. (12,    0,      1,      50),
  1. (14,    0,      1,      35),
  1. (16,    0,      1,      50),
  1. (18,    0,      0,      45),
  1. (20,    0,      0,      60);

在patients表中有四个元素:id,second_attack,treatment,trait_anxiety

第二步:

引用madlib的build_in功能,使用输入的训练数据训练一个分类模型:

  1. SELECT madlib.logregr_train( 
  1.     'patients',                                 -- source table
  1.     'patients_logregr',                         -- output table
  1.     'second_attack',                            -- labels
  1.     'ARRAY[1, treatment, trait_anxiety]',       -- features
  1.     NULL,                                       -- grouping columns
  1.     20,                                         -- max number of iteration
  1.     'irls'                                      -- optimizer
  1.     );

                      

其中特征是treatment,trait_anxiety,因为要研究的是second_attack,所以把它作为labels,

输入的数据来自于patients表,训练后输出的数据会放在patients_logregr表,这里的迭代次数是20。

第三步骤:观察已经被训练完了的模型:

  1. -- Set extended display on for easier reading of output (\x is for psql only)
  1.  \x on
  1.  SELECT * from patients_logregr;

得到的结果是:

  1. -- ************ --
  1.  --    Result    --
  1.  -- ************ --
  1.  coef                     | [-6.36346994178187, -1.02410605239327, 0.119044916668606]
  1.  log_likelihood           | -9.41018298389
  1.  std_err                  | [3.21389766375094, 1.17107844860319, 0.0549790458269309]
  1.  z_stats                  | [-1.97998524145759, -0.874498248699549, 2.16527796868918]
  1.  p_values                 | [0.0477051870698128, 0.38184697353045, 0.0303664045046168]
  1.  odds_ratios              | [0.0017233763092323, 0.359117354054954, 1.12642051220895]
  1.  condition_no             | 326.081922792
  1.  num_rows_processed       | 20
  1.  num_missing_rows_skipped | 0
  1.  num_iterations           | 5
  1.  variance_covariance      | [[10.3291381930637, -0.47430466519573, -0.171995901260052], [-0.47430466519573, 1.37142473278285, -0.00119520703381598], [-0.171995901260052, -0.00119520703381598, 0.00302269548003977]]
  1.   

这是训练完的结果,其中coef也就是coefficient,是系数的意思,log_likelihood是对应的似然,std_err是标准误差

  1. -- Alternatively, unnest the arrays in the results for easier reading of output (\x is for psql only)
  1.  \x off
  1.  SELECT unnest(array['intercept', 'treatment', 'trait_anxiety']) as attribute,
  1.         unnest(coef) as coefficient,
  1.         unnest(std_err) as standard_error,
  1.         unnest(z_stats) as z_stat,
  1.         unnest(p_values) as pvalue,
  1.         unnest(odds_ratios) as odds_ratio
  1.  FROM patients_logregr;

得到的结果是:

  1. -- ************ --
  1.  --    Result    --
  1.  -- ************ --
  1.  +---------------+---------------+------------------+-----------+-----------+--------------+
  1.  | attribute     |   coefficient |   standard_error |    z_stat |    pvalue |   odds_ratio |
  1.  |---------------+---------------+------------------+-----------+-----------+--------------|
  1.  | intercept     |     -6.36347  |         3.2139   | -1.97999  | 0.0477052 |   0.00172338 |
  1.  | treatment     |     -1.02411  |         1.17108  | -0.874498 | 0.381847  |   0.359117   |
  1.  | trait_anxiety |      0.119045 |         0.054979 |  2.16528  | 0.0303664 |   1.12642    |
  1.  +---------------+---------------+------------------+-----------+-----------+--------------+

第三步:

利用训练完的模型去预测,根据原始数据去产生预测值:

  1. -- Display prediction value along with the original value
  1. SELECT p.id, madlib.logregr_predict(coef, ARRAY[1, treatment, trait_anxiety]),
  1.        p.second_attack
  1. FROM patients p, patients_logregr m
  1. ORDER BY p.id;

select的第一个参数是病人的id,第二个参数是madlib根据coef系数以及特征数组进行逻辑回归预测所产生的true或者是false,第三个参数是病人实际第二次心脏病发生与否,以下是结果:

  1. -- ************ --
  1. --    Result    --
  1. -- ************ --
  1. +------+-------------------+-----------------+
  1. |   id | logregr_predict   |   second_attack |
  1. |------+-------------------+-----------------|
  1. |    1 | True              |               1 |
  1. |    2 | True              |               1 |
  1. |    3 | False             |               1 |
  1. |    4 | True              |               1 |
  1. |    5 | False             |               1 |
  1. |    6 | True              |               1 |
  1. |    7 | True              |               1 |
  1. |    8 | True              |               1 |
  1. |    9 | True              |               1 |
  1. |   10 | True              |               1 |
  1. |   11 | True              |               0 |
  1. |   12 | False             |               0 |
  1. |   13 | False             |               0 |
  1. |   14 | False             |               0 |
  1. |   15 | False             |               0 |
  1. |   16 | False             |               0 |
  1. |   17 | True              |               0 |
  1. |   18 | False             |               0 |
  1. |   19 | False             |               0 |
  1. |   20 | True              |               0 |
  1. +------+-------------------+-----------------+

如果预测的可能性为true状态,就求出他发生这种预测的可能概率:

  1. SELECT p.id, madlib.logregr_predict_prob(coef, ARRAY[1, treatment, trait_anxiety])
  1. FROM patients p, patients_logregr m
  1. ORDER BY p.id;


select的第一个参数是病人的id,第二个参数是由coef系数以及有特征构成的数组得到的预测发生概率,结果是:

  1. -- ************ --
  1. --    Result    --
  1. -- ************ --
  1. +------+------------------------+
  1. |   id |   logregr_predict_prob |
  1. |------+------------------------|
  1. |    1 |              0.720223  |
  1. |    2 |              0.894355  |
  1. |    3 |              0.19227   |
  1. |    4 |              0.685513  |
  1. |    5 |              0.167748  |
  1. |    6 |              0.798098  |
  1. |    7 |              0.928568  |
  1. |    8 |              0.959306  |
  1. |    9 |              0.877576  |
  1. |   10 |              0.685513  |
  1. |   11 |              0.586701  |
  1. |   12 |              0.19227   |
  1. |   13 |              0.116032  |
  1. |   14 |              0.0383829 |
  1. |   15 |              0.0674976 |
  1. |   16 |              0.19227   |
  1. |   17 |              0.545871  |
  1. |   18 |              0.267675  |
  1. |   19 |              0.398619  |
  1. |   20 |              0.685513  |
  1. +------+------------------------+ 

3,在sparkMLlib上面使用逻辑回归算法进行预测:


  1. package test

  1. import org.apache.avro.ipc.specific.Person
  1. import org.apache.spark.ml.classification.{LogisticRegression, LogisticRegressionModel}
  1. import org.apache.spark.mllib.classification.{LogisticRegressionWithLBFGS, LogisticRegressionWithSGD}
  1. import org.apache.spark.mllib.evaluation.MulticlassMetrics
  1. import org.apache.spark.mllib.linalg.Vectors
  1. import org.apache.spark.mllib.regression.LabeledPoint
  1. import org.apache.spark.{SparkConf, SparkContext}

  1. /**
  1.   * Created by zengxiaosen on 16/6/6.
  1.   */
  1. object sparksql_logisticregression {



  1.   def main(args: Array[String]) {

  1.     val conf=new SparkConf()
  1.     conf.setAppName("Logistic_regression")
  1.     conf.setMaster("local")
  1.     val sc=new SparkContext(conf)
  1.     val data = sc.textFile("/Users/zengxiaosen/test/people_0.txt")

  1.     val parsedData = data.map { line => //开始对数据集处理
  1.       val parts = line.split(',') //根据逗号进行分区
  1.       LabeledPoint(parts(0).toDouble, Vectors.dense(parts(1).split(' ').map(_.toDouble)))
  1.     } //转化数据格式
  1.     parsedData.foreach(println)


  1.     //val model=new LogisticRegressionWithLBFGS().setNumClasses(10).run(training)
  1.     //划分一下训练数据和测试数据,将parsedData的60%分为训练数据,40%分为测试数据
  1.     val splits = parsedData.randomSplit(Array(0.6, 0.4), seed = 11L)

  1.     val trainingData = splits(0)
  1.     val testData = splits(1)
  1.     //运行训练算法构建模型:
  1.     //val model_0=LogisticRegressionWithSGD.train(trainingData, 50)
  1.     //运行训练算法构建模型
  1.     val model = new LogisticRegressionWithLBFGS().setNumClasses(2).run(trainingData)
  1.     //当模型训练完,我们可以使用testData来检验一下模型的出错率
  1.     //变量labelAndPreds保存了map()转换操作,map()将每一个行转换成二元组。
  1.     //二元组包含了testData的标签数据(point.label,分类数据)和预测出来的分类数据(prediction)。模型使用point.features作为输入数据。
  1.     /*val labelAndPreds = testData.map { point =>
  1.       val prediction = model.predict(point.features)
  1.       (point.label, prediction)
  1.     }*/
  1.     val target = Vectors.dense(-1) //创建测试值
  1.     val resulet = model.predict(target) //根据模型计算结果
  1.     //println(labelAndPreds)
  1.     //val trainErr = labelAndPreds.filter(r => r._1 != r._2).count.toDouble / testData.count
  1.     //println(trainErr)
  1.     println("model_weight:")
  1.     println(model.weights)

  1.     println(resulet) //打印结果
  1.     println(model.predict(Vectors.dense(10)))
  1.     sc.stop
  1.     //获取评估指标

  1.     //保存和加载模型




  1.   }

  1. }

产生的结果:

总结:

1:madlib使得数据库中的表数据能够直接方便的做逻辑回归,通过简单的psql语句就能够挖掘和预测出有用的信息,而spark的机器学习库对于不懂spark的人来说不容易驾驭,因为它涉及各种RDD算子的transformation或者checkpoint等过程,而如果产生bug还需要查看集群的各种信息(包括进程线程容器资源管理器等),给只熟悉sql的人员带来极大负担,但是madlib的操作比较稳定,不太容易产生调试上的操作,当然如果你能驾驭spark,利用spark进行机器学习还是非常方便的;

2:如果利用madlib进行数据挖掘,必须把非关系型数据通过ETL整理成关系型数据进行分析学习,而spark很擅长非关系型数据的处理,所以在ETL阶段,需要想办法更加高效;

3:作为一个用户,在学习难度方面两者相当;

4:在成熟度方面,sparkecosy中的MLlib成熟度没有madlib高,greenplum和madlib都比较成熟;

5:在性能方面,由于spark做机器学习的过程中数据可以checkpoint,而madlib都是写磁盘的,所以在性能方面MLlib比较好。



你可能感兴趣的:(madlib机器学习)