コード例 #1
0
ファイル: Regression.cs プロジェクト: ianzhangtianyi/ApsimX
        /// <summary>Puts the regression line and 1:1 line on graph.</summary>
        /// <param name="definitions">The definitions.</param>
        /// <param name="x">The x data.</param>
        /// <param name="y">The y data.</param>
        /// <param name="colour">The colour of the regresion line.</param>
        /// <param name="title">The title to put in the legen.</param>
        private void PutRegressionLineOnGraph(List <SeriesDefinition> definitions, IEnumerable x, IEnumerable y,
                                              Color colour, string title)
        {
            MathUtilities.RegrStats stat = MathUtilities.CalcRegressionStats(title, y, x);
            if (stat != null)
            {
                stats.Add(stat);
                double minimumX         = MathUtilities.Min(x);
                double maximumX         = MathUtilities.Max(x);
                double minimumY         = MathUtilities.Min(y);
                double maximumY         = MathUtilities.Max(y);
                double lowestAxisScale  = Math.Min(minimumX, minimumY);
                double largestAxisScale = Math.Max(maximumX, maximumY);

                SeriesDefinition regressionDefinition = new SeriesDefinition();
                regressionDefinition.title        = title;
                regressionDefinition.colour       = colour;
                regressionDefinition.line         = LineType.Solid;
                regressionDefinition.marker       = MarkerType.None;
                regressionDefinition.showInLegend = true;
                regressionDefinition.type         = SeriesType.Scatter;
                regressionDefinition.xAxis        = Axis.AxisType.Bottom;
                regressionDefinition.yAxis        = Axis.AxisType.Left;
                regressionDefinition.x            = new double[] { minimumX, maximumX };
                regressionDefinition.y            = new double[] { stat.Slope *minimumX + stat.Intercept, stat.Slope *maximumX + stat.Intercept };
                definitions.Add(regressionDefinition);
            }
        }
コード例 #2
0
ファイル: GraphPresenter.cs プロジェクト: ndb01/ApsimX
        /// <summary>
        /// Add regression line and stats to graph
        /// </summary>
        /// <param name="graphView">The graph to add line and stats to</param>
        /// <param name="stats">The regression stats</param>
        /// <param name="xAxis">The associated x axis</param>
        /// <param name="yAxis">The associated y axis</param>
        /// <param name="colour">The color to use</param>
        /// <param name="seriesIndex">The series index</param>
        private static void AddRegressionToGraph(IGraphView graphView,
                                                 MathUtilities.RegrStats stats,
                                                 Axis.AxisType xAxis, Axis.AxisType yAxis,
                                                 Color colour,
                                                 int seriesIndex)
        {
            if (stats != null)
            {
                double minimumX = graphView.AxisMinimum(xAxis);
                double maximumX = graphView.AxisMaximum(xAxis);
                double minimumY = graphView.AxisMinimum(yAxis);
                double maximumY = graphView.AxisMaximum(yAxis);

                double[] regressionX = new double[] { minimumX, maximumX };
                double[] regressionY = new double[] { stats.m *minimumX + stats.c, stats.m *maximumX + stats.c };
                graphView.DrawLineAndMarkers("", regressionX, regressionY,
                                             xAxis, yAxis, colour,
                                             Series.LineType.Solid, Series.MarkerType.None, true);

                // Show the 1:1 line
                double   lowestAxisScale  = Math.Min(minimumX, minimumY);
                double   largestAxisScale = Math.Max(maximumX, maximumY);
                double[] oneToOne         = new double[] { lowestAxisScale, largestAxisScale };
                graphView.DrawLineAndMarkers("", oneToOne, oneToOne,
                                             xAxis, yAxis, colour,
                                             Series.LineType.Dash, Series.MarkerType.None, true);

                // Draw the equation.
                double interval  = (largestAxisScale - lowestAxisScale) / 13;
                double yPosition = largestAxisScale - seriesIndex * interval;

                string equation = string.Format("y = {0:F2} x + {1:F2}, r2 = {2:F2}, n = {3:F0}\r\n" +
                                                "NSE = {4:F2}, ME = {5:F2}, MAE = {6:F2}\r\n" +
                                                "RSR = {7:F2}, RMSD = {8:F2}",
                                                new object[] { stats.m,
                                                               stats.c,
                                                               stats.R2,
                                                               stats.n,
                                                               stats.NSE,
                                                               stats.ME,
                                                               stats.MAE,
                                                               stats.RSR,
                                                               stats.RMSD });
                graphView.DrawText(equation, lowestAxisScale, yPosition, xAxis, yAxis, colour);
            }
        }
コード例 #3
0
ファイル: GraphPresenter.cs プロジェクト: ndb01/ApsimX
        /// <summary>
        /// Add in regression lines if necessary.
        /// </summary>
        private void AddRegressionLines()
        {
            int seriesIndex = 0;

            if (this.Graph.ShowRegressionLine)
            {
                // Get all x and y values.
                List <double> x = new List <double>();
                List <double> y = new List <double>();
                foreach (SeriesInfo seriesInfo in seriesMetadata)
                {
                    if (seriesInfo.X != null && seriesInfo.Y != null)
                    {
                        foreach (double value in seriesInfo.X)
                        {
                            x.Add(value);
                        }
                        foreach (double value in seriesInfo.Y)
                        {
                            y.Add(value);
                        }
                    }
                }

                MathUtilities.RegrStats stats = MathUtilities.CalcRegressionStats(x, y);
                AddRegressionToGraph(this.GraphView, stats, Axis.AxisType.Bottom, Axis.AxisType.Left,
                                     Color.Black, seriesIndex);
                seriesIndex++;
            }

            foreach (SeriesInfo seriesInfo in seriesMetadata)
            {
                if (seriesInfo.X != null && seriesInfo.Y != null && seriesInfo.series.ShowRegressionLine)
                {
                    MathUtilities.RegrStats stats = MathUtilities.CalcRegressionStats(seriesInfo.X, seriesInfo.Y);
                    if (stats != null)
                    {
                        AddRegressionToGraph(this.GraphView, stats, seriesInfo.series.XAxis, seriesInfo.series.YAxis, seriesInfo.Colour, seriesIndex);
                        seriesIndex++;
                    }
                }
            }
        }
コード例 #4
0
        /// <summary>Puts the regression line and 1:1 line on graph.</summary>
        /// <param name="definitions">The definitions.</param>
        /// <param name="x">The x data.</param>
        /// <param name="y">The y data.</param>
        /// <param name="colour">The colour of the regresion line.</param>
        /// <param name="title">The title to put in the legen.</param>
        private void PutRegressionLineOnGraph(List <SeriesDefinition> definitions, IEnumerable x, IEnumerable y,
                                              Color colour, string title)
        {
            MathUtilities.RegrStats stat = MathUtilities.CalcRegressionStats(title, y, x);
            if (stat != null)
            {
                stats.Add(stat);
                double minimumX         = MathUtilities.Min(x);
                double maximumX         = MathUtilities.Max(x);
                double minimumY         = MathUtilities.Min(y);
                double maximumY         = MathUtilities.Max(y);
                double lowestAxisScale  = Math.Min(minimumX, minimumY);
                double largestAxisScale = Math.Max(maximumX, maximumY);

                var regressionDefinition = new SeriesDefinition
                                               (title, colour,
                                               new double[] { minimumX, maximumX },
                                               new double[] { stat.Slope *minimumX + stat.Intercept, stat.Slope *maximumX + stat.Intercept });
                definitions.Add(regressionDefinition);
            }
        }
コード例 #5
0
        /// <summary>Puts the regression line and 1:1 line on graph.</summary>
        /// <param name="x">The x data.</param>
        /// <param name="y">The y data.</param>
        /// <param name="colour">The colour of the regresion line.</param>
        /// <param name="title">The title to put in the legen.</param>
        private SeriesDefinition PutRegressionLineOnGraph(IEnumerable x, IEnumerable y, Color colour, string title)
        {
            MathUtilities.RegrStats stat = MathUtilities.CalcRegressionStats(title, y, x);
            if (stat != null)
            {
                stats.Add(stat);
                double minimumX         = MathUtilities.Min(x);
                double maximumX         = MathUtilities.Max(x);
                double minimumY         = MathUtilities.Min(y);
                double maximumY         = MathUtilities.Max(y);
                double lowestAxisScale  = Math.Min(minimumX, minimumY);
                double largestAxisScale = Math.Max(maximumX, maximumY);

                var regressionDefinition = new SeriesDefinition
                                               (title, colour,
                                               new double[] { minimumX, maximumX },
                                               new double[] { stat.Slope *minimumX + stat.Intercept, stat.Slope *maximumX + stat.Intercept });
                return(regressionDefinition);
            }
            throw new Exception($"Unable to generate regression line for series {title} - there is no data");
        }
コード例 #6
0
ファイル: Tests.cs プロジェクト: hol353/ApsimX
        /// <summary>
        /// Run tests
        /// </summary>
        /// <param name="accept">If true, the stats from this run will be written to file as the accepted stats.</param>
        /// <param name="GUIrun">If true, do not raise an exception on test failure.</param>
        public void Test(bool accept = false, bool GUIrun = false)
        {
            PredictedObserved PO = Parent as PredictedObserved;
            if (PO == null)
                return;
            DataStore DS = PO.Parent as DataStore;
            MathUtilities.RegrStats[] stats;
            List<string> statNames = (new MathUtilities.RegrStats()).GetType().GetFields().Select(f => f.Name).ToList(); // use reflection, get names of stats available
            DataTable POtable = DS.GetData("*", PO.Name);
            List<string> columnNames;
            string sigIdent = "X";

            if (POtable == null)
            {
                object sim = PO.Parent;
                while (sim as Simulations == null)
                    sim = ((Model)sim).Parent;

                throw new ApsimXException(this, "Could not find PO table in " + (sim != null ? ((Simulations)sim).FileName : "<unknown>") + ". Has the simulation been run?");
            }
            columnNames = POtable.Columns.Cast<DataColumn>().Select(c => c.ColumnName).ToList(); //get list of column names
            columnNames = columnNames.Where(c => c.Contains("Observed")).ToList(); //filter names that are not pred/obs pairs
            for (int i = 0; i < columnNames.Count; i++)
                columnNames[i] = columnNames[i].Replace("Observed.", "");
            columnNames.Sort(); //ensure column names are always in the same order
            stats = new MathUtilities.RegrStats[columnNames.Count];
            List<double> x = new List<double>();
            List<double> y = new List<double>();
            string xstr, ystr;
            double xres;
            double yres;

            for (int c = 0; c < columnNames.Count; c++) //on each P/O column pair
            {
                x.Clear();
                y.Clear();
                foreach (DataRow row in POtable.Rows)
                {
                    xstr = row["Observed." + columnNames[c]].ToString();
                    ystr = row["Predicted." + columnNames[c]].ToString();
                    if (Double.TryParse(xstr, out xres) && Double.TryParse(ystr, out yres))
                    {
                        x.Add(xres);
                        y.Add(yres);
                    }
                }
                if (x.Count == 0 || y.Count == 0)
                    continue;

                stats[c] = MathUtilities.CalcRegressionStats(columnNames[c], y, x);
            }

            //remove any null stats which can occur from non-numeric columns such as dates
            List<MathUtilities.RegrStats> list = new List<MathUtilities.RegrStats>(stats);
            list.RemoveAll(l => l == null);
            stats = list.ToArray();

            //remove entries from column names
            for (int i = columnNames.Count() - 1; i >= 0; i--)
            {
                bool found = false;
                for (int j = 0; j < stats.Count(); j++)
                {
                    if (columnNames[i] == stats[j].Name)
                    {
                        found = true;
                        break;
                    }
                }
                if (!found)
                    columnNames.RemoveAt(i);
            }

            //turn stats array into a DataTable
            //first, check if there is already an AcceptedStats array, create if not.
            //If the names don't match, then use current stats as user has dragged
            //an already existing Test to a new node.
            if (AcceptedStats == null || POName != PO.Name)
            {
                POName = PO.Name;
                AcceptedStats = stats;
                AcceptedStatsName = StringUtilities.Build(statNames, " ");
            }

            //then make sure the names and order of the accepted stats are the same as the new ones.
            if (StringUtilities.Build(statNames, " ") != AcceptedStatsName)
                throw new ApsimXException(this, "Names, number or order of accepted stats do not match class MathUtilities.RegrStats. The class has probably changed.");

            Table = new DataTable("StatTests");
            Table.Columns.Add("Name", typeof(string));
            Table.Columns.Add("Variable", typeof(string));
            Table.Columns.Add("Test", typeof(string));
            Table.Columns.Add("Accepted", typeof(double));
            Table.Columns.Add("Current", typeof(double));
            Table.Columns.Add("Difference", typeof(double));
            Table.Columns.Add("Fail?", typeof(string));

            double accepted;
            double current;
            DataTable AcceptedTable = Table.Copy();
            DataTable CurrentTable = Table.Copy();

            //accepted table
            for (int i = 0; i < AcceptedStats.Count(); i++)
                for (int j = 1; j < statNames.Count; j++) //start at 1; we don't want Name field.
                {
                    accepted = Convert.ToDouble(AcceptedStats[i].GetType().GetField(statNames[j]).GetValue(AcceptedStats[i]));
                    AcceptedTable.Rows.Add(PO.Name,
                                    AcceptedStats[i].Name,
                                    statNames[j],
                                    accepted,
                                    null,
                                    null,
                                    null);
                }

            //current table
            Table = AcceptedTable.Copy();
            int rowIndex = 0;
            for (int i = 0; i < stats.Count(); i++)
                for (int j = 1; j < statNames.Count; j++) //start at 1; we don't want Name field.
                {
                    current = Convert.ToDouble(stats[i].GetType().GetField(statNames[j]).GetValue(stats[i]));
                    CurrentTable.Rows.Add(PO.Name,
                                    stats[i].Name,
                                    statNames[j],
                                    null,
                                    current,
                                    null,
                                    null);
                    Table.Rows[rowIndex]["Current"] = current;
                    rowIndex++;
                }

            //Merge overwrites rows, so add the correct data back in
            foreach(DataRow row in Table.Rows)
            {
                DataRow[] rowAccepted = AcceptedTable.Select("Name = '" + row["Name"] + "' AND Variable = '" + row["Variable"] + "' AND Test = '" + row["Test"] + "'");
                DataRow[] rowCurrent  = CurrentTable.Select ("Name = '" + row["Name"] + "' AND Variable = '" + row["Variable"] + "' AND Test = '" + row["Test"] + "'");

                if (rowAccepted.Count() == 0)
                    row["Accepted"] = DBNull.Value;
                else
                    row["Accepted"] = rowAccepted[0]["Accepted"];

                if (rowCurrent.Count() == 0)
                    row["Current"] = DBNull.Value;
                else
                    row["Current"] = rowCurrent[0]["Current"];

                if (row["Accepted"] != DBNull.Value && row["Current"] != DBNull.Value)
                {
                    row["Difference"] = Convert.ToDouble(row["Current"]) - Convert.ToDouble(row["Accepted"]);
                    row["Fail?"] = Math.Abs(Convert.ToDouble(row["Difference"])) > Math.Abs(Convert.ToDouble(row["Accepted"])) * 0.01 ? sigIdent : " ";
                }
                else
                {
                    row["Difference"] = DBNull.Value;
                    row["Fail?"] = sigIdent;
                }
            }
            //Tables could be large so free the memory.
            AcceptedTable = null;
            CurrentTable = null;

            if (accept)
                AcceptedStats = stats;
            else
            {
                foreach (DataRow row in Table.Rows)
                    if (row["Fail?"].ToString().Equals(sigIdent))
                    {
                        if (!GUIrun)
                        {
                            object sim = PO.Parent;
                            while (sim as Simulations == null)
                                sim = ((Model)sim).Parent;

                            throw new ApsimXException(this, "Significant differences found during regression testing of " + PO.Name + " in " + (sim != null ? ((Simulations)sim).FileName : "<unknown>"));
                        }
                    }
            }
        }
コード例 #7
0
        /// <summary>
        /// Run tests
        /// </summary>
        /// <param name="accept">If true, the stats from this run will be written to file as the accepted stats.</param>
        /// <param name="GUIrun">If true, do not raise an exception on test failure.</param>
        public void Test(bool accept = false, bool GUIrun = false)
        {
            PredictedObserved PO = Parent as PredictedObserved;

            if (PO == null)
            {
                return;
            }
            DataStore DS = PO.Parent as DataStore;

            MathUtilities.RegrStats[] stats;
            List <string>             statNames = (new MathUtilities.RegrStats()).GetType().GetFields().Select(f => f.Name).ToList(); // use reflection, get names of stats available
            DataTable     POtable = DS.GetData("*", PO.Name);
            List <string> columnNames;
            string        sigIdent = "X";

            if (POtable == null)
            {
                object sim = PO.Parent;
                while (sim as Simulations == null)
                {
                    sim = ((Model)sim).Parent;
                }

                throw new ApsimXException(this, "Could not find PO table in " + (sim != null ? ((Simulations)sim).FileName : "<unknown>") + ". Has the simulation been run?");
            }
            columnNames = POtable.Columns.Cast <DataColumn>().Select(c => c.ColumnName).ToList(); //get list of column names
            columnNames = columnNames.Where(c => c.Contains("Observed")).ToList();                //filter names that are not pred/obs pairs
            for (int i = 0; i < columnNames.Count; i++)
            {
                columnNames[i] = columnNames[i].Replace("Observed.", "");
            }
            columnNames.Sort(); //ensure column names are always in the same order
            stats = new MathUtilities.RegrStats[columnNames.Count];
            List <double> x = new List <double>();
            List <double> y = new List <double>();
            string        xstr, ystr;
            double        xres;
            double        yres;

            for (int c = 0; c < columnNames.Count; c++) //on each P/O column pair
            {
                x.Clear();
                y.Clear();
                foreach (DataRow row in POtable.Rows)
                {
                    xstr = row["Observed." + columnNames[c]].ToString();
                    ystr = row["Predicted." + columnNames[c]].ToString();
                    if (Double.TryParse(xstr, out xres) && Double.TryParse(ystr, out yres))
                    {
                        x.Add(xres);
                        y.Add(yres);
                    }
                }
                if (x.Count == 0 || y.Count == 0)
                {
                    continue;
                }

                stats[c] = MathUtilities.CalcRegressionStats(columnNames[c], y, x);
            }

            //remove any null stats which can occur from non-numeric columns such as dates
            List <MathUtilities.RegrStats> list = new List <MathUtilities.RegrStats>(stats);

            list.RemoveAll(l => l == null);
            stats = list.ToArray();

            //remove entries from column names
            for (int i = columnNames.Count() - 1; i >= 0; i--)
            {
                bool found = false;
                for (int j = 0; j < stats.Count(); j++)
                {
                    if (columnNames[i] == stats[j].Name)
                    {
                        found = true;
                        break;
                    }
                }
                if (!found)
                {
                    columnNames.RemoveAt(i);
                }
            }

            //turn stats array into a DataTable
            //first, check if there is already an AcceptedStats array, create if not.
            //If the names don't match, then use current stats as user has dragged
            //an already existing Test to a new node.
            if (AcceptedStats == null || POName != PO.Name)
            {
                POName            = PO.Name;
                AcceptedStats     = stats;
                AcceptedStatsName = StringUtilities.Build(statNames, " ");
            }

            //then make sure the names and order of the accepted stats are the same as the new ones.
            if (StringUtilities.Build(statNames, " ") != AcceptedStatsName)
            {
                throw new ApsimXException(this, "Names, number or order of accepted stats do not match class MathUtilities.RegrStats. The class has probably changed.");
            }

            Table = new DataTable("StatTests");
            Table.Columns.Add("Name", typeof(string));
            Table.Columns.Add("Variable", typeof(string));
            Table.Columns.Add("Test", typeof(string));
            Table.Columns.Add("Accepted", typeof(double));
            Table.Columns.Add("Current", typeof(double));
            Table.Columns.Add("Difference", typeof(double));
            Table.Columns.Add("Fail?", typeof(string));

            double    accepted;
            double    current;
            DataTable AcceptedTable             = Table.Copy();
            DataTable CurrentTable              = Table.Copy();

            //accepted table
            for (int i = 0; i < AcceptedStats.Count(); i++)
            {
                for (int j = 1; j < statNames.Count; j++) //start at 1; we don't want Name field.
                {
                    accepted = Convert.ToDouble(AcceptedStats[i].GetType().GetField(statNames[j]).GetValue(AcceptedStats[i]));
                    AcceptedTable.Rows.Add(PO.Name,
                                           AcceptedStats[i].Name,
                                           statNames[j],
                                           accepted,
                                           null,
                                           null,
                                           null);
                }
            }

            //current table
            Table = AcceptedTable.Copy();
            int rowIndex = 0;

            for (int i = 0; i < stats.Count(); i++)
            {
                for (int j = 1; j < statNames.Count; j++) //start at 1; we don't want Name field.
                {
                    current = Convert.ToDouble(stats[i].GetType().GetField(statNames[j]).GetValue(stats[i]));
                    CurrentTable.Rows.Add(PO.Name,
                                          stats[i].Name,
                                          statNames[j],
                                          null,
                                          current,
                                          null,
                                          null);
                    Table.Rows[rowIndex]["Current"] = current;
                    rowIndex++;
                }
            }

            //Merge overwrites rows, so add the correct data back in
            foreach (DataRow row in Table.Rows)
            {
                DataRow[] rowAccepted = AcceptedTable.Select("Name = '" + row["Name"] + "' AND Variable = '" + row["Variable"] + "' AND Test = '" + row["Test"] + "'");
                DataRow[] rowCurrent  = CurrentTable.Select("Name = '" + row["Name"] + "' AND Variable = '" + row["Variable"] + "' AND Test = '" + row["Test"] + "'");

                if (rowAccepted.Count() == 0)
                {
                    row["Accepted"] = DBNull.Value;
                }
                else
                {
                    row["Accepted"] = rowAccepted[0]["Accepted"];
                }

                if (rowCurrent.Count() == 0)
                {
                    row["Current"] = DBNull.Value;
                }
                else
                {
                    row["Current"] = rowCurrent[0]["Current"];
                }

                if (row["Accepted"] != DBNull.Value && row["Current"] != DBNull.Value)
                {
                    row["Difference"] = Convert.ToDouble(row["Current"]) - Convert.ToDouble(row["Accepted"]);
                    row["Fail?"]      = Math.Abs(Convert.ToDouble(row["Difference"])) > Math.Abs(Convert.ToDouble(row["Accepted"])) * 0.01 ? sigIdent : " ";
                }
                else
                {
                    row["Difference"] = DBNull.Value;
                    row["Fail?"]      = sigIdent;
                }
            }
            //Tables could be large so free the memory.
            AcceptedTable = null;
            CurrentTable  = null;

            if (accept)
            {
                AcceptedStats = stats;
            }
            else
            {
                foreach (DataRow row in Table.Rows)
                {
                    if (row["Fail?"].ToString().Equals(sigIdent))
                    {
                        if (!GUIrun)
                        {
                            object sim = PO.Parent;
                            while (sim as Simulations == null)
                            {
                                sim = ((Model)sim).Parent;
                            }

                            throw new ApsimXException(this, "Significant differences found during regression testing of " + PO.Name + " in " + (sim != null ? ((Simulations)sim).FileName : "<unknown>"));
                        }
                    }
                }
            }
        }
コード例 #8
0
 public void TestExponentialFit()
 {
     double[] expX = x.Select(xi => 0.5 * Math.Exp(xi * 2.0)).ToArray();
     MathUtilities.RegrStats stats = RegressionUtilities.ExponentialFitStats(x, expX);
     Assert.That(MathUtilities.FloatsAreEqual(stats.R2, 1.0), "Exponential regression test has failed. r2=" + stats.R2);
 }
コード例 #9
0
 public void TestPolyFit()
 {
     double[] xPoly5 = x.Select(xi => Math.Pow(xi, 5)).ToArray();
     MathUtilities.RegrStats stats = RegressionUtilities.PolyFitStats(x, xPoly5, 5);
     Assert.That(MathUtilities.FloatsAreEqual(stats.R2, 1.0), "Polynomial regression test has failed. r2=" + stats.R2);
 }
コード例 #10
0
        public static DataTable CalculateStatsOnPredictedObservedValues(DataTable POtable)
        {
            DataTable currentTable = CreateTestsStatsTable();

            try
            {
                Utilities.WriteToLogFile("       1/4. CalculateStatsOnPredictedObservedValues:  Start processing");
                MathUtilities.RegrStats[] stats;
                List <string>             statNames = (new MathUtilities.RegrStats()).GetType().GetFields().Select(f => f.Name).ToList(); // use reflection, get names of stats available

                var columnNames = (from row in POtable.AsEnumerable() select row.Field <string>("ValueName")).Distinct().ToList();

                //columnNames.Sort(); //ensure column names are always in the same order
                stats = new MathUtilities.RegrStats[columnNames.Count];

                List <double> x = new List <double>();
                List <double> y = new List <double>();
                string        valueName = string.Empty, xstr, ystr;
                int           c             = 0;
                string        holdValueName = POtable.Rows[0]["ValueName"].ToString();

                //loop through our current POtable and collate the necessary data to calculate stats for current PredictedObservedValues
                foreach (DataRow row in POtable.Rows) //on each P/O column pair
                {
                    valueName = row["ValueName"].ToString();
                    if (valueName != holdValueName)
                    {
                        if (x.Count != 0 || y.Count != 0)
                        {
                            stats[c] = MathUtilities.CalcRegressionStats(holdValueName, y, x);
                            c       += 1;
                        }
                        holdValueName = valueName;
                        x.Clear();
                        y.Clear();
                    }

                    Double xres, yres;
                    xstr = row["ObservedValue"].ToString();
                    ystr = row["PredictedValue"].ToString();
                    if ((Double.TryParse(xstr, out xres)) && (Double.TryParse(ystr, out yres)))
                    {
                        x.Add(xres);
                        y.Add(yres);
                    }
                }
                Utilities.WriteToLogFile("       2/4. CalculateStatsOnPredictedObservedValues:  CalcRegressionStats");
                if (x.Count != 0 || y.Count != 0)
                {
                    stats[c] = MathUtilities.CalcRegressionStats(holdValueName, y, x);
                }


                //remove any null stats which can occur from non-numeric columns such as dates
                List <MathUtilities.RegrStats> list = new List <MathUtilities.RegrStats>(stats);
                list.RemoveAll(l => l == null);
                stats = list.ToArray();

                //remove entries from column names
                for (int i = columnNames.Count() - 1; i >= 0; i--)
                {
                    bool found = false;
                    for (int j = 0; j < stats.Count(); j++)
                    {
                        if (columnNames[i].ToString() == stats[j].Name)
                        {
                            found = true;
                            break;
                        }
                    }
                    if (!found)
                    {
                        columnNames.RemoveAt(i);
                    }
                }

                double  current;
                DataRow tRow;
                bool    hasValue;
                string  variable, test, statValue, helperStr;

                Utilities.WriteToLogFile("       3/4. CalculateStatsOnPredictedObservedValues:  Loop through stats and put them into a datatable");
                //Loop through stats and put them into a datatable
                int rowIndex = 0;
                for (int i = 0; i < stats.Count(); i++)
                {
                    //for (int j = 1; j < statNames.Count; j++) //start at 1; we don't want Name field.
                    for (int j = 0; j < statNames.Count; j++) //need to ensure wthat we dont do 'Name'
                    {
                        //current = Math.Round(Convert.ToDouble(stats[i].GetType().GetField(statNames[j]).GetValue(stats[i])), 6);
                        //CurrentTable.Rows.Add(PO_Name, stats[i].Name, statNames[j], null, current, null, null);
                        test = statNames[j];
                        if (test != "Name")
                        {
                            variable  = stats[i].Name;
                            statValue = stats[i].GetType().GetField(statNames[j]).GetValue(stats[i]).ToString();
                            helperStr = "Variable: " + variable + ", Test: " + test + ", Value: " + statValue;

                            //CurrentTable.Rows.Add(PO_Name, stats[i].Name, statNames[j], null, current, null, null);
                            tRow             = currentTable.NewRow();
                            tRow["Variable"] = variable;
                            tRow["Test"]     = test;

                            hasValue = true;
                            try
                            {
                                current = Math.Round(Convert.ToDouble(statValue), 6);
                                if (double.IsNaN(current) == true)
                                {
                                    hasValue = false;
                                }
                                if (double.IsInfinity(current) == true)
                                {
                                    hasValue = false;
                                }
                                if (hasValue == true)
                                {
                                    tRow["Current"] = current;
                                    //currentTable.Rows[rowIndex]["Current"] = current;
                                }
                            }
                            catch (Exception)
                            {
                                Utilities.WriteToLogFile("    ERROR in DoValidationTest: Unable to convert:" + helperStr);
                            }
                            currentTable.Rows.Add(tRow);
                            rowIndex++;
                        }
                    }
                }
                Utilities.WriteToLogFile("       4/4. CalculateStatsOnPredictedObservedValues:  completed");
            }
            catch (Exception ex)
            {
                //throw new Exception("ERROR in CalculateStatsOnPredictedObservedValues:  Unable to process Test Data: " + ex.Message.ToString());
                Utilities.WriteToLogFile("     ERROR in CalculateStatsOnPredictedObservedValues:  Unable to process Test Data: " + ex.Message.ToString());
            }
            return(currentTable);
        }
コード例 #11
0
        public const double Threshold = 0.01; // 1%

        /// <summary>
        /// Run tests
        /// </summary>
        public static DataTable DoValidationTest(string PO_Name, DataTable POtable, DataTable acceptedStats)
        {
            DataTable currentTable = CreateTestsStatsTable();
            string    helperStr    = string.Empty;

            try
            {
                MathUtilities.RegrStats[] stats;
                List <string>             statNames = (new MathUtilities.RegrStats()).GetType().GetFields().Select(f => f.Name).ToList(); // use reflection, get names of stats available
                List <string>             columnNames;

                Utilities.WriteToLogFile("    1/8. DoValidationTest: get the column names");
                columnNames = POtable.Columns.Cast <DataColumn>().Select(c => c.ColumnName).ToList(); //get list of column names
                columnNames = columnNames.Where(c => c.Contains("Observed")).ToList();                //filter names that are not pred/obs pairs
                for (int i = 0; i < columnNames.Count; i++)
                {
                    columnNames[i] = columnNames[i].Replace("Observed.", "");
                }

                columnNames.Sort(); //ensure column names are always in the same order
                stats = new MathUtilities.RegrStats[columnNames.Count];
                List <double> x = new List <double>();
                List <double> y = new List <double>();
                string        xstr, ystr;
                Double        xres, yres;

                Utilities.WriteToLogFile("    2/8. DoValidationTest: get the predicted observed values and calc regression stats");
                for (int c = 0; c < columnNames.Count; c++) //on each P/O column pair
                {
                    x.Clear();
                    y.Clear();
                    foreach (DataRow row in POtable.Rows)
                    {
                        xstr = row["Observed." + columnNames[c]].ToString();
                        ystr = row["Predicted." + columnNames[c]].ToString();
                        if ((Double.TryParse(xstr, out xres)) && (Double.TryParse(ystr, out yres)))
                        {
                            x.Add(xres);
                            y.Add(yres);
                        }
                    }
                    if (x.Count == 0 || y.Count == 0)
                    {
                        continue;
                    }

                    stats[c] = MathUtilities.CalcRegressionStats(columnNames[c], y, x);
                }

                //remove any null stats which can occur from non-numeric columns such as dates
                Utilities.WriteToLogFile("    3/8. DoValidationTest: remove any null stats which can occur from non-numeric columns such as dates");
                List <MathUtilities.RegrStats> list = new List <MathUtilities.RegrStats>(stats);
                list.RemoveAll(l => l == null);
                stats = list.ToArray();

                //remove entries from column names
                Utilities.WriteToLogFile("    4/8. DoValidationTest: remove entries from column names");
                for (int i = columnNames.Count() - 1; i >= 0; i--)
                {
                    bool found = false;
                    for (int j = 0; j < stats.Count(); j++)
                    {
                        if (columnNames[i] == stats[j].Name)
                        {
                            found = true;
                            break;
                        }
                    }
                    if (!found)
                    {
                        columnNames.RemoveAt(i);
                    }
                }

                double  current;
                DataRow tRow;
                bool    hasValue;

                string variable, test, statValue;
                //Loop through stats and put them into a datatable
                Utilities.WriteToLogFile("    5/8. DoValidationTest: Loop through stats and put them into a datatable ");

                int rowIndex = 0;
                for (int i = 0; i < stats.Count(); i++)
                {
                    //for (int j = 1; j < statNames.Count; j++) //start at 1; we don't want Name field.
                    for (int j = 0; j < statNames.Count; j++) //need to ensure we don't do 'Name'
                    {
                        test = statNames[j];
                        if (test != "Name")
                        {
                            variable  = stats[i].Name;
                            statValue = stats[i].GetType().GetField(statNames[j]).GetValue(stats[i]).ToString();
                            helperStr = "Variable: " + variable + ", Test: " + test + ", Value: " + statValue;

                            //CurrentTable.Rows.Add(PO_Name, stats[i].Name, statNames[j], null, current, null, null);
                            tRow             = currentTable.NewRow();
                            tRow["Variable"] = variable;
                            tRow["Test"]     = test;

                            hasValue = true;
                            try
                            {
                                current = Math.Round(Convert.ToDouble(statValue), 6);
                                if (double.IsNaN(current) == true)
                                {
                                    hasValue = false;
                                }
                                if (double.IsInfinity(current) == true)
                                {
                                    hasValue = false;
                                }
                                if (hasValue == true)
                                {
                                    tRow["Current"] = current;
                                    //currentTable.Rows[rowIndex]["Current"] = current;
                                }
                            }
                            catch (Exception)
                            {
                                Utilities.WriteToLogFile("    ERROR in DoValidationTest: Unable to convert:" + helperStr);
                            }

                            currentTable.Rows.Add(tRow);
                            rowIndex++;
                        }
                    }
                }
                helperStr = string.Empty;
                Utilities.WriteToLogFile("    6/8. DoValidationTest: Loop through stats and put them into a datatable - Completed");

                //Now merge this with out Accepted Table
                //Now add the comparison columns and determine values
                Utilities.WriteToLogFile("    7/8. DoValidationTest: MergeAndCompareAcceptedAgainstCurrent ");
                MergeAndCompareAcceptedAgainstCurrent(ref currentTable, acceptedStats);

                //Need to ensure that the order of the columns in the Datatable matches our table type
                Utilities.WriteToLogFile("    8/8. DoValidationTest: OrderCurrentTableforTableType ");
                OrderCurrentTableforTableType(ref currentTable);

                Utilities.WriteToLogFile("         DoValidationTest: complete");
            }
            catch (Exception ex)
            {
                //throw new Exception("ERROR in DoValidationTest:: " + ex.Message.ToString());
                Utilities.WriteToLogFile("    ERROR in DoValidationTest: " + helperStr + " - " + ex.Message.ToString());
            }
            return(currentTable);
        }