The following program calculates the the best model and statistical coefficients for the following model:
H(Y) = A + B F(X) + C G(X)
Where X is the independent variable and Y is the dependent variable. In addition, H(), F(), and G() are transformation functions for the regression variables. The program also calculates the coefficient of determination R-Square.
The program performs different transformations on all the variables. These transformations include:
The program attempts to fit a a large combination of different curves. For data that have only positive values, the program succeeds in calculating all different models. The presence of negative values and zeros will reduce the number of models tested. The application skips certain transformations for an entire data set if ANY value is zero and/or negative. The bypass prevents run-time errors. Skipping a transformation for an entire data set makes the models easier to compare since they all are based on the same number of observations.
Click here to download a ZIP file containing the project files for this program.
The program is a Windows application that has the following interface:
The above interface has the following controls:
The application reads data from text files. Each line in the source text file may be one of the following:
Here is an example of a data file:
Sample Data file Created 1/31/2006 General format for a data line is (the Weight value is optional): X,Y[,Weight] Next we have X = 100 and Y = 212 100,212 Notice leading spaces on next line 10,50 The next line has a commented observation ! 33,45 25,77 Next data line has a weight value of 2 (X = 30, Y = 86, and weight = 2) 30,86,2
The application allows for flexible commenting throughout the text file and is able to extract the data. You can add leading characters like !, #, or % as the first character of a comment line. This option may make it easier for the human eye to spot comment lines. It may also make it easier for a separate utility program to strip the comment lines.
One reason clicking the Read Data button displays the data is to allow you to double check the integrity of the data. If a data line has only one value, then the application generates flags an error. If a data line has more than 3 values, the program ignores the extra values and does not raise an error.
The application shifts and scales data using the following formulas:
X' = ScaleX * (X - ShiftX)
Y' = ScaleY * (Y - ShiftY)
Keep the above equations in mind when you assign values for the shift and/or scale factors.
Some of the mathematical transformations used take arguments that are only positive or only non-negative. In case you source data contains zeros and/or negative values, the application will avoid applying certain mathematical transformation to avoid causing run-time errors. Keep in mind that the program applies such avoidance to the entire data set and not just to those specific values that can cause error. You will notice the difference in the number of models display depending on your source data range. When using all-positive observations, the applications applies the entire set of transformations. When you have zeros or negative values, the application applies fewer transformations.
Here is a sample output:
The above output shows the first few best regression models. Here is the simple help message box:
The project file contains the following modules and classes of interest:
Here is the listing for class Form1:
using System.Diagnostics; using System; using System.Windows.Forms; using System.Collections; using System.Drawing; using Microsoft.VisualBasic; using System.Data; using System.Collections.Generic; using System.IO; namespace Best_XY_MLR_cs { public partial class Form1 { public Form1() { InitializeComponent(); } private string sDataFilename; private bool bEditMode; private bool bTextHasChanged; private void cmdCalc_Click(System.Object sender, System.EventArgs e) { CStatSum objLR; CResults objRes; int I; int nDataCOunt = 0; double fShiftX; double fShiftY; double fScaleX; double fScaleY; string sBuffer; if (sDataFilename == "") { MessageBox.Show("Please select a data file first", "Error", MessageBoxButtons.OK, MessageBoxIcon.Hand); return; } objLR = new CStatSum(); objRes = new CResults(); if (bTextHasChanged) { if (MessageBox.Show("Save changed data?", "Confirmation", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == System.Windows.Forms.DialogResult.Yes) { File.WriteAllText(sDataFilename, txtRes.Text); } bTextHasChanged = false; } bEditMode = false; // check the Shift X text box if (txtShiftX.Text.Length > 0) { fShiftX = double.Parse(txtShiftX.Text); } else { fShiftX = 0; } // check the Shift Y text box if (txtShiftY.Text.Length > 0) { fShiftY = double.Parse(txtShiftY.Text); } else { fShiftY = 0; } // check the Scale X text box if (txtScaleX.Text.Length > 0) { fScaleX = double.Parse(txtScaleX.Text); if (fScaleX == 0) { fScaleX = 1; } } else { fScaleX = 1; } // check the Scale Y text box if (txtScaleY.Text.Length > 0) { fScaleY = double.Parse(txtScaleY.Text); if (fScaleY == 0) { fScaleY = 1; } } else { fScaleY = 1; } if (objLR.GetData(sDataFilename, ref nDataCOunt, fShiftX, fShiftY, fScaleX, fScaleY)) { Cursor = Cursors.WaitCursor; objLR.FindBestFit(ref objRes); objRes.SortResults(); sBuffer = "Source Data File: " + sDataFilename + "\r\n" + "\r\n"; sBuffer = sBuffer + "Date/Time: " + DateTime.Now + "\r\n" + "\r\n"; sBuffer = sBuffer + "Number of observations = " + nDataCOunt + "\r\n" + "\r\n"; if (fScaleX != 1) { sBuffer = sBuffer + "Scale X = " + fScaleX + "\r\n"; } if (fShiftX != 0) { sBuffer = sBuffer + "Shift X = " + fShiftX + "\r\n"; } if (fScaleY != 1) { sBuffer = sBuffer + "Scale Y = " + fScaleY + "\r\n"; } if (fShiftY != 0) { sBuffer = sBuffer + "Shift Y = " + fShiftY + "\r\n" + "\r\n"; } for (I = 0; I <= objRes.Count() - 1; I++) { sBuffer = sBuffer + "R-Sqr = " + objRes.GetR2(I).ToString() + "\r\n"; sBuffer = sBuffer + "Model: " + objRes.GetModel(I) + "\r\n"; sBuffer = sBuffer + "A = " + objRes.GetIntercept(I).ToString() + ", B1 = " + objRes.GetSlope1(I).ToString() + ", B2 = " + objRes.GetSlope2(I).ToString() + "\r\n"; } txtRes.Text = sBuffer; sBuffer = ""; Cursor = Cursors.Default; cmdSaveRes.Enabled = true; } else { MessageBox.Show("Error in processing data", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } } private void Form1_Load(System.Object sender, System.EventArgs e) { sDataFilename = ""; cmdCalc.Enabled = false; cmdSaveRes.Enabled = false; bEditMode = false; } private void cmdReadData_Click(System.Object sender, System.EventArgs e) { dlgReadData.Filter = "All files (*.*)|*.*|Text files|*.txt|Data files (*.dat)|*.dat"; if (dlgReadData.ShowDialog() == System.Windows.Forms.DialogResult.OK) { sDataFilename = dlgReadData.FileName; txtRes.Text = File.ReadAllText(sDataFilename); cmdCalc.Enabled = true; cmdSaveRes.Enabled = true; bTextHasChanged = false; bEditMode = true; } } private void cmdSaveRes_Click(System.Object sender, System.EventArgs e) { dlgSaveRes.Filter = "All files (*.*)|*.*|Text files|*.txt|Data files (*.dat)|*.dat"; if (dlgSaveRes.ShowDialog() == System.Windows.Forms.DialogResult.OK) { File.WriteAllText(dlgSaveRes.FileName, txtRes.Text); bTextHasChanged = false; } } private void cmdClose_Click(System.Object sender, System.EventArgs e) { if (MessageBox.Show("Close application?", "Confirmation", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == System.Windows.Forms.DialogResult.Yes) { Close(); } } private void txtRes_TextChanged(System.Object sender, System.EventArgs e) { if (bEditMode) { bTextHasChanged = true; } } private void cmdHelp_Click(System.Object sender, System.EventArgs e) { string sText; double x1, x2; int i; Random r = new Random(); sText = "Each line can be 1) empty, 2) a comment line or 3) a data line" + "\r\n" + "A data line has a pair of y and x values separated by a comma" + "\r\n" + "A data line can have a weight value that is appended after x and is separated by a comma" + "\r\n" + "Weights are optional and need to appear when their values are not 1" + "\r\n" + "A comment line must NOT start with any of the chatacters +-.0123456789" + "\r\n" + "Show an example?"; if (MessageBox.Show(sText, "Help", MessageBoxButtons.YesNo, MessageBoxIcon.Information) == System.Windows.Forms.DialogResult.Yes) { bEditMode = false; sText = "Sample data (example of free form comment line)" + "\r\n" + "45,32" + "\r\n" + "67,34" + "\r\n" + "Next line is an observation that is temporaryly commente dout" + "\r\n" + "! 56,23" + "\r\n"; for (i = 1; i < 11; i++) { x1 = (int)(200 * r.NextDouble()); x2 = (int)(200 * r.NextDouble()); sText = sText + x1.ToString() + "," + x2.ToString() + "\r\n"; } txtRes.Text = sText; } } } }Here is the listing for module TypeModule:
using System.Diagnostics; using System; using System.Windows.Forms; using System.Collections; using System.Drawing; using Microsoft.VisualBasic; using System.Data; using System.Collections.Generic; namespace Best_XY_MLR_cs { sealed class TypeModule { public enum FitType { eLinear, eSquare, eCube, eCubeRoot, eRecip, eRecipCubeRoot, eRecipSquare, eRecipCube, eSqrt, eRecipSqrt, eLn } public struct ResType { public string m_sModel; public double m_fR2; public double m_fSlope1; public double m_fSlope2; public double m_fIntercept; public string m_sErr; } } }
Here is the listing for class CErrors:
using System.Diagnostics; using System; using System.Windows.Forms; using System.Collections; using System.Drawing; using Microsoft.VisualBasic; using System.Data; using System.Collections.Generic; using Microsoft.VisualBasic.CompilerServices; namespace Best_XY_MLR_cs { public class CErrors { private string[] m_sErrors; private int m_nNumErrs; public CErrors() { Clear(); } public void Add(string sErr) { m_sErrors = (string[])Microsoft.VisualBasic.CompilerServices.Utils.CopyArray((Array)m_sErrors, new string[m_nNumErrs + 1 + 1]); m_sErrors[m_nNumErrs] = sErr; m_nNumErrs++; } public int GetCount() { return m_nNumErrs; } public string GetErrText(int nIndex) { string sErrText = "Out of Bound Index"; try { sErrText = m_sErrors[nIndex]; } catch { } return sErrText; } public void Clear() { m_nNumErrs = 0; m_sErrors = new string[2]; } } }
Here is the listing for class CResults::
using System.Diagnostics; using System; using System.Windows.Forms; using System.Collections; using System.Drawing; using Microsoft.VisualBasic; using System.Data; using System.Collections.Generic; using System.IO; using Microsoft.VisualBasic.CompilerServices; namespace Best_XY_MLR_cs { public class CStatSum { private const double EPSILON = 1.0e-50; private const string DIGIT_MARKERS = "-+0123456789."; private bool m_bZeroX; private bool m_bZeroY; private bool m_bNegX; private bool m_bNegY; private double m_fSum; private double m_fSumX11; private double m_fSumX21; private double m_fSumX22; private double m_fSumX12; private double m_fSumY; private double m_fSumY2; private double m_fSumX1Y; private double m_fSumX2Y; private double m_fSumX1X2; private double m_fMeanX1; private double m_fMeanX2; private double m_fMeanY; private double m_fSdevX1; private double m_fSdevX2; private double m_fSdevY; private double m_fSlope1; private double m_fSlope2; private double m_fIntercept; private double m_fR2; private string m_sTX1; private string m_sTX2; private string m_sTY; private string m_sWt; private int m_nDataCount; private double[] m_fX; private double[] m_fY; private double[] m_fWt; public void InitSums() { m_fSum = 0; m_fSumX11 = 0; m_fSumX12 = 0; m_fSumX21 = 0; m_fSumX22 = 0; m_fSumY = 0; m_fSumY2 = 0; m_fSumX1Y = 0; m_fSumX2Y = 0; m_fSumX1X2 = 0; m_sTX1 = ""; m_sTX2 = ""; m_sTY = ""; m_sWt = ""; } public CStatSum() { InitSums(); } public bool GetData(string sDataFilename, ref int nDataCOunt, double ShiftX, double ShiftY, double ScaleX, double ScaleY) { string sLine; string[] sLines; string[] sData; int I, J, K, N; bool bRes = true; char[] cDelim = new char[1]; try { sLines = File.ReadAllLines(sDataFilename); nDataCOunt = sLines.GetUpperBound(0); // Dimension arrays for maximum capacity m_fX = new double[nDataCOunt + 1]; m_fY = new double[nDataCOunt + 1]; m_fWt = new double[nDataCOunt + 1]; J = 0; m_nDataCount = 0; cDelim[0] = ','; while (!(J == sLines.Length)) { sLine = sLines[J].Trim(null); // is line not empty? if (sLine.Length > 0) { // is it NOT a comment? if (DIGIT_MARKERS.IndexOf(sLine.Substring(0, 1)) >= 0) { sData = sLine.Split(cDelim); N = sData.GetUpperBound(0); m_fX[m_nDataCount] = double.Parse(sData[0]); m_fY[m_nDataCount] = double.Parse(sData[1]); if (N < 2) { m_fWt[m_nDataCount] = 1; } else { m_fWt[m_nDataCount] = double.Parse(sData[2]); } m_nDataCount++; } } J++; } // adjust arrays to actual number of data m_fX = (double[])Microsoft.VisualBasic.CompilerServices.Utils.CopyArray((Array)m_fX, new double[m_nDataCount + 1]); m_fY = (double[])Microsoft.VisualBasic.CompilerServices.Utils.CopyArray((Array)m_fY, new double[m_nDataCount + 1]); m_fWt = (double[])Microsoft.VisualBasic.CompilerServices.Utils.CopyArray((Array)m_fWt, new double[m_nDataCount + 1]); nDataCOunt = m_nDataCount; for (I = 0; I <= m_nDataCount - 1; I++) { m_fX[I] = ScaleX * (m_fX[I] - ShiftX); m_fY[I] = ScaleY * (m_fY[I] - ShiftY); } } catch (Exception) { bRes = false; } return bRes; } private void Add(double X1, double X2, double Y, double Wt) { m_fSum = m_fSum + Wt; m_fSumX11 = m_fSumX11 + X1 * Wt; m_fSumX21 = m_fSumX21 + X2 * Wt; m_fSumX12 = m_fSumX12 + X1 * X1 * Wt; m_fSumX22 = m_fSumX22 + X2 * X2 * Wt; m_fSumY = m_fSumY + Y * Wt; m_fSumY2 = m_fSumY2 + Y * Y * Wt; m_fSumX1Y = m_fSumX1Y + X1 * Y * Wt; m_fSumX2Y = m_fSumX2Y + X2 * Y * Wt; m_fSumX1X2 = m_fSumX1X2 + X1 * X2 * Wt; } public void FindBestFit(ref CResults objRes) { int I; TypeModule.FitType ITX1; TypeModule.FitType ITX2; TypeModule.FitType ITY; bool bOK; double fXt1; double fXt2; double fYt; CErrors objErrs; string sModel; string sErr; objErrs = new CErrors(); try { m_bZeroX = false; m_bZeroY = false; m_bNegX = false; m_bNegY = false; objRes.Clear(); for (I = 0; I <= m_nDataCount - 1; I++) { if (m_fX[I] < 0) { m_bNegX = true; } if (m_fY[I] < 0) { m_bNegY = true; } if (Math.Abs(m_fX[I]) < EPSILON) { m_bZeroX = true; } if (Math.Abs(m_fY[I]) < EPSILON) { m_bZeroY = true; } } for (ITY = TypeModule.FitType.eLinear; ITY <= TypeModule.FitType.eLn; ITY++) { // validate transformations if (m_bZeroY && m_bNegY) { bOK = CanHandleZeroAndNegative(ITY); } else if (m_bZeroY) { bOK = CanHandleZero(ITY); } else if (m_bNegY) { bOK = CanHandleNegative(ITY); } else { bOK = true; } // Can proceed? if (bOK) { for (ITX1 = TypeModule.FitType.eLinear; ITX1 <= TypeModule.FitType.eLn; ITX1++) { // validate transformations if (m_bZeroX && m_bNegX) { bOK = CanHandleZeroAndNegative(ITX1); } else if (m_bZeroX) { bOK = CanHandleZero(ITX1); } else if (m_bNegX) { bOK = CanHandleNegative(ITX1); } else { bOK = true; } // Can proceed? if (bOK) { for (ITX2 = ITX1; ITX2 <= TypeModule.FitType.eLn; ITX2++) { // validate transformations if (m_bZeroX && m_bNegX) { bOK = CanHandleZeroAndNegative(ITX2); } else if (m_bZeroX) { bOK = CanHandleZero(ITX2); } else if (m_bNegX) { bOK = CanHandleNegative(ITX2); } else { bOK = true; } // lastly check if two transformations are the same if (ITX1 == ITX2) { bOK = false; } if (bOK) { // initialize summations InitSums(); for (I = 0; I <= m_nDataCount - 1; I++) { fXt1 = 0; fXt2 = 0; fYt = 0; switch (ITX1) { case TypeModule.FitType.eLinear: fXt1 = m_fX[I]; break; case TypeModule.FitType.eSquare: fXt1 = Math.Pow(m_fX[I], 2); break; case TypeModule.FitType.eCube: fXt1 = Math.Pow(m_fX[I], 3); break; case TypeModule.FitType.eCubeRoot: fXt1 = Math.Pow(m_fX[I], (1 / 3)); break; case TypeModule.FitType.eRecip: fXt1 = 1 / m_fX[I]; break; case TypeModule.FitType.eRecipCubeRoot: fXt1 = Math.Pow(1 / m_fX[I], (1 / 3)); break; case TypeModule.FitType.eRecipSquare: fXt1 = Math.Pow(1 / m_fX[I], 2); break; case TypeModule.FitType.eRecipCube: fXt1 = Math.Pow(1 / m_fX[I], 3); break; case TypeModule.FitType.eSqrt: fXt1 = Math.Sqrt(m_fX[I]); break; case TypeModule.FitType.eRecipSqrt: fXt1 = 1 / Math.Sqrt(m_fX[I]); break; case TypeModule.FitType.eLn: fXt1 = Math.Log(m_fX[I]); break; } switch (ITX2) { case TypeModule.FitType.eLinear: fXt2 = m_fX[I]; break; case TypeModule.FitType.eSquare: fXt2 = Math.Pow(m_fX[I], 2); break; case TypeModule.FitType.eCube: fXt2 = Math.Pow(m_fX[I], 3); break; case TypeModule.FitType.eCubeRoot: fXt2 = Math.Pow(m_fX[I], (1 / 3)); break; case TypeModule.FitType.eRecip: fXt2 = 1 / m_fX[I]; break; case TypeModule.FitType.eRecipCubeRoot: fXt2 = Math.Pow(1 / m_fX[I], (1 / 3)); break; case TypeModule.FitType.eRecipSquare: fXt2 = Math.Pow(1 / m_fX[I], 2); break; case TypeModule.FitType.eRecipCube: fXt2 = Math.Pow(1 / m_fX[I], 3); break; case TypeModule.FitType.eSqrt: fXt2 = Math.Sqrt(m_fX[I]); break; case TypeModule.FitType.eRecipSqrt: fXt2 = 1 / Math.Sqrt(m_fX[I]); break; case TypeModule.FitType.eLn: fXt2 = Math.Log(m_fX[I]); break; } switch (ITY) { case TypeModule.FitType.eLinear: fYt = m_fY[I]; break; case TypeModule.FitType.eSquare: fYt = Math.Pow(m_fY[I], 2); break; case TypeModule.FitType.eCube: fYt = Math.Pow(m_fY[I], 3); break; case TypeModule.FitType.eCubeRoot: fYt = Math.Pow(m_fY[I], (1 / 3)); break; case TypeModule.FitType.eRecip: fYt = 1 / m_fY[I]; break; case TypeModule.FitType.eRecipCubeRoot: fYt = Math.Pow(1 / m_fY[I], (1 / 3)); break; case TypeModule.FitType.eRecipSquare: fYt = Math.Pow(1 / m_fY[I], 2); break; case TypeModule.FitType.eRecipCube: fYt = Math.Pow(1 / m_fY[I], 3); break; case TypeModule.FitType.eSqrt: fYt = Math.Sqrt(m_fY[I]); break; case TypeModule.FitType.eRecipSqrt: fYt = 1 / Math.Sqrt(m_fY[I]); break; case TypeModule.FitType.eLn: fYt = Math.Log(m_fY[I]); break; } // add transformed data to statistical summations Add(fXt1, fXt2, fYt, m_fWt[I]); } // store transformation data m_sTX1 = SayTransform(ITX1, "X"); m_sTX2 = SayTransform(ITX2, "X"); m_sTY = SayTransform(ITY, "Y"); sModel = m_sTY + " - A + B1 * " + m_sTX1 + " + B2 * " + m_sTX2; // calculate regression statistics and store in // object accessed by m_objRes CalcLR(ref objRes, ref objErrs); if (objErrs.GetCount() > 0) { sErr = objErrs.GetErrText(0); } else { sErr = ""; } objErrs.Clear(); // reset error object objRes.Add(sModel, m_fR2, m_fSlope1, m_fSlope2, m_fIntercept, sErr); } else { m_sTX1 = SayTransform(ITX1, "X"); m_sTX2 = SayTransform(ITX2, "X"); m_sTY = SayTransform(ITY, "Y"); sModel = m_sTY + " - A + B1 * " + m_sTX1 + " + B2 * " + m_sTX2; // objRes.Add(sModel, -1, 0, 0, 0, 0) } } } } } } } catch (Exception ex) { objErrs.Add(ex.Message); } } private string SayTransform(TypeModule.FitType eVal, string sVar) { switch (eVal) { case TypeModule.FitType.eLinear: return sVar; break; case TypeModule.FitType.eSquare: return sVar + "^2"; break; case TypeModule.FitType.eCube: return sVar + "^3"; break; case TypeModule.FitType.eCubeRoot: return sVar + "^1/3"; break; case TypeModule.FitType.eRecip: return "1/" + sVar; break; case TypeModule.FitType.eRecipCubeRoot: return "1/" + sVar + "^1/3"; break; case TypeModule.FitType.eRecipSquare: return "1/" + sVar + "^2"; break; case TypeModule.FitType.eRecipCube: return "1/" + sVar + "^3"; break; case TypeModule.FitType.eSqrt: return sVar + "^1/2"; break; case TypeModule.FitType.eRecipSqrt: return "1/" + sVar + "^1/2"; break; case TypeModule.FitType.eLn: return "Ln(" + sVar + ")"; break; default: return ""; } } private bool CanHandleZero(TypeModule.FitType eVal) { bool returnValue; switch (eVal) { case TypeModule.FitType.eLinear: returnValue = true; break; case TypeModule.FitType.eSquare: returnValue = true; break; case TypeModule.FitType.eCube: returnValue = true; break; case TypeModule.FitType.eCubeRoot: returnValue = true; break; case TypeModule.FitType.eSqrt: returnValue = true; break; default: returnValue = false; break; } return returnValue; } private bool CanHandleZeroAndNegative(TypeModule.FitType eVal) { bool returnValue; switch (eVal) { case TypeModule.FitType.eLinear: returnValue = true; break; case TypeModule.FitType.eSquare: returnValue = true; break; case TypeModule.FitType.eCube: returnValue = true; break; default: returnValue = false; break; } return returnValue; } private bool CanHandleNegative(TypeModule.FitType eVal) { bool returnValue; switch (eVal) { case TypeModule.FitType.eLinear: returnValue = true; break; case TypeModule.FitType.eSquare: returnValue = true; break; case TypeModule.FitType.eCube: returnValue = true; break; case TypeModule.FitType.eRecip: returnValue = true; break; case TypeModule.FitType.eRecipSquare: returnValue = true; break; case TypeModule.FitType.eRecipCube: returnValue = true; break; default: returnValue = false; break; } return returnValue; } private void CalcLR(ref CResults objRes, ref CErrors objErrs) { double A; double B; if (m_fSum < 2) { return; } // caluclate regression try { m_fMeanX1 = m_fSumX11 / m_fSum; m_fMeanX2 = m_fSumX21 / m_fSum; m_fMeanY = m_fSumY / m_fSum; m_fSdevX1 = Math.Sqrt((m_fSumX12 - Math.Pow(m_fSumX11, 2) / m_fSum) / (m_fSum - 1)); m_fSdevX2 = Math.Sqrt((m_fSumX22 - Math.Pow(m_fSumX21, 2) / m_fSum) / (m_fSum - 1)); m_fSdevY = Math.Sqrt((m_fSumY2 - Math.Pow(m_fSumY, 2) / m_fSum) / (m_fSum - 1)); A = (m_fSum * m_fSumX12 - Math.Pow(m_fSumX11, 2)) * (m_fSum * m_fSumX2Y - m_fSumX21 * m_fSumY); B = (m_fSum * m_fSumX1X2 - m_fSumX11 * m_fSumX21) * (m_fSum * m_fSumX1Y - m_fSumX11 * m_fSumY); m_fSlope2 = (A - B) / ( (m_fSum * m_fSumX12 - m_fSumX11 * m_fSumX11) * (m_fSum * m_fSumX22 - m_fSumX21 * m_fSumX21) - Math.Pow(m_fSum * m_fSumX1X2 - m_fSumX11 * m_fSumX21, 2) ); m_fSlope1 = ((m_fSum * m_fSumX1Y - m_fSumX11 * m_fSumY) - m_fSlope2 * (m_fSum * m_fSumX1X2 - m_fSumX11 * m_fSumX21)) / (m_fSum * m_fSumX12 - m_fSumX11 * m_fSumX11); m_fIntercept = m_fMeanY - m_fSlope1 * m_fMeanX1 - m_fSlope2 * m_fMeanX2; m_fR2 = (m_fIntercept * m_fSumY + m_fSlope1 * m_fSumX1Y + m_fSlope2 * m_fSumX2Y - m_fSumY * m_fSumY / m_fSum) / (m_fSumY2 - m_fSumY * m_fSumY / m_fSum); } catch (Exception ex) { objErrs.Add("Error in model " + m_sTY + "= A0 + A1 " + m_sTX1 + " + A2 " + m_sTX2 + "\r\n" + ex.Message.ToString()); } } } }
Copyright (c) Namir Shammas. All rights reserved.