Skip to content
Closed
147 changes: 147 additions & 0 deletions docs/ml-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -801,6 +801,153 @@ jsc.stop();

</div>

## Examples: Summaries for LogisticRegression.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Examples -> Example

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summaries -> Summary (There is only one summary)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No period at end


Once [`LogisticRegression`](api/scala/index.html#org.apache.spark.ml.classification.LogisticRegression)
is run on data, it is useful to extract statistics such as the
loss per iteration which will provide an intuition on overfitting and metrics to understand
how well the model has performed on training and test data.

[`LogisticRegressionTrainingSummary`](api/scala/index.html#org.apache.spark.mllib.classification.LogisticRegressionTrainingSummary)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this links the scala api doc, move this under the scala codetab and add another one for the java api doc

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

provides an interface to access such relevant information. i.e the `objectiveHistory` and metrics
to evaluate the performance on the training data directly with very less code to be rewritten by
the user.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should document that logistic regression in ML currently [only supports two classes|https://github.com/apache/spark/blob/master/mllib/src/main/scala/org/apache/spark/ml/classification/LogisticRegression.scala#L259] in the user guide (hence the casts to BinaryLogisticRegression), and that the traits are there for future extensibility purposes

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should also mention that the predictions are transient and that the summary is only available on the driver


This examples illustrates the use of `LogisticRegressionTrainingSummary` on some toy data.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

examples -> example


<div class="codetabs">
<div data-lang="scala">
{% highlight scala %}
import org.apache.spark.{SparkConf, SparkContext}
import org.apache.spark.ml.classification.{LogisticRegression, BinaryLogisticRegressionSummary}
import org.apache.spark.mllib.regression.LabeledPoint
import org.apache.spark.mllib.linalg.Vectors
import org.apache.spark.sql.{Row, SQLContext}

val conf = new SparkConf().setAppName("LogisticRegressionSummary")
val sc = new SparkContext(conf)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need for conf, sc, or sqlContext since they exist already in spark-shell (the code examples should be copy-pasteable into spark-shell)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I copied the example code shown previously where all these are set.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are not always consistent, but I've been trying to discourage those. Basically, I want users to be able to copy and paste the code into the spark shell and have it work.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I realized that and I removed it.

val sqlContext = new SQLContext(sc)
import sqlContext.implicits._

// Use some random data for demonstration.
// Note that the RDD of LabeledPoints can be converted to a dataframe directly.
val data = sc.parallelize(Array(
LabeledPoint(0.0, Vectors.dense(0.2, 4.5, 1.6)),
LabeledPoint(1.0, Vectors.dense(3.1, 6.8, 3.6)),
LabeledPoint(0.0, Vectors.dense(2.4, 0.9, 1.9)),
LabeledPoint(1.0, Vectors.dense(9.1, 3.1, 3.6)),
LabeledPoint(0.0, Vectors.dense(2.5, 1.9, 9.1)))
)
val logRegDataFrame = data.toDF()

// Run Logistic Regression on your toy data.
// Since LogisticRegression is an estimator, it returns an instance of LogisticRegressionModel
// which is a transformer.
val logReg = new LogisticRegression()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use builder notation new LogisticRegression().setMaxIter(...).setRegParam(...)

logReg.setMaxIter(5)
logReg.setRegParam(0.01)
val logRegModel = logReg.fit(logRegDataFrame)

// Extract the summary directly from the returned LogisticRegressionModel instance.
val trainingSummary = logRegModel.summary

// Obtain the loss per iteration. This should decrease upto a certain point and
// then increase or show negligible change after this.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Training loss should always decrease; overfitting only affects the loss on test-set

val objectiveHistory = trainingSummary.objectiveHistory
objectiveHistory.foreach(loss => println(loss))

// Obtain the metrics useful to judge performance on test data.
val binarySummary = trainingSummary.asInstanceOf[BinaryLogisticRegressionSummary]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add comment that that this cast is OK because we have a binary classification problem

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto for java example


// Obtain the receiver-operating characteristic as a dataframe and areaUnderROC.
val roc = binarySummary.roc
roc.show()
roc.select("FPR").show()
println(binarySummary.areaUnderROC)

// Get the threshold corresponding to the maximum F-Measure and rerun LogisticRegression with
// this selected threshold.
val fMeasure = binarySummary.fMeasureByThreshold
val maxFMeasure = fMeasure.select(max("F-Measure")).head().getDouble(0)
val bestThreshold = fMeasure.where($"F-Measure" === maxFMeasure).
select("threshold").head().getDouble(0)
logReg.setThreshold(bestThreshold)
logReg.fit(logRegDataFrame)
{% endhighlight %}
</div>

<div data-lang="java">
{% highlight java %}
import com.google.common.collect.Lists;

import org.apache.spark.SparkConf;
import org.apache.spark.api.java.JavaRDD;
import org.apache.spark.api.java.JavaSparkContext;
import org.apache.spark.ml.classification.BinaryLogisticRegressionSummary;
import org.apache.spark.ml.classification.LogisticRegression;
import org.apache.spark.ml.classification.LogisticRegressionModel;
import org.apache.spark.ml.classification.LogisticRegressionTrainingSummary;
import org.apache.spark.mllib.regression.LabeledPoint;
import org.apache.spark.mllib.linalg.Vectors;
import org.apache.spark.sql.DataFrame;
import org.apache.spark.sql.Row;
import org.apache.spark.sql.SQLContext;
import static org.apache.spark.sql.functions.*;

SparkConf conf = new SparkConf().setAppName("LogisticRegressionSummary");
JavaSparkContext jsc = new JavaSparkContext(conf);
SQLContext jsql = new SQLContext(jsc);

// Use some random data for demonstration.
// Note that the RDD of LabeledPoints can be converted to a dataframe directly.
JavaRDD<LabeledPoint> data = sc.parallelize(Lists.newArrayList(
new LabeledPoint(0.0, Vectors.dense(0.2, 4.5, 1.6)),
new LabeledPoint(1.0, Vectors.dense(3.1, 6.8, 3.6)),
new LabeledPoint(0.0, Vectors.dense(2.4, 0.9, 1.9)),
new LabeledPoint(1.0, Vectors.dense(9.1, 3.1, 3.6)),
new LabeledPoint(0.0, Vectors.dense(2.5, 1.9, 9.1)))
);
DataFrame logRegDataFrame = sql.createDataFrame(data, LabeledPoint.class);

// Run Logistic Regression on your toy data.
// Since LogisticRegression is an estimator, it returns an instance of LogisticRegressionModel
// which is a transformer.
LogisticRegression logReg = new LogisticRegression();
logReg.setMaxIter(5);
logReg.setRegParam(0.01);
LogisticRegressionModel logRegModel = logReg.fit(logRegDataFrame);

// Extract the summary directly from the returned LogisticRegressionModel instance.
LogisticRegressionTrainingSummary trainingSummary = logRegModel.summary();

// Obtain the loss per iteration. This should decrease upto a certain point and
// then increase or show negligible change after this.
double[] objectiveHistory = trainingSummary.objectiveHistory();
for (double lossPerIteration: objectiveHistory) {
System.out.println(lossPerIteration);
}

// Obtain the metrics useful to judge performance on test data.
BinaryLogisticRegressionSummary binarySummary = (BinaryLogisticRegressionSummary) trainingSummary;

// Obtain the receiver-operating characteristic as a dataframe and areaUnderROC.
DataFrame roc = binarySummary.roc();
roc.show();
roc.select("FPR").show();
System.out.println(binarySummary.areaUnderROC());

// Get the threshold corresponding to the maximum F-Measure and rerun LogisticRegression with
// this selected threshold.
DataFrame fMeasure = binarySummary.fMeasureByThreshold();
double maxFMeasure = fMeasure.select(max("F-Measure")).head().getDouble(0);
double bestThreshold = fMeasure.where(fMeasure.col("F-Measure").equalTo(maxFMeasure)).
select("threshold").head().getDouble(0);
logReg.setThreshold(bestThreshold);
logReg.fit(logRegDataFrame);
{% endhighlight %}
</div>
</div>

# Dependencies

Spark ML currently depends on MLlib and has the same dependencies.
Expand Down