Пример #1
0
        //this is asych for the calling Task.WhenAll
        //but does not necessarily need internal asych awaits
        public async Task RunAlgorithmAsync(List <List <double> > data)
        {
            try
            {
                //minimal data requirement is first five cols
                if (_colNames.Count() < 5 ||
                    _mathTerms.Count() == 0)
                {
                    ErrorMessage = "Regression requires at least one dependent variable and one independent variable.";
                    return;
                }
                if (data.Count() < 5)
                {
                    //185 same as other analysis
                    ErrorMessage = "Regression requires at least 2 rows of observed data and 3 rows of scoring data.";
                    return;
                }
                //convert data to a Math.Net Matrix
                //v185 uses same ci technique as algos 2,3 and 4 -last 3 rows are used to generate ci
                List <List <double> > dataci = data.Skip(data.Count - _scoreRows).ToList();
                data.Reverse();
                List <List <double> > dataobs = data.Skip(_scoreRows).ToList();
                dataobs.Reverse();
                //actual observed values
                Vector <double> y  = Shared.GetYData(dataobs);
                Matrix <double> x  = Shared.GetDoubleMatrix(dataobs, _colNames, _depColNames);
                Matrix <double> ci = Shared.GetDoubleMatrix(dataci, _colNames, _depColNames);

                //model expected values - get the coefficents
                //use normal equations regression
                Vector <double> p = MultipleRegression.NormalEquations(x, y);
                //but note that this runs without errors in more cases but still does not give good results
                //Vector<double> p = MultipleRegression.QR(x, y);

                if (p.Count() != ci.Row(_scoreRows - 1).Count())
                {
                    //185 same as other analysis
                    ErrorMessage = "The scoring and training datasets have different numbers of columns.";
                    return;
                }
                //get the predicted yhats
                Vector <double> yhat = GetYHatandSetQTPred(y.Count, x, p, ci.Row(_scoreRows - 1).ToArray());
                //get the durbin-watson d statistic
                double d   = GetDurbinWatson(y, yhat);
                double SSE = 0;
                //sum of the square of the error (between the predicted, p, and observed, y);
                SSE = Distance.SSD(yhat, y);
                double rSquared = GoodnessOfFit.RSquared(yhat, y);
                //sum of the square of the regression (between the predicted, p, and observed mean, statsY.Mean);
                double SSR = 0;
                for (int i = 0; i < yhat.Count(); i++)
                {
                    SSR += Math.Pow((yhat[i] - y.Mean()), 2);
                }
                //set joint vars properties
                //degrees freedom
                double dfR         = x.ColumnCount - 1;
                double dfE         = x.RowCount - x.ColumnCount;
                int    idfR        = x.ColumnCount - 1;
                int    idfE        = x.RowCount - x.ColumnCount;
                double s2          = SSE / dfE;
                double s           = Math.Sqrt(s2);
                double MSR         = SSR / dfR;
                double MSE         = SSE / dfE;
                double FValue      = MSR / MSE;
                double adjRSquared = 1 - ((x.RowCount - 1) * (MSE / (SSE + SSR)));
                double pValue      = Shared.GetPValueForFDist(idfR, idfE, FValue);

                //correct 2 tailed t test
                //double TCritialValue = ExcelFunctions.TInv(0.05, idfE);
                //so do this
                double dbCI           = CalculatorHelpers.GetConfidenceIntervalProb(_confidenceInt);
                double tCriticalValue = ExcelFunctions.TInv(dbCI, idfE);
                //set each coeff properties
                //coeffs st error
                //use matrix math to get the standard error of coefficients
                Matrix <double> xt = x.Transpose();
                //matrix x'x
                Matrix <double> xx       = xt.Multiply(x);
                Matrix <double> xxminus1 = xx.Inverse();

                double   sxx  = 0;
                double[] xiSE = new double[x.ColumnCount];
                //coeff tstats
                double[] xiT = new double[x.ColumnCount];
                //lower value for pvalue
                double[] xiP = new double[x.ColumnCount];
                for (int i = 0; i < x.ColumnCount; i++)
                {
                    //use the matrix techniques shown on p 717 of Mendenhall and Sincich
                    sxx     = s * Math.Sqrt(xxminus1.Column(i)[i]);
                    xiSE[i] = sxx;
                    xiT[i]  = p[i] / sxx;
                    xiP[i]  = Shared.GetPValueForTDist(idfE, xiT[i], 0, 1);
                }
                double FCriticalValue    = 0;
                string FGreaterFCritical = string.Empty;
                if (_subalgorithm == Calculator1.MATH_SUBTYPES.subalgorithm8.ToString())
                {
                    //anova regression
                    //anova critical fvalue test
                    //FCriticalValue = ExcelFunctions.FInv(1 - _confidenceInt, idfR, idfE);
                    FCriticalValue    = ExcelFunctions.FInv(dbCI, idfR, idfE);
                    FGreaterFCritical = (FValue > FCriticalValue) ? "true" : "false";
                    SetAnovaIntervals(0, p, xiSE, tCriticalValue);
                    SetAnovaIntervals(1, p, xiSE, tCriticalValue);
                    SetAnovaIntervals(2, p, xiSE, tCriticalValue);
                }
                else
                {
                    //set QTM ci and pi intervals
                    SetQTIntervals(0, s, xxminus1, ci.Row(_scoreRows - 1).ToArray(), p, tCriticalValue);
                    SetQTIntervals(1, s, xxminus1, ci.Row(_scoreRows - 2).ToArray(), p, tCriticalValue);
                    SetQTIntervals(2, s, xxminus1, ci.Row(_scoreRows - 3).ToArray(), p, tCriticalValue);
                }
                //add the data to a string builder
                StringBuilder sb = new StringBuilder();
                sb.AppendLine("regression results");
                //dep var has to be in the 4 column always
                string sLine = string.Concat("dependent variable:  ", _colNames[3]);
                sb.AppendLine(sLine);
                string[] cols = new string[] { "source", "df", "SS", "MS" };
                sb.AppendLine(Shared.GetLine(cols, true));
                cols = new string[] { "model", dfR.ToString("F0"), SSR.ToString("F4"), MSR.ToString("F4") };
                sb.AppendLine(Shared.GetLine(cols, false));
                cols = new string[] { "error  ", dfE.ToString("F0"), SSE.ToString("F4"), MSE.ToString("F4") };
                sb.AppendLine(Shared.GetLine(cols, false));
                cols = new string[] { "total    ", (dfR + dfE).ToString("F0"), (SSR + SSE).ToString("F4") };
                sb.AppendLine(Shared.GetLine(cols, false));
                sb.AppendLine(string.Empty);
                cols = new string[] { "R-squared", rSquared.ToString("F4"), "Adj R-squared", adjRSquared.ToString("F4") };
                sb.AppendLine(Shared.GetLine(cols, false));
                cols = new string[] { "F value", FValue.ToString("F4"), "prob > F", pValue.ToString("F4") };
                sb.AppendLine(Shared.GetLine(cols, false));
                sb.AppendLine(string.Empty);
                cols = new string[] { GetName("variable"), "coefficient", "stand error", "T-ratio", "prob > T" };
                sb.AppendLine(Shared.GetLine(cols, true));
                for (int i = 0; i < p.Count(); i++)
                {
                    if (i == 0)
                    {
                        cols = new string[] { GetName(_depColNames[i]), p[i].ToString("F5"), xiSE[i].ToString("F4"), xiT[i].ToString("F4"), xiP[i].ToString("F4") };
                        sb.AppendLine(Shared.GetLine(cols, false));
                    }
                    else
                    {
                        cols = new string[] { GetName(_depColNames[i]), p[i].ToString("F5"), xiSE[i].ToString("F4"), xiT[i].ToString("F4"), xiP[i].ToString("F4") };
                        sb.AppendLine(Shared.GetLine(cols, false));
                    }
                }
                cols = new string[] { "durbin-watson: ", d.ToString("F4") };
                sb.AppendLine(Shared.GetLine(cols, false));
                if (_subalgorithm == Calculator1.MATH_SUBTYPES.subalgorithm8.ToString())
                {
                    cols = new string[] { "F Critical Value", FCriticalValue.ToString("F5"), "F > F Critical", FGreaterFCritical };
                    sb.AppendLine(Shared.GetLine(cols, true));
                    cols = new string[] { "estimate", "predicted", string.Concat("lower ", _confidenceInt.ToString(), "%"), string.Concat("upper ", _confidenceInt.ToString(), "%") };
                    sb.AppendLine(Shared.GetLine(cols, true));
                    cols = new string[] { "Col 0 Mean CI ", QTPredicted.ToString("F4"), QTL.ToString("F4"), QTU.ToString("F4") };
                    sb.AppendLine(Shared.GetLine(cols, false));
                    cols = new string[] { "Col 1 - 0 Mean CI ", QTPredicted10.ToString("F4"), QTL10.ToString("F4"), QTU10.ToString("F4") };
                    sb.AppendLine(Shared.GetLine(cols, false));
                    cols = new string[] { "Col 2 - 0 Mean CI ", QTPredicted20.ToString("F4"), QTL20.ToString("F4"), QTU20.ToString("F4") };
                    sb.AppendLine(Shared.GetLine(cols, false));
                }
                else
                {
                    cols = new string[] { "estimate", "predicted", string.Concat("lower ", _confidenceInt.ToString(), "%"), string.Concat("upper ", _confidenceInt.ToString(), "%") };
                    sb.AppendLine(Shared.GetLine(cols, true));
                    cols = new string[] { "QTM CI ", QTPredicted.ToString("F4"), QTL.ToString("F4"), QTU.ToString("F4") };
                    sb.AppendLine(Shared.GetLine(cols, false));
                    cols = new string[] { "QTM PI ", QTPredicted.ToString("F4"), (QTPredicted - QTPI).ToString("F4"), (QTPredicted + QTPI).ToString("F4") };
                    sb.AppendLine(Shared.GetLine(cols, false));
                    string sRow = string.Concat("row ", data.Count - 2);
                    cols = new string[] { sRow };
                    sb.AppendLine(Shared.GetLine(cols, true));
                    cols = new string[] { "CI ", QTPredicted10.ToString("F4"), QTL10.ToString("F4"), QTU10.ToString("F4") };
                    sb.AppendLine(Shared.GetLine(cols, false));
                    cols = new string[] { "PI ", QTPredicted10.ToString("F4"), (QTPredicted10 - QTPI10).ToString("F4"), (QTPredicted10 + QTPI10).ToString("F4") };
                    sb.AppendLine(Shared.GetLine(cols, false));
                    sRow = string.Concat("row ", data.Count - 1);
                    cols = new string[] { sRow };
                    sb.AppendLine(Shared.GetLine(cols, true));
                    cols = new string[] { "CI ", QTPredicted20.ToString("F4"), QTL20.ToString("F4"), QTU20.ToString("F4") };
                    sb.AppendLine(Shared.GetLine(cols, false));
                    cols = new string[] { "PI ", QTPredicted20.ToString("F4"), (QTPredicted20 - QTPI20).ToString("F4"), (QTPredicted20 + QTPI20).ToString("F4") };
                    sb.AppendLine(Shared.GetLine(cols, false));
                }
                if (this.MathResult.ToLower().StartsWith("http"))
                {
                    string sError    = string.Empty;
                    bool   bHasSaved = CalculatorHelpers.SaveTextInURI(
                        _params.ExtensionDocToCalcURI, sb.ToString(), this.MathResult, out sError);
                    if (!string.IsNullOrEmpty(sError))
                    {
                        this.MathResult += sError;
                    }
                }
                else
                {
                    this.MathResult = sb.ToString();
                }
            }
            catch (Exception ex)
            {
                this.ErrorMessage = ex.Message;
            }
        }
Пример #2
0
        //this is asych for the calling Task.WhenAll
        //but does not necessarily need internal asych awaits
        public async Task <bool> RunAlgorithmAsync(List <List <double> > data)
        {
            bool bHasCalculations = false;

            try
            {
                //minimal data requirement is first five cols
                if (_colNames.Count() < 5 ||
                    _mathTerms.Count() == 0)
                {
                    ErrorMessage = "Complete randomized anova requires at least 1 dependent variable and 1 independent variable. Randomized block and factorial anovas require at least 2 independent variables.";
                    return(bHasCalculations);
                }
                if (data.Count() < 5)
                {
                    //185 same as other analysis
                    ErrorMessage = "Anova requires at least 2 rows of observed data and 3 rows of scoring data.";
                    return(bHasCalculations);
                }

                //convert data to a Math.Net Matrix
                //last 3 rows are used to generate ci
                List <List <double> > dataci = data.Skip(data.Count - _scoreRows).ToList();
                data.Reverse();
                List <List <double> > dataobs = data.Skip(_scoreRows).ToList();
                dataobs.Reverse();
                //actual observed values
                Vector <double> y = Shared.GetYData(dataobs);
                //treatments or factor1 levels
                Matrix <double> treatments = Shared.GetDistinctMatrix(dataobs, 1);
                //206 condition added due to M and E dataset indexing
                _totalsNeeded = treatments.ColumnCount;
                double tDF = treatments.ColumnCount - 1;
                //step 1. get total of observed data
                double yTotal = y.Sum();
                //step 2. get total of observed data squared
                double yTotal2 = y.PointwisePower(2).Sum();
                //step 3. set CM
                double CM = Math.Pow(yTotal, 2) / y.Count();
                //step 4. treatments and blocks
                double SSTotal = yTotal2 - CM;
                //add the data to a string builder
                StringBuilder sb = new StringBuilder();
                sb.AppendLine("anova results");
                //5 col array
                string[] cols = new string[] { "source", "df", "SS", "MS", "F" };
                sb.AppendLine(Shared.GetLine(cols, true));
                List <List <double> > totals = new List <List <double> >(_totalsNeeded);
                //min treatment block required
                bool bIsBlock = (_depColNames.Contains("treatment") && _depColNames.Contains("block")) ? true : false;
                //min 2 factors required
                bool bIsFactorial = (_depColNames.Contains("factor1") && _depColNames.Contains("factor2")) ? true : false;
                bool bIsComplete  = (bIsBlock == false && bIsFactorial == false) ? true : false;
                if (bIsComplete)
                {
                    double eDF = y.Count() - treatments.ColumnCount;
                    //step 5.treatments (correct to divide by rows)
                    double SST = ((treatments.ColumnSums().PointwisePower(2).Sum()) / treatments.RowCount) - CM;

                    //step 6. error
                    double SSE = SSTotal - SST;

                    //step 7. mean treatment
                    double MST = SST / tDF;

                    //step 8. mean error
                    double MSE = SSE / (y.Count() - treatments.ColumnCount);

                    //step 9. F treatments
                    double FT = MST / MSE;

                    //tests
                    double s = Math.Pow(MSE, 0.5);
                    //correct 2 tailed t test
                    int itDF = CalculatorHelpers.ConvertStringToInt(tDF.ToString());
                    int ieDF = CalculatorHelpers.ConvertStringToInt(eDF.ToString());

                    double dbCI = CalculatorHelpers.GetConfidenceIntervalProb(_confidenceInt);
                    //TINV divides dbCI by 2 to get student t
                    double tCriticalValue = ExcelFunctions.TInv(dbCI, ieDF);
                    //prevents an error in Finv
                    if (itDF == 0)
                    {
                        itDF = 1;
                    }
                    double FCriticalTValue    = ExcelFunctions.FInv(dbCI, itDF, ieDF);
                    string FTGreaterFCritical = (FT > FCriticalTValue) ? "true" : "false";
                    for (int i = 0; i < _totalsNeeded; i++)
                    {
                        //206 condition added due to M and E dataset indexing
                        if (i < treatments.ColumnCount)
                        {
                            SetAnovaIntervals(i, totals, treatments, tCriticalValue, s,
                                              CalculatorHelpers.ConvertStringToDouble(treatments.RowCount.ToString()),
                                              FT, FCriticalTValue, bIsComplete);
                        }
                    }
                    this.DataToAnalyze.Add(Label, totals);
                    ////add the data to a string builder

                    cols = new string[] { "treats", itDF.ToString("F0"), SST.ToString("F4"), MST.ToString("F4"), FT.ToString("F4") };
                    sb.AppendLine(Shared.GetLine(cols, false));

                    cols = new string[] { "error  ", ieDF.ToString("F0"), SSE.ToString("F4"), MSE.ToString("F4") };
                    sb.AppendLine(Shared.GetLine(cols, false));
                    cols = new string[] { "total    ", (y.Count() - 1).ToString("F0"), (SSTotal).ToString("F4") };
                    sb.AppendLine(Shared.GetLine(cols, false));

                    cols = new string[] { string.Concat("F Crit ", "treats"), FCriticalTValue.ToString("F5"), "F > F Critical", FTGreaterFCritical };
                    sb.AppendLine(Shared.GetLine(cols, true));
                }
                else
                {
                    //observations per cell for factorials (data[0] if first row of data)
                    double r = Shared.GetObservationsPerCell(dataobs, 1, data[0].ElementAt(1), data[0].ElementAt(2));
                    //blocks or factor2 levels
                    Matrix <double> blocks = Shared.GetDistinctMatrix(dataobs, 2);
                    double          bDF    = blocks.ColumnCount - 1;
                    double          eDF    = y.Count() - treatments.ColumnCount - blocks.ColumnCount + 1;
                    if (bIsFactorial)
                    {
                        eDF = (treatments.ColumnCount * blocks.ColumnCount) * (r - 1);
                    }
                    //factorial interaction df
                    double tbDF = tDF * bDF;

                    //step 5.treatments (correct to divide by r)
                    double SST = ((treatments.ColumnSums().PointwisePower(2).Sum()) / (blocks.ColumnCount * r)) - CM;
                    //step 6. blocks
                    double SSB = ((blocks.ColumnSums().PointwisePower(2).Sum()) / (treatments.ColumnCount * r)) - CM;
                    //factor level interaction
                    double SSFL = 0;
                    //step 7. error
                    double SSE = 0;
                    if (bIsFactorial)
                    {
                        double totalinteraction = Shared.GetTotalInteraction(blocks, r);
                        //watch block.colcount for 2 x 3 factorials
                        SSFL = (totalinteraction / r) - SST - SSB - CM;
                        //step 7. error
                        SSE = SSTotal - SST - SSB - SSFL;
                    }
                    else
                    {
                        //step 7. error
                        SSE = SSTotal - SST - SSB;
                    }
                    //step 8. mean treatment
                    double MST = SST / tDF;
                    //step 9. mean block
                    double MSB = SSB / bDF;
                    //step 10. mean error
                    double MSE  = SSE / eDF;
                    double MSFL = SSFL / tbDF;
                    //step 11. F treatments
                    double FT = MST / MSE;
                    //step 12. F blocks
                    double FB  = MSB / MSE;
                    double FTB = MSFL / MSE;
                    //tests
                    double s = Math.Pow(MSE, 0.5);
                    //correct 2 tailed t test
                    int itDF  = CalculatorHelpers.ConvertStringToInt(tDF.ToString());
                    int ibDF  = CalculatorHelpers.ConvertStringToInt(bDF.ToString());
                    int itbDF = CalculatorHelpers.ConvertStringToInt(tbDF.ToString());
                    int ieDF  = CalculatorHelpers.ConvertStringToInt(eDF.ToString());

                    double dbCI = CalculatorHelpers.GetConfidenceIntervalProb(_confidenceInt);
                    //TINV divides dbCI by 2 to get student t
                    double tCriticalValue = ExcelFunctions.TInv(dbCI, ieDF);
                    //prevents an error in Finv
                    if (itDF == 0)
                    {
                        itDF = 1;
                    }
                    double FCriticalTValue    = ExcelFunctions.FInv(dbCI, itDF, ieDF);
                    string FTGreaterFCritical = (FT > FCriticalTValue) ? "true" : "false";
                    //prevents an error in Finv
                    if (ibDF == 0)
                    {
                        ibDF = 1;
                    }
                    double FCriticalBValue    = ExcelFunctions.FInv(dbCI, ibDF, ieDF);
                    string FBGreaterFCritical = (FB > FCriticalBValue) ? "true" : "false";
                    //prevents an error in Finv
                    if (itbDF == 0)
                    {
                        itbDF = 1;
                    }
                    double FCriticalTBValue    = ExcelFunctions.FInv(dbCI, itbDF, ieDF);
                    string FTBGreaterFCritical = (FTB > FCriticalTBValue) ? "true" : "false";
                    //List<List<double>> totals = new List<List<double>>(_totalsNeeded);
                    if (bIsFactorial)
                    {
                        //unless custom stylesheets are developed, can only display factor 1 - factor 2 diffs
                        //build a matrix equivalent to treatments -1 row, variable cols
                        Matrix <double> torbs = Matrix <double> .Build.Dense(1, _totalsNeeded);

                        List <double> mrow = new List <double>(_totalsNeeded);
                        for (int i = 0; i < _totalsNeeded; i++)
                        {
                            double cellMean = Shared.GetMeanPerCell(dataobs, 1, 2, i, i, r);
                            mrow.Add(cellMean);
                        }
                        torbs.SetRow(0, mrow.ToArray());
                        for (int i = 0; i < _totalsNeeded; i++)
                        {
                            //206 condition added due to M and E dataset indexing
                            if (i < treatments.ColumnCount)
                            {
                                //treatments
                                SetAnovaIntervals(i, totals, torbs, tCriticalValue, s,
                                                  CalculatorHelpers.ConvertStringToDouble(blocks.ColumnCount.ToString()),
                                                  FT, FCriticalTValue, bIsComplete);
                            }
                        }
                        //cell1Mean = Shared.GetMeanPerCell(dataobs, 1, 2, 0, 0, r);
                        //cell2Mean = Shared.GetMeanPerCell(dataobs, 1, 2, 0, 1, r);
                        //SetAnovaIntervals2(1, cell1Mean, cell2Mean, tCriticalValue, s, r);
                        //cell1Mean = Shared.GetMeanPerCell(dataobs, 1, 2, 0, 0, r);
                        //cell2Mean = Shared.GetMeanPerCell(dataobs, 1, 2, 2, 0, r);
                        //SetAnovaIntervals2(2, cell1Mean, cell2Mean, tCriticalValue, s, r);
                        //double cell1Mean = Shared.GetMeanPerCell(dataobs, 1, 2, 0, 0, r);
                        //double cell2Mean = Shared.GetMeanPerCell(dataobs, 1, 2, 1, 0, r);
                        //SetAnovaIntervals2(0, cell1Mean, cell2Mean, tCriticalValue, s, r);
                        //cell1Mean = Shared.GetMeanPerCell(dataobs, 1, 2, 0, 0, r);
                        //cell2Mean = Shared.GetMeanPerCell(dataobs, 1, 2, 0, 1, r);
                        //SetAnovaIntervals2(1, cell1Mean, cell2Mean, tCriticalValue, s, r);
                        //cell1Mean = Shared.GetMeanPerCell(dataobs, 1, 2, 0, 0, r);
                        //cell2Mean = Shared.GetMeanPerCell(dataobs, 1, 2, 2, 0, r);
                        //SetAnovaIntervals2(2, cell1Mean, cell2Mean, tCriticalValue, s, r);
                    }
                    else
                    {
                        //unless custom stylesheets are developed, need to only display treatment diffs
                        for (int i = 0; i < _totalsNeeded; i++)
                        {
                            //206 condition added due to M and E dataset indexing
                            if (i < treatments.ColumnCount)
                            {
                                //treatments
                                SetAnovaIntervals(i, totals, treatments, tCriticalValue, s,
                                                  CalculatorHelpers.ConvertStringToDouble(blocks.ColumnCount.ToString()),
                                                  FT, FCriticalTValue, bIsComplete);
                                ////blocks
                                //SetAnovaIntervals(i, totals, blocks, tCriticalValue, s,
                                //    CalculatorHelpers.ConvertStringToDouble(treatments.ColumnCount.ToString()),
                                //    FB, FCriticalBValue, bIsComplete);
                                //interactions
                            }
                        }
                    }
                    this.DataToAnalyze.Add(Label, totals);
                    string sTreats = "treats ";
                    string sBlocks = "blocks ";
                    if (bIsFactorial)
                    {
                        sTreats = "factor1 ";
                        sBlocks = "factor2 ";
                    }
                    ////add the data to a string builder
                    //StringBuilder sb = new StringBuilder();
                    //sb.AppendLine("anova results");

                    cols = new string[] { sTreats, itDF.ToString("F0"), SST.ToString("F4"), MST.ToString("F4"), FT.ToString("F4") };
                    sb.AppendLine(Shared.GetLine(cols, false));
                    cols = new string[] { sBlocks, bDF.ToString("F0"), SSB.ToString("F4"), MSB.ToString("F4"), FB.ToString("F4") };
                    sb.AppendLine(Shared.GetLine(cols, false));
                    if (bIsFactorial)
                    {
                        cols = new string[] { "interacts  ", tbDF.ToString("F0"), SSFL.ToString("F4"), MSFL.ToString("F4"), FTB.ToString("F4") };
                        sb.AppendLine(Shared.GetLine(cols, false));
                    }
                    cols = new string[] { "error  ", ieDF.ToString("F0"), SSE.ToString("F4"), MSE.ToString("F4") };
                    sb.AppendLine(Shared.GetLine(cols, false));
                    cols = new string[] { "total    ", (y.Count() - 1).ToString("F0"), (SSTotal).ToString("F4") };
                    sb.AppendLine(Shared.GetLine(cols, false));

                    cols = new string[] { string.Concat("F Crit ", sTreats), FCriticalTValue.ToString("F5"), "F > F Critical", FTGreaterFCritical };
                    sb.AppendLine(Shared.GetLine(cols, true));
                    cols = new string[] { string.Concat("F Crit ", sBlocks), FCriticalBValue.ToString("F5"), "F > F Critical", FBGreaterFCritical };
                    sb.AppendLine(Shared.GetLine(cols, true));
                    if (bIsFactorial)
                    {
                        cols = new string[] { "F Crit Interacts", FCriticalTBValue.ToString("F5"), "F > F Critical", FTBGreaterFCritical };
                        sb.AppendLine(Shared.GetLine(cols, true));
                    }
                }
                cols = new string[] { "estimate", "mean diff", string.Concat("lower ", _confidenceInt.ToString(), "%"), string.Concat("upper ", _confidenceInt.ToString(), "%") };
                sb.AppendLine(Shared.GetLine(cols, true));
                //same report for calculator and analyzer
                for (int i = 0; i < _totalsNeeded; i++)
                {
                    if (totals[i].Count >= 5)
                    {
                        if (i == 0)
                        {
                            QTPredicted = totals[i].ElementAt(0);
                            QTL         = QTPredicted - totals[i].ElementAt(4);
                            QTU         = QTPredicted + totals[i].ElementAt(4);
                            cols        = new string[] { "Treat 1 Mean ", QTPredicted.ToString("F4"), QTL.ToString("F4"), QTU.ToString("F4") };
                            sb.AppendLine(Shared.GetLine(cols, false));
                        }
                        else
                        {
                            QTPredicted = totals[i].ElementAt(1);
                            QTL         = QTPredicted - totals[i].ElementAt(2);
                            QTU         = QTPredicted + totals[i].ElementAt(2);
                            cols        = new string[] { string.Concat("xminus1 ", i.ToString(), " "), QTPredicted.ToString("F4"), QTL.ToString("F4"), QTU.ToString("F4") };
                            sb.AppendLine(Shared.GetLine(cols, false));
                            QTPredicted = totals[i].ElementAt(3);
                            QTL         = QTPredicted - totals[i].ElementAt(4);
                            QTU         = QTPredicted + totals[i].ElementAt(4);
                            cols        = new string[] { string.Concat("base ", i.ToString(), " "), QTPredicted.ToString("F4"), QTL.ToString("F4"), QTU.ToString("F4") };
                            sb.AppendLine(Shared.GetLine(cols, false));
                        }
                    }
                }
                if (this.MathResult.ToLower().StartsWith("http"))
                {
                    bool bHasSaved = await CalculatorHelpers.SaveTextInURI(
                        _params.ExtensionDocToCalcURI, sb.ToString(), this.MathResult);

                    if (!string.IsNullOrEmpty(_params.ExtensionDocToCalcURI.ErrorMessage))
                    {
                        this.MathResult += _params.ExtensionDocToCalcURI.ErrorMessage;
                        //done with errormsg
                        _params.ExtensionDocToCalcURI.ErrorMessage = string.Empty;
                    }
                }
                else
                {
                    this.MathResult = sb.ToString();
                }
                bHasCalculations = true;
            }
            catch (Exception ex)
            {
                this.ErrorMessage = ex.Message;
            }
            return(bHasCalculations);
        }