/// <summary> /// Writes class classification statistics. /// </summary> /// <param name="writer">A stream to write the report to.</param> /// <param name="summary">Classification results for the class.</param> /// <param name="classNameLength">The number of characters in the class name column.</param> private static void WriteClassStatistics(TextWriter writer, ClassSummary <T> summary, int classNameLength) { writer.Write(string.Format(CultureInfo.InvariantCulture, "{{0,-{0}}},", classNameLength), summary.Label); WriteShortStatistics(writer, summary.Statistics.All); WriteLongStatistics(writer, summary.Statistics.WithTruth); writer.WriteLine(); }
/// <summary> /// Initializes a new instance of the <see cref="ClassificationReport{T}"/> class. /// </summary> /// <param name="results">The classification results.</param> public ClassificationReport(IEnumerable <ClassificationResult <T> > results) { if (results == null) { throw new ArgumentNullException(nameof(results)); } Dictionary <T, ClassSummary <T> > summaries = new Dictionary <T, ClassSummary <T> >(); foreach (ClassificationResult <T> result in results) { this.results.Add(result); T expected = result.Expected; if (!summaries.TryGetValue(expected, out ClassSummary <T> summary)) { summaries[expected] = summary = new ClassSummary <T>(expected); this.classes.Add(summary); } summary.Add(result); this.AllClasses.Add(result); this.ConfusionMatrix.Add(result.Predicted, expected); } this.results.TrimExcess(); this.classes.TrimExcess(); }
/// <summary> /// Writes class errors. /// </summary> /// <param name="writer">A stream to write the report to.</param> /// <param name="summary">Classification results for the class.</param> private static void WriteClassificationErrors(TextWriter writer, ClassSummary <T> summary) { int acceptedErrors = summary.Errors.Count(); if (acceptedErrors > 0) { writer.WriteLine(string.Format(CultureInfo.InvariantCulture, "{0} ({1})", summary.Label, acceptedErrors)); writer.WriteLine(); ClassificationResult <T> .Write(writer, summary.Errors); writer.WriteLine("-----------------------------------------------------------------------------"); writer.WriteLine(); } }
/// <summary> /// Writes class reject curve. /// </summary> /// <param name="writer">A stream to write the report to.</param> /// <param name="summary">Classification results for the class.</param> private static void WriteClassRejectCurve(TextWriter writer, ClassSummary <T> summary) { float[] errorRates = { 0.001f, 0.005f, 0.01f, 0.02f, 0.03f, 0.04f, 0.05f, 0.06f, 0.07f, 0.08f, 0.09f, 0.10f, 0.11f }; writer.WriteLine(summary.Label); writer.WriteLine(); writer.WriteLine( "{0,-10}{1,-10}{2,-10}{3,-10}", "Target", "Error", "Accept", "Threshold"); RejectCurveTarget[] targets = summary.Statistics.RejectCurveTruth.GetTargets(errorRates); foreach (RejectCurveTarget target in targets) { if (target.Point.HasValue) { writer.WriteLine( "{0,-10:P2}{1,-10:P2}{2,-10:P2}{3,-10:N0}", target.Target, target.Point.Value.ErrorRate, target.Point.Value.AcceptRate, target.Point.Value.Threshold); } else { writer.WriteLine( "{0,-10:P2}{1,-10}{1,-10}{1,-10}", target.Target, "N/A"); } } writer.WriteLine(); // write area float average = summary.Statistics.RejectCurveTruth.GetArea(0.0f, errorRates.Last(), 100); writer.WriteLine( "Area: {0:P2}", average); writer.WriteLine("-----------------------------------------------------------------------------"); writer.WriteLine(); }
/// <summary> /// Writes all reject curves. /// </summary> /// <param name="writer">A stream to write the report to.</param> /// <param name="all">Classification results for all classes.</param> /// <param name="classes">Classification results for each class.</param> private static void WriteRejectCurves(TextWriter writer, ClassSummary <T> all, IList <ClassSummary <T> > classes) { float[] errorRates = { 0.001f, 0.005f, 0.01f, 0.02f, 0.03f, 0.04f, 0.05f, 0.06f, 0.07f, 0.08f, 0.09f, 0.10f, 0.11f }; List <ClassSummary <T> > combined = new List <ClassSummary <T> >() { all }; combined.AddRange(classes); string separator = new string('-', 10 + (30 * combined.Count)); // write class names writer.Write("{0,-10}", string.Empty); foreach (ClassSummary <T> cls in combined) { writer.Write("{0,-30}", cls.Label); } writer.WriteLine(); writer.WriteLine(separator); // write header writer.Write("{0,-10}", "Target"); for (int i = 0, ii = combined.Count; i < ii; i++) { writer.Write("{0,-10}{1,-10}{2,-10}", "Error", "Accept", "Thresh"); } writer.WriteLine(); // write targets foreach (float errorRate in errorRates) { writer.Write("{0,-10:P2}", errorRate); foreach (ClassSummary <T> cls in combined) { RejectCurveTarget target = cls.Statistics.RejectCurveTruth.GetTarget(errorRate); if (target.Point.HasValue) { writer.Write( "{0,-10:P2}{1,-10:P2}{2,-10:N0}", target.Point.Value.ErrorRate, target.Point.Value.AcceptRate, target.Point.Value.Threshold); } else { writer.Write( "{0,-10}{0,-10}{0,-10}", "N/A"); } } writer.WriteLine(); } writer.WriteLine(separator); // write area writer.Write("{0,-10}", "Area:"); foreach (ClassSummary <T> cls in combined) { float average = cls.Statistics.RejectCurveTruth.GetArea(0.0f, errorRates.Last(), 100); writer.Write("{0,-30:P2}", average); } writer.WriteLine(); }