2020-03-30 18:01:44 +00:00
|
|
|
unit WLSUnit;
|
|
|
|
|
|
|
|
{$mode objfpc}{$H+}
|
|
|
|
|
|
|
|
interface
|
|
|
|
|
|
|
|
uses
|
2020-10-11 22:31:17 +00:00
|
|
|
Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs,
|
|
|
|
StdCtrls, Buttons, ExtCtrls, ComCtrls,
|
2020-10-12 16:17:29 +00:00
|
|
|
Globals, MainUnit, DictionaryUnit, Matrixlib, DataProcs,
|
2020-10-14 14:28:59 +00:00
|
|
|
RegressionUnit, ReportFrameUnit, ChartFrameUnit, BasicStatsParamsFormUnit;
|
2020-03-30 18:01:44 +00:00
|
|
|
|
|
|
|
type
|
|
|
|
|
|
|
|
{ TWLSFrm }
|
|
|
|
|
2020-10-12 16:17:29 +00:00
|
|
|
TWLSFrm = class(TBasicStatsParamsForm)
|
2020-03-30 18:01:44 +00:00
|
|
|
DepInBtn: TBitBtn;
|
|
|
|
DepOutBtn: TBitBtn;
|
|
|
|
IndInBtn: TBitBtn;
|
|
|
|
IndOutBtn: TBitBtn;
|
2020-10-11 22:31:17 +00:00
|
|
|
PageControl: TPageControl;
|
|
|
|
OLSPage: TTabSheet;
|
2020-10-12 13:43:51 +00:00
|
|
|
ResRegPageControl: TPageControl;
|
2020-10-11 22:31:17 +00:00
|
|
|
ResidualsRegPage: TTabSheet;
|
2020-10-12 13:43:51 +00:00
|
|
|
ResRegReportPage: TTabSheet;
|
2020-10-12 16:49:08 +00:00
|
|
|
UserWeightsChk: TRadioButton;
|
|
|
|
WeightChk: TRadioButton;
|
2020-10-11 22:31:17 +00:00
|
|
|
WLSPage: TTabSheet;
|
2020-10-12 16:49:08 +00:00
|
|
|
WeightInBtn: TBitBtn;
|
|
|
|
WeightOutBtn: TBitBtn;
|
2020-03-30 18:01:44 +00:00
|
|
|
SaveChk: TCheckBox;
|
|
|
|
OriginChk: TCheckBox;
|
|
|
|
Origin2Chk: TCheckBox;
|
|
|
|
DepVarEdit: TEdit;
|
2020-10-12 16:49:08 +00:00
|
|
|
WeightVarEdit: TEdit;
|
2020-10-11 22:31:17 +00:00
|
|
|
OptionsGroup: TGroupBox;
|
2020-03-30 18:01:44 +00:00
|
|
|
Label1: TLabel;
|
|
|
|
Label2: TLabel;
|
|
|
|
Label3: TLabel;
|
|
|
|
Label4: TLabel;
|
|
|
|
IndVarList: TListBox;
|
|
|
|
VarList: TListBox;
|
|
|
|
procedure DepInBtnClick(Sender: TObject);
|
|
|
|
procedure DepOutBtnClick(Sender: TObject);
|
|
|
|
procedure IndInBtnClick(Sender: TObject);
|
|
|
|
procedure IndOutBtnClick(Sender: TObject);
|
2020-10-11 22:31:17 +00:00
|
|
|
procedure IndVarListDblClick(Sender: TObject);
|
2020-10-12 16:49:08 +00:00
|
|
|
procedure UserWeightsChkChange(Sender: TObject);
|
2020-10-11 22:31:17 +00:00
|
|
|
procedure VarListDblClick(Sender: TObject);
|
2020-10-12 16:17:29 +00:00
|
|
|
procedure VarListSelectionChange(Sender: TObject; {%H-}User: boolean);
|
2020-10-12 16:49:08 +00:00
|
|
|
procedure WeightInBtnClick(Sender: TObject);
|
|
|
|
procedure WeightOutBtnClick(Sender: TObject);
|
2020-03-30 18:01:44 +00:00
|
|
|
|
|
|
|
private
|
2020-10-11 22:31:17 +00:00
|
|
|
OLSReportFrame: TReportFrame;
|
|
|
|
ResidualsRegReportFrame: TReportFrame;
|
|
|
|
WLSReportFrame: TReportFrame;
|
2020-10-12 13:43:51 +00:00
|
|
|
|
2020-10-17 22:42:41 +00:00
|
|
|
procedure AddVariable(AVarName: String; AData: DblDyneVec; ANumFormat: String);
|
|
|
|
|
|
|
|
procedure AddWeightsToGrid(const ASqrPredictedResiduals, AWeights: DblDyneVec);
|
|
|
|
|
|
|
|
procedure CalcWeights(xValues: DblDyneMat; ACoeffs: DblDyneVec;
|
|
|
|
out ASquaredPredictedResiduals: DblDyneVec; out AWeights: DblDyneVec);
|
2020-10-12 21:53:18 +00:00
|
|
|
|
2020-10-12 13:43:51 +00:00
|
|
|
procedure CreateOrGetChartFrame(AColIndex: Integer; AVarName: String;
|
|
|
|
out AMemo: TMemo; out AChartFrame: TChartFrame);
|
|
|
|
|
|
|
|
function GetPageCaption(AVarName: String): String;
|
|
|
|
|
2020-10-17 22:42:41 +00:00
|
|
|
procedure PlotSquaredResiduals(AIndepCols: IntDyneVec; ADepCol: Integer;
|
|
|
|
const AIndepValues: DblDyneMat; const ADepValues: DblDyneVec);
|
2020-10-12 16:17:29 +00:00
|
|
|
|
|
|
|
procedure PlotXY(AChartFrame: TChartFrame; const XPoints, YPoints: DblDyneVec;
|
|
|
|
const ARegressionResults: TBivariateRegressionResults; const XLabel, YLabel: String);
|
|
|
|
|
2020-10-17 22:42:41 +00:00
|
|
|
procedure Predict(const xData: DblDyneMat; const yData: DblDyneVec;
|
|
|
|
ARegressionResults: TMultipleRegressionResults);
|
2020-10-11 22:31:17 +00:00
|
|
|
|
2020-10-17 22:42:41 +00:00
|
|
|
function PrepareData(out AIndepCols: IntDyneVec; out ADepCol: Integer;
|
|
|
|
out AWeightCol: Integer; out ARowLabels: StrDyneVec;
|
|
|
|
out xValues: DblDyneMat; out yValues: DblDyneVec): Boolean;
|
2020-10-12 17:09:06 +00:00
|
|
|
|
2020-10-17 22:42:41 +00:00
|
|
|
function Process_OLSRegression(AIndepCols: IntDyneVec; ADepCol: Integer;
|
|
|
|
const ARowLabels: StrDyneVec; const xValues: DblDyneMat;
|
|
|
|
const yValues: DblDyneVec): Boolean;
|
2020-10-12 21:53:18 +00:00
|
|
|
|
|
|
|
function Process_SquaredResidualsRegression(AIndepCols: IntDyneVec;
|
2020-10-17 22:42:41 +00:00
|
|
|
const ARowLabels: StrDyneVec; const xValues: DblDyneMat;
|
|
|
|
out AWeights: DblDyneVec): Boolean;
|
|
|
|
|
|
|
|
function Process_WeightedRegression(AIndepCols: IntDyneVec;
|
|
|
|
const ARowLabels: StrDyneVec; const xValues: DblDyneMat;
|
|
|
|
const yValues: DblDyneVec; const AWeights: DblDyneVec;
|
|
|
|
SubtractMeans: Boolean): Boolean;
|
|
|
|
|
|
|
|
function RegressionAndReport(const ARowLabels: StrDyneVec;
|
|
|
|
const xValues: DblDyneMat; const yValues: DblDyneVec;
|
|
|
|
out ARegressionResults: TMultipleRegressionResults; AReport: TStrings): Boolean;
|
2020-10-12 21:53:18 +00:00
|
|
|
|
2020-10-12 16:17:29 +00:00
|
|
|
procedure WriteDescriptiveReport(AMemo: TMemo;
|
|
|
|
const ARegressionResults: TBivariateRegressionResults;
|
|
|
|
const XLabel, YLabel: String);
|
2020-10-12 13:43:51 +00:00
|
|
|
|
2020-10-11 22:31:17 +00:00
|
|
|
protected
|
|
|
|
procedure AdjustConstraints; override;
|
|
|
|
procedure Compute; override;
|
|
|
|
procedure UpdateBtnStates; override;
|
|
|
|
function Validate(out AMsg: String; out AControl: TWinControl): Boolean; override;
|
|
|
|
|
2020-03-30 18:01:44 +00:00
|
|
|
public
|
2020-10-11 22:31:17 +00:00
|
|
|
constructor Create(AOwner: TComponent); override;
|
|
|
|
procedure Reset; override;
|
|
|
|
|
|
|
|
end;
|
2020-03-30 18:01:44 +00:00
|
|
|
|
|
|
|
var
|
|
|
|
WLSFrm: TWLSFrm;
|
|
|
|
|
2020-10-11 22:31:17 +00:00
|
|
|
|
2020-03-30 18:01:44 +00:00
|
|
|
implementation
|
|
|
|
|
2020-10-11 22:31:17 +00:00
|
|
|
{$R *.lfm}
|
|
|
|
|
2020-03-30 18:01:44 +00:00
|
|
|
uses
|
2020-10-12 16:49:08 +00:00
|
|
|
Math,
|
2020-10-12 16:17:29 +00:00
|
|
|
TAChartUtils, TAChartAxisUtils, TALegend, TASources, TACustomSeries,
|
2020-10-14 14:28:59 +00:00
|
|
|
Utils, MatrixUnit, GridProcs;
|
2020-03-30 18:01:44 +00:00
|
|
|
|
2020-10-17 22:42:41 +00:00
|
|
|
const
|
|
|
|
CONF_LEVEL = DEFAULT_CONFIDENCE_LEVEL_PERCENT / 100.0;
|
|
|
|
|
2020-03-30 18:01:44 +00:00
|
|
|
{ TWLSFrm }
|
|
|
|
|
2020-10-11 22:31:17 +00:00
|
|
|
constructor TWLSFrm.Create(AOwner: TComponent);
|
2020-03-30 18:01:44 +00:00
|
|
|
begin
|
2020-10-11 22:31:17 +00:00
|
|
|
inherited;
|
2020-03-30 18:01:44 +00:00
|
|
|
if DictionaryFrm = nil then Application.CreateForm(TDictionaryFrm, DictionaryFrm);
|
|
|
|
|
2020-10-11 22:31:17 +00:00
|
|
|
OLSReportFrame := TReportFrame.Create(self);
|
|
|
|
OLSReportFrame.Name := '';
|
|
|
|
OLSReportFrame.Parent := OLSPage;
|
|
|
|
OLSReportFrame.Align := alClient;
|
|
|
|
OLSReportFrame.BorderSpacing.Left := 0;
|
|
|
|
OLSReportFrame.BorderSpacing.Top := 0;
|
|
|
|
OLSReportFrame.BorderSpacing.Bottom := 0;
|
|
|
|
OLSReportFrame.BorderSpacing.Right := 0;
|
|
|
|
InitToolbar(OLSReportFrame.ReportToolbar, tpRight);
|
|
|
|
|
|
|
|
ResidualsRegReportFrame := TReportFrame.Create(self);
|
|
|
|
ResidualsRegReportFrame.Name := '';
|
2020-10-12 13:43:51 +00:00
|
|
|
ResidualsRegReportFrame.Parent := ResRegReportPage;
|
2020-10-11 22:31:17 +00:00
|
|
|
ResidualsRegReportFrame.Align := alClient;
|
|
|
|
ResidualsRegReportFrame.BorderSpacing.Left := 0;
|
|
|
|
ResidualsRegReportFrame.BorderSpacing.Top := 0;
|
|
|
|
ResidualsRegReportFrame.BorderSpacing.Bottom := 0;
|
|
|
|
ResidualsRegReportFrame.BorderSpacing.Right := 0;
|
|
|
|
InitToolbar(ResidualsRegReportFrame.ReportToolbar, tpRight);
|
|
|
|
|
|
|
|
WLSReportFrame := TReportFrame.Create(self);
|
|
|
|
WLSReportFrame.Name := '';
|
|
|
|
WLSReportFrame.Parent := WLSPage;
|
|
|
|
WLSReportFrame.Align := alClient;
|
|
|
|
WLSReportFrame.BorderSpacing.Left := 0;
|
|
|
|
WLSReportFrame.BorderSpacing.Top := 0;
|
|
|
|
WLSReportFrame.BorderSpacing.Bottom := 0;
|
|
|
|
WLSReportFrame.BorderSpacing.Right := 0;
|
|
|
|
InitToolbar(WLSReportFrame.ReportToolbar, tpRight);
|
2020-10-17 22:42:41 +00:00
|
|
|
|
|
|
|
PageControl.ActivePageIndex := 0;
|
2020-03-30 18:01:44 +00:00
|
|
|
end;
|
|
|
|
|
|
|
|
|
2020-10-17 22:42:41 +00:00
|
|
|
{ Adds a new variable names AColTitle after the last grid column,
|
|
|
|
and writes the specified data to the grid (in the specified number format). }
|
|
|
|
procedure TWLSFrm.AddVariable(AVarName: String; AData: DblDyneVec; ANumFormat: String);
|
2020-10-12 21:53:18 +00:00
|
|
|
var
|
2020-10-17 22:42:41 +00:00
|
|
|
i, colIndex: Integer;
|
2020-10-12 21:53:18 +00:00
|
|
|
begin
|
2020-10-17 22:42:41 +00:00
|
|
|
colIndex := GetVariableIndex(OS3MainFrm.DataGrid, AVarname);
|
|
|
|
if colIndex = -1 then
|
2020-10-12 21:53:18 +00:00
|
|
|
begin
|
2020-10-17 22:42:41 +00:00
|
|
|
colIndex := NoVariables + 1;
|
|
|
|
DictionaryFrm.NewVar(colIndex);
|
|
|
|
DictionaryFrm.DictGrid.Cells[1, colIndex] := AVarName;
|
|
|
|
DictionaryFrm.DictGrid.Cells[7, colIndex] := 'R';
|
|
|
|
OS3MainFrm.DataGrid.Cells[colIndex, 0] := AVarName;
|
|
|
|
OS3MainFrm.NoVarsEdit.Text := IntToStr(NoVariables);
|
|
|
|
end;
|
|
|
|
for i := 0 to High(AData) do
|
|
|
|
OS3MainFrm.DataGrid.Cells[colIndex, i+1] := Format(ANumFormat, [AData[i]]);
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
{ Calculate predicted squared residuals and save recipricols to grid as weights }
|
|
|
|
procedure TWLSFrm.AddWeightsToGrid(const ASqrPredictedResiduals, AWeights: DblDyneVec);
|
|
|
|
begin
|
|
|
|
// Create new variables and add to grid
|
|
|
|
AddVariable('Pred SqrResid', ASqrPredictedResiduals, '%.3f');
|
|
|
|
AddVariable('WEIGHTS', AWeights, '%.3f');
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
{ Calculate predicted values of the squared residuals, as well as the weights }
|
|
|
|
procedure TWLSFrm.CalcWeights(xValues: DblDyneMat; ACoeffs: DblDyneVec;
|
|
|
|
out ASquaredPredictedResiduals: DblDyneVec; out AWeights: DblDyneVec);
|
|
|
|
var
|
|
|
|
i, j, n, m: Integer;
|
|
|
|
sum: Double;
|
|
|
|
begin
|
|
|
|
ASquaredPredictedResiduals := nil;
|
|
|
|
AWeights := nil;
|
|
|
|
|
|
|
|
MatSize(xValues, n,m);
|
|
|
|
SetLength(ASquaredPredictedResiduals, n);
|
|
|
|
SetLength(AWeights, n);
|
|
|
|
|
|
|
|
sum := 0;
|
|
|
|
for i := 0 to n-1 do
|
|
|
|
begin
|
|
|
|
ASquaredPredictedResiduals[i] := ACoeffs[m]; // intercept value
|
|
|
|
for j := 0 to m-1 do
|
|
|
|
ASquaredPredictedResiduals[i] += abs(xValues[i, j] * ACoeffs[j]);
|
|
|
|
if ASquaredPredictedResiduals[i] <> 0 then
|
|
|
|
AWeights[i] := 1 / ASquaredPredictedResiduals[i]
|
|
|
|
else
|
|
|
|
AWeights[i] := 0;
|
|
|
|
sum := sum + AWeights[i];
|
2020-10-12 21:53:18 +00:00
|
|
|
end;
|
2020-10-17 22:42:41 +00:00
|
|
|
|
|
|
|
// Normalize weights to 1.0
|
|
|
|
AWeights := AWeights * (1.0 / sum);
|
2020-10-12 21:53:18 +00:00
|
|
|
end;
|
|
|
|
|
|
|
|
|
2020-10-11 22:31:17 +00:00
|
|
|
procedure TWLSFrm.AdjustConstraints;
|
2020-03-30 18:01:44 +00:00
|
|
|
begin
|
2020-10-11 22:31:17 +00:00
|
|
|
ParamsPanel.Constraints.MinHeight := DepInBtn.Top + (IndOutBtn.Top - DepInBtn.Top)*2 + DepInBtn.Top +
|
|
|
|
OptionsGroup.Height + ButtonBevel.Height + CloseBtn.BorderSpacing.Top + CloseBtn.Height;
|
2020-03-30 18:01:44 +00:00
|
|
|
|
2020-10-12 16:49:08 +00:00
|
|
|
ParamsPanel.Constraints.MinWidth := Max(
|
|
|
|
4*CloseBtn.Width + 3*CloseBtn.BorderSpacing.Left,
|
|
|
|
OptionsGroup.Width
|
|
|
|
);
|
2020-03-30 18:01:44 +00:00
|
|
|
end;
|
|
|
|
|
2020-10-11 22:31:17 +00:00
|
|
|
procedure TWLSFrm.Compute;
|
2020-03-30 18:01:44 +00:00
|
|
|
var
|
2020-10-17 22:42:41 +00:00
|
|
|
i, j, noIndep, NCases, pos, col: integer;
|
2020-10-14 14:28:59 +00:00
|
|
|
X, weight: double;
|
2020-10-11 22:31:17 +00:00
|
|
|
Means: DblDyneVec = nil;
|
|
|
|
Variances: DblDyneVec = nil;
|
|
|
|
StdDevs: DblDyneVec = nil;
|
|
|
|
BWeights: DblDyneVec = nil;
|
|
|
|
BetaWeights: DblDyneVec = nil;
|
|
|
|
BStdErrs: DblDyneVec = nil;
|
|
|
|
BtTests: DblDyneVec = nil;
|
|
|
|
tProbs: DblDyneVec = nil;
|
|
|
|
lReport: TStrings;
|
|
|
|
StdErrEst: Double = 0.0;
|
|
|
|
R2: Double = 0.0;
|
|
|
|
errorcode: Boolean = false;
|
2020-10-12 21:53:18 +00:00
|
|
|
PrintDesc: boolean = true;
|
2020-10-17 22:42:41 +00:00
|
|
|
|
|
|
|
indepCols: IntDyneVec = nil;
|
|
|
|
rowLabels: StrDyneVec = nil;
|
|
|
|
weights: DblDyneVec = nil;
|
|
|
|
xValues: DblDyneMat = nil;
|
|
|
|
yValues: DblDyneVec = nil;
|
|
|
|
depCol: Integer;
|
|
|
|
weightCol: Integer = -1;
|
|
|
|
useOrigin: Boolean;
|
2020-03-30 18:01:44 +00:00
|
|
|
begin
|
|
|
|
SetLength(Means, NoVariables + 2);
|
|
|
|
SetLength(Variances, NoVariables + 2);
|
|
|
|
SetLength(StdDevs, NoVariables + 2);
|
2020-10-12 21:53:18 +00:00
|
|
|
SetLength(BWeights, NoVariables + 2); // do not remove!
|
2020-03-30 18:01:44 +00:00
|
|
|
SetLength(BetaWeights, NoVariables + 2);
|
|
|
|
SetLength(BStdErrs, NoVariables + 2);
|
|
|
|
SetLength(Bttests, NoVariables + 2);
|
|
|
|
SetLength(tprobs, NoVariables + 2);
|
|
|
|
|
|
|
|
lReport := TStringList.Create;
|
|
|
|
try
|
|
|
|
NCases := NoCases;
|
2020-10-11 22:31:17 +00:00
|
|
|
|
2020-10-12 21:53:18 +00:00
|
|
|
// Get column indexes and do some validation checks.
|
2020-10-17 22:42:41 +00:00
|
|
|
if not PrepareData(indepCols, depCol, weightCol, RowLabels, xValues, yValues) then
|
2020-03-30 18:01:44 +00:00
|
|
|
exit;
|
|
|
|
|
2020-10-17 22:42:41 +00:00
|
|
|
// Do the OLS regression
|
|
|
|
if not Process_OLSRegression(indepCols, depCol, RowLabels, xValues, yValues) then
|
|
|
|
exit;
|
2020-03-30 18:01:44 +00:00
|
|
|
|
2020-10-17 22:42:41 +00:00
|
|
|
// Regress the squared residuals on the predictors
|
|
|
|
if WeightChk.Checked then
|
|
|
|
begin
|
|
|
|
if not Process_SquaredResidualsRegression(indepCols, RowLabels, xValues, weights) then
|
|
|
|
exit;
|
|
|
|
useOrigin := OriginChk.Checked;
|
|
|
|
end else
|
|
|
|
begin
|
|
|
|
// Read the weights from the user column
|
|
|
|
weights := CollectVecValues(OS3MainFrm.DataGrid, weightCol, indepCols);
|
|
|
|
useOrigin := Origin2Chk.Checked;
|
|
|
|
end;
|
|
|
|
|
|
|
|
// Do the weighted regression, finally
|
|
|
|
Process_WeightedRegression(indepCols, RowLabels, xValues, yValues, weights, useOrigin);
|
|
|
|
|
|
|
|
|
|
|
|
exit;
|
2020-03-30 18:01:44 +00:00
|
|
|
|
2020-10-11 22:31:17 +00:00
|
|
|
|
2020-03-30 18:01:44 +00:00
|
|
|
|
2020-10-12 21:53:18 +00:00
|
|
|
if WeightChk.Checked then
|
2020-10-11 22:31:17 +00:00
|
|
|
begin
|
|
|
|
// Weight variables and do OLS regression on weighted variables
|
2020-10-17 22:42:41 +00:00
|
|
|
// DepCol := olddepcol;
|
2020-10-11 22:31:17 +00:00
|
|
|
IndepCols[Noindep] := DepCol;
|
|
|
|
for i := 1 to NoCases do
|
|
|
|
begin
|
2020-10-14 14:28:59 +00:00
|
|
|
weight := StrToFloat(Trim(OS3MainFrm.DataGrid.Cells[NoVariables,i]));
|
2020-10-11 22:31:17 +00:00
|
|
|
for j := 0 to Noindep do
|
|
|
|
begin
|
|
|
|
pos := IndepCols[j];
|
|
|
|
X := StrToFloat(Trim(OS3MainFrm.DataGrid.Cells[pos,i]));
|
2020-10-14 14:28:59 +00:00
|
|
|
X := X * weight;
|
|
|
|
OS3MainFrm.DataGrid.Cells[pos, i] := FloatToStr(X); // wp: DON'T OVERWRITE GRID CELLS
|
2020-10-11 22:31:17 +00:00
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
// get means of variables and subtract from the values
|
|
|
|
if OriginChk.Checked then
|
|
|
|
begin
|
2020-10-12 16:17:29 +00:00
|
|
|
for j := 0 to NoIndep do
|
2020-10-11 22:31:17 +00:00
|
|
|
begin
|
|
|
|
Means[j] := 0.0;
|
|
|
|
NCases := 0;
|
|
|
|
pos := IndepCols[j];
|
|
|
|
for i := 1 to NoCases do
|
|
|
|
begin
|
|
|
|
if (DataProcs.ValidValue(i,pos)) then
|
|
|
|
begin
|
|
|
|
Means[j] := Means[j] + StrToFloat(Trim(OS3MainFrm.DataGrid.Cells[pos,i]));
|
|
|
|
NCases := NCases + 1;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
Means[j] := Means[j] / NCases;
|
|
|
|
for i := 1 to NoCases do
|
|
|
|
begin
|
|
|
|
if (DataProcs.ValidValue(i,pos)) then
|
|
|
|
begin
|
|
|
|
X := StrToFloat(Trim(OS3MainFrm.DataGrid.Cells[pos,i]));
|
|
|
|
X := X - Means[j];
|
2020-10-12 21:53:18 +00:00
|
|
|
OS3MainFrm.DataGrid.Cells[pos,i] := FloatToStr(X); // wp: DON'T OVERWRITE GRID DATA!
|
2020-10-11 22:31:17 +00:00
|
|
|
end;
|
|
|
|
end; // next i
|
|
|
|
end; // next j
|
|
|
|
end; // if origin checked
|
|
|
|
|
|
|
|
lReport.Clear;
|
|
|
|
lReport.Add('WEIGHTED LEAST SQUARES (WLS) REGRESSION RESULTS');
|
|
|
|
lReport.Add('');
|
|
|
|
MReg(Noindep, IndepCols, DepCol, RowLabels, Means, Variances, StdDevs,
|
2020-10-12 21:53:18 +00:00
|
|
|
BWeights, BetaWeights, BStdErrs, Bttests, tprobs, R2, stdErrEst,
|
2020-10-11 22:31:17 +00:00
|
|
|
NCases, errorcode, PrintDesc, lReport);
|
|
|
|
|
|
|
|
WLSReportFrame.DisplayReport(lReport);
|
|
|
|
lReport.Clear;
|
2020-10-12 21:53:18 +00:00
|
|
|
end; // if weightschk checked
|
|
|
|
|
2020-10-11 22:31:17 +00:00
|
|
|
// use the weights entered by the user
|
2020-10-12 21:53:18 +00:00
|
|
|
if UserWeightsChk.Checked then
|
2020-10-11 22:31:17 +00:00
|
|
|
begin
|
|
|
|
// Weight variables and do OLS regression on weighted variables
|
2020-10-17 22:42:41 +00:00
|
|
|
// depCol := olddepcol;
|
2020-10-12 21:53:18 +00:00
|
|
|
indepCols[Noindep] := depCol; // wp: CALCULATION SHOULD NORMALIZE USER WEIGHTS HERE !!!
|
2020-10-11 22:31:17 +00:00
|
|
|
for i := 1 to NoCases do
|
|
|
|
begin
|
2020-10-14 14:28:59 +00:00
|
|
|
weight := StrToFloat(Trim(OS3MainFrm.DataGrid.Cells[weightCol, i]));
|
2020-10-11 22:31:17 +00:00
|
|
|
for j := 0 to Noindep do
|
|
|
|
begin
|
2020-10-12 21:53:18 +00:00
|
|
|
pos := indepCols[j];
|
2020-10-11 22:31:17 +00:00
|
|
|
X := StrToFloat(OS3MainFrm.DataGrid.Cells[pos,i]);
|
2020-10-14 14:28:59 +00:00
|
|
|
X := X * weight;
|
|
|
|
OS3MainFrm.DataGrid.Cells[pos, i] := FloatToStr(X);
|
2020-10-11 22:31:17 +00:00
|
|
|
end;
|
|
|
|
end;
|
2020-10-14 14:28:59 +00:00
|
|
|
if Origin2Chk.Checked then // get means of variables and subtract from the values
|
2020-10-11 22:31:17 +00:00
|
|
|
begin
|
|
|
|
for j := 0 to Noindep do
|
|
|
|
begin
|
|
|
|
Means[j] := 0.0;
|
|
|
|
NCases := 0;
|
|
|
|
pos := IndepCols[j];
|
|
|
|
for i := 1 to NoCases do
|
|
|
|
begin
|
|
|
|
if (DataProcs.ValidValue(i,pos)) then
|
|
|
|
begin
|
2020-10-14 14:28:59 +00:00
|
|
|
Means[j] := Means[j] + StrToFloat(Trim(OS3MainFrm.DataGrid.Cells[pos, i]));
|
2020-10-11 22:31:17 +00:00
|
|
|
NCases := NCases + 1;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
Means[j] := Means[j] / NCases;
|
|
|
|
for i := 1 to NoCases do
|
|
|
|
begin
|
|
|
|
if (DataProcs.ValidValue(i,pos)) then
|
|
|
|
begin
|
|
|
|
X := StrToFloat(OS3MainFrm.DataGrid.Cells[pos,i]);
|
|
|
|
X := X - Means[j];
|
2020-10-12 21:53:18 +00:00
|
|
|
OS3MainFrm.DataGrid.Cells[pos,i] := FloatToStr(X); // wp: DON'T OVERWRITE GRID DATA!
|
2020-10-11 22:31:17 +00:00
|
|
|
end;
|
|
|
|
end; // next i
|
|
|
|
end; // next j
|
|
|
|
end; // if origin checked
|
|
|
|
|
|
|
|
lReport.Clear;
|
|
|
|
lReport.Add('WEIGHTED LEAST SQUARES (WLS) REGRESSION RESULTS');
|
|
|
|
lReport.Add('');
|
|
|
|
MReg(Noindep, IndepCols, DepCol, RowLabels, Means, Variances, StdDevs,
|
2020-10-12 21:53:18 +00:00
|
|
|
BWeights, BetaWeights, BStdErrs, Bttests, tprobs, R2, stdErrEst,
|
2020-10-11 22:31:17 +00:00
|
|
|
NCases, errorcode, PrintDesc, lReport);
|
|
|
|
|
|
|
|
WLSReportFrame.DisplayReport(lReport);
|
|
|
|
lReport.Clear;
|
|
|
|
end;
|
2020-03-30 18:01:44 +00:00
|
|
|
|
|
|
|
finally
|
|
|
|
lReport.Free;
|
2020-10-11 22:31:17 +00:00
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
2020-10-12 13:43:51 +00:00
|
|
|
procedure TWLSFrm.CreateOrGetChartFrame(AColIndex: Integer; AVarName: String;
|
|
|
|
out AMemo: TMemo; out AChartFrame: TChartFrame);
|
|
|
|
var
|
|
|
|
sheetTitle: String;
|
|
|
|
tabSheet: TTabSheet;
|
|
|
|
i: Integer;
|
|
|
|
begin
|
|
|
|
sheetTitle := GetPageCaption(AVarName);
|
|
|
|
|
|
|
|
// Find existing sheet first.
|
|
|
|
for i := 1 to ResRegPageControl.PageCount-1 do
|
|
|
|
if ResRegPageControl.Pages[i].Caption = sheetTitle then begin
|
|
|
|
tabSheet := ResRegPageControl.Pages[i];
|
|
|
|
AChartFrame := tabSheet.Controls[0] as TChartFrame;
|
|
|
|
AMemo := tabSheet.Controls[1] as TMemo;
|
|
|
|
exit;
|
|
|
|
end;
|
|
|
|
|
|
|
|
// Not found: create new sheet ...
|
|
|
|
tabSheet := ResRegPageControl.AddTabSheet;
|
|
|
|
tabSheet.Caption := sheetTitle;
|
|
|
|
tabSheet.Tag := AColIndex;
|
|
|
|
|
|
|
|
// ... and add ChartFrame
|
|
|
|
AChartFrame := TChartFrame.Create(tabSheet);
|
|
|
|
AChartFrame.Parent := tabSheet;
|
|
|
|
AChartFrame.Align := alClient;
|
|
|
|
AChartFrame.Chart.Legend.Alignment := laBottomCenter;
|
|
|
|
AChartFrame.Chart.Legend.ColumnCount := 3;
|
|
|
|
AChartFrame.Chart.Legend.TextFormat := tfHTML;
|
|
|
|
AChartFrame.Chart.BottomAxis.Intervals.MaxLength := 80;
|
|
|
|
AChartFrame.Chart.BottomAxis.Intervals.MinLength := 30;
|
2020-10-12 16:17:29 +00:00
|
|
|
with AChartFrame.Chart.AxisList.Add do
|
|
|
|
begin
|
|
|
|
Alignment := calRight;
|
|
|
|
Marks.Source := TListChartSource.Create(self);
|
|
|
|
Marks.Style := smsLabel;
|
|
|
|
Grid.Visible := false;
|
|
|
|
TickColor := clNone;
|
|
|
|
end;
|
|
|
|
with AChartFrame.Chart.AxisList.Add do
|
|
|
|
begin
|
|
|
|
Alignment := calTop;
|
|
|
|
Marks.Source := TListChartSource.Create(self);
|
|
|
|
Marks.Style := smsLabel;
|
|
|
|
Grid.Visible := false;
|
|
|
|
TickColor := clNone;
|
|
|
|
end;
|
2020-10-12 13:43:51 +00:00
|
|
|
|
|
|
|
// ... and add memo
|
|
|
|
AMemo := TMemo.Create(tabSheet);
|
|
|
|
AMemo.Parent := tabSheet;
|
|
|
|
AMemo.Align := alBottom;
|
|
|
|
AMemo.BorderStyle := bsNone;
|
|
|
|
AMemo.Font.Name := 'Courier New';
|
|
|
|
AMemo.Font.Size := 8;
|
|
|
|
AMemo.ReadOnly := true;
|
|
|
|
AMemo.Scrollbars := ssAutoBoth;
|
|
|
|
AMemo.WordWrap := false;
|
|
|
|
|
|
|
|
// ... and splitter
|
|
|
|
with TSplitter.Create(tabSheet) do
|
|
|
|
begin
|
|
|
|
Parent := tabSheet;
|
|
|
|
Align := alBottom;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
2020-10-11 22:31:17 +00:00
|
|
|
procedure TWLSFrm.DepInBtnClick(Sender: TObject);
|
|
|
|
var
|
|
|
|
index: integer;
|
|
|
|
begin
|
|
|
|
index := VarList.ItemIndex;
|
|
|
|
if (index > -1) and (DepVarEdit.Text = '') then
|
|
|
|
begin
|
|
|
|
DepVarEdit.Text := VarList.Items[index];
|
|
|
|
VarList.Items.Delete(index);
|
|
|
|
UpdateBtnStates;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
procedure TWLSFrm.DepOutBtnClick(Sender: TObject);
|
|
|
|
begin
|
|
|
|
if (DepVarEdit.Text <> '') then
|
|
|
|
begin
|
|
|
|
VarList.Items.Add(DepVarEdit.Text);
|
|
|
|
DepVarEdit.Text := '';
|
|
|
|
UpdateBtnStates;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
2020-10-12 13:43:51 +00:00
|
|
|
function TWLSFrm.GetPageCaption(AVarName: String): String;
|
|
|
|
begin
|
|
|
|
Result := 'Plot of ' + AVarName;
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
2020-10-11 22:31:17 +00:00
|
|
|
procedure TWLSFrm.IndInBtnClick(Sender: TObject);
|
|
|
|
var
|
|
|
|
i: integer;
|
|
|
|
begin
|
|
|
|
i := 0;
|
|
|
|
while (i < VarList.Items.Count) do
|
|
|
|
begin
|
|
|
|
if (VarList.Selected[i]) then
|
|
|
|
begin
|
|
|
|
IndVarList.Items.Add(VarList.Items[i]);
|
|
|
|
VarList.Items.Delete(i);
|
|
|
|
i := 0;
|
|
|
|
end else
|
|
|
|
inc(i);
|
|
|
|
end;
|
|
|
|
UpdateBtnStates;
|
|
|
|
end;
|
|
|
|
|
|
|
|
procedure TWLSFrm.IndOutBtnClick(Sender: TObject);
|
|
|
|
var
|
|
|
|
i: integer;
|
|
|
|
begin
|
|
|
|
i := 0;
|
|
|
|
while (i < IndVarList.Items.Count) do
|
|
|
|
begin
|
|
|
|
if IndVarlist.Selected[i] then
|
|
|
|
begin
|
|
|
|
VarList.Items.Add(IndVarList.Items[i]);
|
|
|
|
IndVarlist.Items.Delete(i);
|
|
|
|
i := 0;
|
|
|
|
end else
|
|
|
|
inc(i);
|
|
|
|
end;
|
|
|
|
UpdateBtnStates;
|
|
|
|
end;
|
2020-03-30 18:01:44 +00:00
|
|
|
|
2020-10-11 22:31:17 +00:00
|
|
|
|
|
|
|
procedure TWLSFrm.IndVarListDblClick(Sender: TObject);
|
|
|
|
var
|
|
|
|
index: Integer;
|
|
|
|
begin
|
|
|
|
index := IndVarList.ItemIndex;
|
|
|
|
if index > -1 then
|
|
|
|
begin
|
|
|
|
VarList.Items.Add(IndVarList.Items[index]);
|
|
|
|
IndVarlist.Items.Delete(index);
|
|
|
|
UpdateBtnStates;
|
2020-03-30 18:01:44 +00:00
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
2020-10-12 16:17:29 +00:00
|
|
|
|
|
|
|
procedure TWLSFrm.PlotSquaredResiduals(AIndepCols: IntDyneVec;
|
2020-10-17 22:42:41 +00:00
|
|
|
ADepCol: Integer; const AIndepValues: DblDyneMat; const ADepValues: DblDyneVec);
|
|
|
|
var
|
|
|
|
x, y: DblDyneVec;
|
|
|
|
i, xCol, yCol: Integer;
|
|
|
|
regressionRes: TBivariateRegressionResults;
|
|
|
|
memo: TMemo;
|
|
|
|
chartFrame: TChartFrame;
|
|
|
|
xLabel, yLabel: String;
|
|
|
|
numIndepCols: Integer;
|
|
|
|
begin
|
|
|
|
// We will plot the selected vector of the independent values vertically,
|
|
|
|
// and the dependent values horizontally.
|
|
|
|
|
|
|
|
xCol := ADepCol;
|
|
|
|
x := VecCopy(ADepValues);
|
|
|
|
xLabel := OS3MainFrm.DataGrid.Cells[xCol, 0];
|
|
|
|
numIndepCols := Length(AIndepCols);
|
|
|
|
|
|
|
|
for i := 0 to numIndepCols-1 do
|
|
|
|
begin
|
|
|
|
yCol := AIndepCols[i];
|
|
|
|
yLabel := OS3MainFrm.DataGrid.Cells[yCol, 0];
|
|
|
|
y := MatColVector(AIndepValues, yCol-1);
|
|
|
|
SortOnX(x, y);
|
|
|
|
|
|
|
|
// Regression
|
|
|
|
BivariateRegression(x, y, CONF_LEVEL, regressionRes);
|
|
|
|
|
|
|
|
// Create tab with chart and report controls
|
|
|
|
CreateOrGetChartFrame(yCol-1, yLabel, memo, chartFrame); // -1 because yCol i is in grid units
|
|
|
|
|
|
|
|
// Plot
|
|
|
|
PlotXY(chartFrame, x, y, regressionRes, xLabel, yLabel);
|
|
|
|
|
|
|
|
// Print the descriptive statistics
|
|
|
|
WriteDescriptiveReport(memo, regressionRes, xLabel, yLabel);
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
(*
|
2020-10-12 16:17:29 +00:00
|
|
|
var
|
|
|
|
xCol, yCol: Integer;
|
|
|
|
xLabel, yLabel: String;
|
|
|
|
i: Integer;
|
|
|
|
colNoSelected: IntDyneVec = nil;
|
|
|
|
xPoints: DblDyneVec = nil;
|
|
|
|
yPoints: DblDyneVec = nil;
|
|
|
|
regressionRes: TBivariateRegressionResults;
|
|
|
|
memo: TMemo;
|
|
|
|
chartFrame: TChartFrame;
|
|
|
|
begin
|
|
|
|
SetLength(colNoSelected, 2);
|
|
|
|
xCol := ADepCol;
|
|
|
|
|
|
|
|
for i := 0 to ANumIndepCols-1 do
|
|
|
|
begin
|
|
|
|
// Get values
|
|
|
|
yCol := AIndepCols[i];
|
|
|
|
colNoSelected[0] := xCol;
|
|
|
|
colNoSelected[1] := yCol;
|
|
|
|
xLabel := OS3MainFrm.DataGrid.Cells[xCol, 0];
|
|
|
|
yLabel := OS3MainFrm.DataGrid.Cells[yCol, 0];
|
2020-10-17 22:42:41 +00:00
|
|
|
xPoints := CollectVecValues(OS3MainFrm.DataGrid, xCol, colNoSelected);
|
|
|
|
yPoints := CollectVecValues(OS3MainFrm.DataGrid, yCol, colNoSelected);
|
2020-10-12 16:17:29 +00:00
|
|
|
SortOnX(xPoints, yPoints);
|
|
|
|
|
|
|
|
// Regression
|
2020-10-14 14:28:59 +00:00
|
|
|
BivariateRegression(xPoints, yPoints, AConfLevel, regressionRes);
|
2020-10-12 16:17:29 +00:00
|
|
|
|
|
|
|
// Create tab with chart and report controls
|
|
|
|
CreateOrGetChartFrame(yCol, yLabel, memo, chartFrame);
|
|
|
|
|
|
|
|
// Plot
|
|
|
|
PlotXY(chartFrame, xPoints, yPoints, regressionRes, xLabel, yLabel);
|
|
|
|
|
|
|
|
// Print the descriptive statistics
|
|
|
|
WriteDescriptiveReport(memo, regressionRes, xLabel, yLabel);
|
|
|
|
end;
|
|
|
|
end;
|
2020-10-17 22:42:41 +00:00
|
|
|
*)
|
2020-10-12 16:17:29 +00:00
|
|
|
|
|
|
|
procedure TWLSFrm.PlotXY(AChartFrame: TChartFrame; const XPoints, YPoints: DblDyneVec;
|
|
|
|
const ARegressionResults: TBivariateRegressionResults; const XLabel, YLabel: String);
|
|
|
|
var
|
|
|
|
xpts: DblDyneVec = nil;
|
|
|
|
ypts: DblDyneVec = nil;
|
|
|
|
conf: DblDyneVec = nil;
|
|
|
|
ext: TDoubleRect;
|
|
|
|
i: Integer;
|
|
|
|
rightLabels, topLabels: TListChartSource;
|
|
|
|
ser: TChartSeries;
|
|
|
|
begin
|
|
|
|
rightLabels := AChartFrame.Chart.AxisList[2].Marks.Source as TListChartSource;
|
|
|
|
rightLabels.Clear;
|
|
|
|
topLabels := AChartFrame.Chart.AxisList[3].Marks.Source as TListChartSource;
|
|
|
|
topLabels.Clear;
|
|
|
|
AChartFrame.Clear;
|
|
|
|
|
|
|
|
with ARegressionResults do
|
|
|
|
AChartFrame.SetFooter(Format('R(X,Y) = %.3f, Slope = %.3f, Intercept = %.3f', [
|
|
|
|
R, Slope, Intercept
|
|
|
|
]));
|
|
|
|
|
|
|
|
// Data points
|
|
|
|
AChartFrame.SetXTitle(XLabel);
|
|
|
|
AChartFrame.SetYTitle(YLabel);
|
|
|
|
AChartFrame.PlotXY(ptSymbols, XPoints, YPoints, nil, nil, 'Data', DATA_COLORS[0]);
|
|
|
|
|
|
|
|
// Regression line
|
|
|
|
SetLength(xpts, 2);
|
|
|
|
SetLengtH(ypts, 2);
|
|
|
|
ext := AChartFrame.Chart.GetFullExtent;
|
|
|
|
xpts[0] := ext.a.x;
|
|
|
|
xpts[1] := ext.b.x;
|
|
|
|
with ARegressionResults do
|
|
|
|
begin
|
|
|
|
ypts[0] := Intercept + Slope * xpts[0];
|
|
|
|
ypts[1] := Intercept + Slope * xpts[1];
|
|
|
|
end;
|
|
|
|
AChartFrame.PlotXY(ptLines, xpts, ypts, nil, nil, 'Predicted', clBlack);
|
|
|
|
rightLabels.Add(ypts[1], ypts[1], 'Predicted');
|
|
|
|
|
|
|
|
// Upper ...
|
|
|
|
SetLength(conf, ARegressionResults.Count);
|
|
|
|
for i := 0 to High(conf) do
|
|
|
|
conf[i] := ARegressionResults.ConfidenceLimits(XPoints[i], true);
|
|
|
|
ser := AChartFrame.PlotXY(ptLines, XPoints, conf, nil, nil, 'Upper confidence band', clRed);
|
|
|
|
rightLabels.Add(ser.yValue[ser.Count-1], ser.yValue[ser.Count-1], 'UCL');
|
|
|
|
|
|
|
|
// ... and lower confidence limit curves
|
|
|
|
for i := 0 to High(conf) do
|
|
|
|
conf[i] := ARegressionResults.ConfidenceLimits(XPoints[i], false);
|
|
|
|
ser := AChartFrame.PlotXY(ptLines, XPoints, conf, nil, nil, 'Lower confidence band', clRed);
|
|
|
|
rightLabels.Add(ser.yValue[ser.Count-1], ser.yValue[ser.Count-1], 'LCL');
|
|
|
|
|
|
|
|
// Mean lines
|
|
|
|
with ARegressionResults do
|
|
|
|
begin
|
|
|
|
AChartFrame.VertLine(XMean, clGreen, psDashDot, 'Mean ' + XLabel);
|
|
|
|
topLabels.Add(XMean, XMean, 'Mean ' + XLabel);
|
|
|
|
|
|
|
|
AChartFrame.HorLine(YMean, clGreen, psDash, 'Mean ' + YLabel);
|
|
|
|
rightLabels.Add(YMean, YMean, 'Mean ' + YLabel);
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
2020-10-12 13:43:51 +00:00
|
|
|
{ Routine obtains predicted raw and standardized scores and their
|
|
|
|
residuals. It is assumed that the dependent variable is last in the
|
|
|
|
list of variable column pointers stored in the ColNoSelected vector.
|
|
|
|
Get the z predicted score and its residual }
|
2020-10-17 22:42:41 +00:00
|
|
|
procedure TWLSFrm.Predict(const xData: DblDyneMat; const yData: DblDyneVec;
|
|
|
|
ARegressionResults: TMultipleRegressionResults);
|
2020-10-11 22:31:17 +00:00
|
|
|
var
|
2020-10-17 22:42:41 +00:00
|
|
|
means, stddevs, variances: DblDyneVec;
|
|
|
|
i, j, n, m: Integer;
|
|
|
|
zPred: DblDyneVec = nil;
|
|
|
|
// zResid: DblDyneVec = nil;
|
|
|
|
rawPred: DblDyneVec = nil;
|
|
|
|
rawResid: DblDyneVec = nil;
|
|
|
|
sqrResid: DblDyneVec = nil;
|
2020-03-30 18:01:44 +00:00
|
|
|
begin
|
2020-10-17 22:42:41 +00:00
|
|
|
MatSize(xData, n, m);
|
|
|
|
MatColMeanVarStdDev(xData, means, variances, stddevs);
|
2020-10-14 14:28:59 +00:00
|
|
|
|
2020-10-17 22:42:41 +00:00
|
|
|
SetLength(zPred, n);
|
|
|
|
// SetLength(zResid, n);
|
|
|
|
SetLength(rawPred, n);
|
|
|
|
SetLength(rawResid, n);
|
|
|
|
SetLength(sqrResid, n);
|
2020-03-30 18:01:44 +00:00
|
|
|
|
2020-10-17 22:42:41 +00:00
|
|
|
for i := 0 to n-1 do
|
2020-10-12 13:43:51 +00:00
|
|
|
begin
|
2020-10-17 22:42:41 +00:00
|
|
|
zPred[i] := 0;
|
|
|
|
for j := 0 to m-1 do
|
|
|
|
zPred[i] := zPred[i] + (xData[i, j] - means[j]) / stdDevs[j] * ARegressionResults.Beta[j];
|
|
|
|
|
|
|
|
{
|
|
|
|
zResid[i] := (yData[i] - ARegressionResults.MeanY) / ARegressionResults.StdDevY;
|
|
|
|
|
|
|
|
w: THIS IS NOT CORRECT. Remove above line because it is not needed.
|
2020-10-12 13:43:51 +00:00
|
|
|
|
2020-10-17 22:42:41 +00:00
|
|
|
This is the code used by the original routine
|
2020-10-12 13:43:51 +00:00
|
|
|
if StdDevs[NoVars-1] <> 0.0 then
|
|
|
|
begin
|
|
|
|
Index := ColNoSelected[NoVars-1];
|
|
|
|
z2 := StrToFloat(OS3MainFrm.DataGrid.Cells[Index,i]);
|
|
|
|
z2 := (z2 - Means[NoVars-1]) / StdDevs[NoVars-1]; // z score
|
2020-10-14 14:28:59 +00:00
|
|
|
OS3MainFrm.DataGrid.Cells[col2, i] := Format('%.4f',[z2 - zpredicted]); // z residual
|
2020-10-12 13:43:51 +00:00
|
|
|
end;
|
2020-10-17 22:42:41 +00:00
|
|
|
}
|
2020-10-12 13:43:51 +00:00
|
|
|
|
2020-10-17 22:42:41 +00:00
|
|
|
rawPred[i] := ARegressionResults.Coeffs[m]; // intercept
|
|
|
|
for j := 0 to m-1 do
|
|
|
|
rawPred[i] := rawPred[i] + ARegressionResults.Coeffs[j] * xData[i, j];
|
2020-10-12 13:43:51 +00:00
|
|
|
|
2020-10-17 22:42:41 +00:00
|
|
|
rawResid[i] := rawPred[i] - yData[i];
|
|
|
|
sqrResid[i] := sqr(rawResid[i]);
|
2020-10-12 13:43:51 +00:00
|
|
|
end;
|
|
|
|
|
2020-10-17 22:42:41 +00:00
|
|
|
AddVariable('z Pred', zPred, '%.4f');
|
|
|
|
// AddGridColumn('z Resid', zResid, '%.4f');
|
|
|
|
AddVariable('Raw Pred', rawPred, '%.3f');
|
|
|
|
AddVariable('Raw Resid', rawResid, '%.3f');
|
|
|
|
AddVariable('Sqr Resid', sqrResid, '%.3f');
|
2020-03-30 18:01:44 +00:00
|
|
|
end;
|
|
|
|
|
2020-10-12 13:43:51 +00:00
|
|
|
|
2020-10-17 22:42:41 +00:00
|
|
|
{ Prepares the data for the analysis by extracting all needed data from the
|
|
|
|
grid:
|
|
|
|
- AIndepCols: integer array containing the grid column indexes of the
|
|
|
|
independent variables to be used
|
|
|
|
- ADepCol: grid column index of the dependent variable to be used
|
|
|
|
- AWeightCol: optional grid column index of the weight data to be used
|
|
|
|
- ARowLabels: string array containing the names of the independent variables
|
|
|
|
as well of the dependent variable (last)
|
|
|
|
- xValues: matrix with all independent values. The columns of the matrix
|
|
|
|
correspond to the variables, the row correspond to the cases.
|
|
|
|
- yValues: vector with the dependent variable values
|
|
|
|
}
|
|
|
|
function TWLSFrm.PrepareData(out AIndepCols: IntDyneVec; out ADepCol: Integer;
|
|
|
|
out AWeightCol: Integer; out ARowLabels: StrDyneVec;
|
|
|
|
out xValues: DblDyneMat; out yValues: DblDyneVec): Boolean;
|
2020-10-12 17:09:06 +00:00
|
|
|
var
|
|
|
|
i: Integer;
|
|
|
|
msg: String;
|
|
|
|
C: TWinControl;
|
2020-10-17 22:42:41 +00:00
|
|
|
numIndepCols: Integer;
|
2020-10-12 17:09:06 +00:00
|
|
|
begin
|
|
|
|
Result := false;
|
|
|
|
AIndepCols := nil;
|
|
|
|
ARowLabels := nil;
|
2020-10-17 22:42:41 +00:00
|
|
|
xValues := nil;
|
|
|
|
yvalues := nil;
|
2020-10-12 17:09:06 +00:00
|
|
|
|
|
|
|
if not Validate(msg, C) then
|
|
|
|
begin
|
|
|
|
C.SetFocus;
|
|
|
|
ErrorMsg(msg);
|
|
|
|
exit;
|
|
|
|
end;
|
|
|
|
|
2020-10-17 22:42:41 +00:00
|
|
|
numIndepCols := IndVarList.Items.Count;
|
2020-10-12 17:09:06 +00:00
|
|
|
ADepCol := GetVariableIndex(OS3MainFrm.DataGrid, DepVarEdit.Text);
|
|
|
|
AWeightCol := GetVariableIndex(OS3MainFrm.DataGrid, WeightVarEdit.Text);
|
|
|
|
|
2020-10-17 22:42:41 +00:00
|
|
|
SetLength(AIndepCols, numIndepCols);
|
|
|
|
SetLength(ARowLabels, numIndepCols + 1); // +1 to add independent column label
|
2020-10-12 17:09:06 +00:00
|
|
|
|
2020-10-17 22:42:41 +00:00
|
|
|
for i := 0 to numIndepCols-1 do
|
2020-10-12 17:09:06 +00:00
|
|
|
begin
|
|
|
|
AIndepCols[i] := GetVariableIndex(OS3MainFrm.DataGrid, IndVarList.Items[i]);
|
|
|
|
if AIndepCols[i] = -1 then
|
|
|
|
begin
|
|
|
|
ErrorMsg('Dependent variable %s not found.', [IndVarList.Items[i]]);
|
|
|
|
exit;
|
|
|
|
end;
|
|
|
|
ARowLabels[i] := IndVarList.Items[i];
|
|
|
|
end;
|
2020-10-17 22:42:41 +00:00
|
|
|
ARowLabels[numIndepCols] := DepVarEdit.Text;
|
2020-10-12 21:53:18 +00:00
|
|
|
|
|
|
|
// Check variable types: all of them must be numeric (float or integer)
|
|
|
|
if not IsNumericCol(ADepCol) then
|
|
|
|
begin
|
|
|
|
ErrorMsg('Incorrect data type of dependent variable.');
|
|
|
|
exit;
|
|
|
|
end;
|
|
|
|
|
2020-10-17 22:42:41 +00:00
|
|
|
for i := 0 to numIndepCols-1 do
|
2020-10-12 21:53:18 +00:00
|
|
|
if not IsNumericCol(AIndepCols[i]) then
|
|
|
|
begin
|
|
|
|
ErrorMsg('Incorrect data type of independent variable "%s"', [ARowLabels[i]]);
|
|
|
|
exit;
|
|
|
|
end;
|
|
|
|
|
|
|
|
if (AWeightCol > -1) and (not IsNumericCol(AWeightCol)) then
|
|
|
|
begin
|
|
|
|
ErrorMsg('Incorrect data type of weight variable.');
|
|
|
|
exit;
|
|
|
|
end;
|
|
|
|
|
2020-10-17 22:42:41 +00:00
|
|
|
xValues := CollectMatValues(OS3MainFrm.DataGrid, AIndepCols);
|
|
|
|
yValues := CollectVecValues(OS3MainFrm.DataGrid, ADepCol);
|
|
|
|
|
2020-10-12 17:09:06 +00:00
|
|
|
Result := true;
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
2020-10-12 21:53:18 +00:00
|
|
|
{ Runs the ordinary least squares regression on the grid data }
|
2020-10-17 22:42:41 +00:00
|
|
|
function TWLSFrm.Process_OLSRegression(AIndepCols: IntDyneVec;
|
|
|
|
ADepCol: Integer; const ARowLabels: StrDyneVec;
|
|
|
|
const xValues: DblDyneMat; const yValues: DblDyneVec): Boolean;
|
2020-10-12 21:53:18 +00:00
|
|
|
var
|
|
|
|
lReport: TStrings;
|
2020-10-17 22:42:41 +00:00
|
|
|
regressionRes: TMultipleRegressionResults;
|
|
|
|
i: Integer;
|
|
|
|
numIndepCols: Integer;
|
2020-10-12 21:53:18 +00:00
|
|
|
begin
|
|
|
|
Result := false;
|
2020-10-17 22:42:41 +00:00
|
|
|
numIndepCols := Length(AIndepCols);
|
2020-10-12 21:53:18 +00:00
|
|
|
|
|
|
|
lReport := TStringList.Create;
|
|
|
|
try
|
|
|
|
lReport.Add('ORDINARY LEAST SQUARES (OLS) REGRESSION RESULTS');
|
|
|
|
lReport.Add('');
|
2020-10-17 22:42:41 +00:00
|
|
|
lReport.Add('Dependent variable: ');
|
|
|
|
lReport.Add(' ' + OS3MainFrm.DataGrid.Cells[ADepCol, 0]);
|
|
|
|
lReport.Add('Independent variables:');
|
|
|
|
for i := 0 to numIndepCols-1 do
|
|
|
|
lReport.Add(' ' + ARowLabels[i]);
|
|
|
|
lReport.Add('');
|
|
|
|
|
|
|
|
Result := RegressionAndReport(ARowLabels, xValues, yValues, regressionRes, lReport);
|
|
|
|
|
|
|
|
if Result then
|
|
|
|
begin
|
|
|
|
Predict(xValues, yValues, regressionRes);
|
|
|
|
OLSReportFrame.DisplayReport(lReport);
|
|
|
|
end;
|
|
|
|
|
|
|
|
finally
|
|
|
|
lReport.Free;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
function TWLSFrm.Process_SquaredResidualsRegression(AIndepCols: IntDyneVec;
|
|
|
|
const ARowLabels: StrDyneVec; const xValues: DblDyneMat; out AWeights: DblDyneVec): Boolean;
|
|
|
|
var
|
|
|
|
lReport: TStrings;
|
|
|
|
sqrResiduals: DblDyneVec;
|
|
|
|
predSqrResiduals: DblDyneVec;
|
|
|
|
regressionRes: TMultipleRegressionResults;
|
|
|
|
i, depCol, numIndepCols: Integer;
|
|
|
|
begin
|
|
|
|
AWeights := nil;
|
|
|
|
ResidualsRegPage.TabVisible := WeightChk.Checked;
|
|
|
|
|
|
|
|
if not WeightChk.Checked then
|
|
|
|
exit;
|
|
|
|
|
|
|
|
numIndepCols := Length(AIndepCols);
|
|
|
|
|
|
|
|
// The last grid column (added by Process_ODSRegression) contains the
|
|
|
|
// squared residuals which will be fitted here.
|
|
|
|
depCol := NoVariables;
|
|
|
|
sqrResiduals := CollectVecValues(OS3MainFrm.DataGrid, depCol);
|
|
|
|
|
|
|
|
lReport := TStringList.Create;
|
|
|
|
try
|
|
|
|
lReport.Add('REGRESSION OF SQUARED RESIDUALS ON INDEPENDENT VARIABLES');
|
|
|
|
lReport.Add('');
|
|
|
|
lReport.Add('Dependent variable: ');
|
|
|
|
lReport.Add(' ' + ARowLabels[numIndepCols]);
|
|
|
|
lReport.Add('Independent variables:');
|
|
|
|
for i := 0 to numIndepCols-1 do
|
|
|
|
lReport.Add(' ' + ARowLabels[i]);
|
|
|
|
lReport.Add('');
|
2020-10-12 21:53:18 +00:00
|
|
|
|
2020-10-17 22:42:41 +00:00
|
|
|
Result := RegressionAndReport(ARowLabels, xValues, sqrResiduals, regressionRes, lReport);
|
2020-10-12 21:53:18 +00:00
|
|
|
|
2020-10-17 22:42:41 +00:00
|
|
|
if Result then
|
|
|
|
begin
|
|
|
|
// Display the results
|
|
|
|
ResidualsRegReportFrame.DisplayReport(lReport);
|
2020-10-12 21:53:18 +00:00
|
|
|
|
2020-10-17 22:42:41 +00:00
|
|
|
// Calculate weights and store them in the grid
|
|
|
|
CalcWeights(xValues, regressionRes.Coeffs, predSqrResiduals, AWeights);
|
2020-10-12 21:53:18 +00:00
|
|
|
|
2020-10-17 22:42:41 +00:00
|
|
|
// Display squared residuals for each independent variable
|
|
|
|
PlotSquaredResiduals(AIndepCols, depCol, xValues, sqrResiduals);
|
2020-10-12 21:53:18 +00:00
|
|
|
|
2020-10-17 22:42:41 +00:00
|
|
|
// Store weights to the grid
|
|
|
|
if SaveChk.Checked then
|
|
|
|
AddWeightsToGrid(predSqrResiduals, AWeights);
|
|
|
|
end;
|
2020-10-12 21:53:18 +00:00
|
|
|
|
|
|
|
finally
|
|
|
|
lReport.Free;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
2020-10-17 22:42:41 +00:00
|
|
|
function TWLSFrm.Process_WeightedRegression(AIndepCols: IntDyneVec;
|
|
|
|
const ARowLabels: StrDyneVec; const xValues: DblDyneMat;
|
|
|
|
const yValues: DblDyneVec; const AWeights: DblDyneVec; SubtractMeans: Boolean): Boolean;
|
2020-10-12 21:53:18 +00:00
|
|
|
var
|
2020-10-17 22:42:41 +00:00
|
|
|
i, j, n, m: Integer;
|
|
|
|
regressionRes: TMultipleRegressionResults;
|
2020-10-12 21:53:18 +00:00
|
|
|
lReport: TStrings;
|
2020-10-17 22:42:41 +00:00
|
|
|
means: DblDyneVec;
|
2020-10-12 21:53:18 +00:00
|
|
|
begin
|
2020-10-17 22:42:41 +00:00
|
|
|
MatSize(xValues, n, m);
|
|
|
|
|
|
|
|
for i :=0 to n-1 do
|
|
|
|
for j := 0 to m-1 do
|
|
|
|
xValues[i, j] := xValues[i, j] * AWeights[i];
|
|
|
|
|
|
|
|
if SubtractMeans then
|
|
|
|
begin
|
|
|
|
means := MatRowMeans(xValues);
|
|
|
|
for i := 0 to n-1 do
|
|
|
|
for j := 0 to m-1 do
|
|
|
|
xValues[i, j] := xValues[i, j] - means[i];
|
|
|
|
end;
|
|
|
|
|
2020-10-12 21:53:18 +00:00
|
|
|
lReport := TStringList.Create;
|
|
|
|
try
|
2020-10-17 22:42:41 +00:00
|
|
|
lReport.Add('WEIGHTED LEAST SQUARES (WLS) REGRESSION RESULTS');
|
|
|
|
lReport.Add('');
|
|
|
|
lReport.Add('Dependent variable: ');
|
|
|
|
lReport.Add(' ' + ARowLabels[m]);
|
|
|
|
lReport.Add('Independent variables:');
|
|
|
|
for i := 0 to m-1 do
|
|
|
|
lReport.Add(' ' + ARowLabels[i]);
|
2020-10-12 21:53:18 +00:00
|
|
|
lReport.Add('');
|
|
|
|
|
2020-10-17 22:42:41 +00:00
|
|
|
Result := RegressionAndReport(ARowLabels, xValues, yValues, regressionRes, lReport);
|
2020-10-12 21:53:18 +00:00
|
|
|
|
2020-10-17 22:42:41 +00:00
|
|
|
if Result then
|
|
|
|
WLSReportFrame.DisplayReport(lReport);
|
2020-10-12 21:53:18 +00:00
|
|
|
|
|
|
|
finally
|
|
|
|
lReport.Free;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
2020-10-17 22:42:41 +00:00
|
|
|
function TWLSFrm.RegressionAndReport(const ARowLabels: StrDyneVec;
|
|
|
|
const xValues: DblDyneMat; const yValues: DblDyneVec;
|
|
|
|
out ARegressionResults: TMultipleRegressionResults; AReport: TStrings): Boolean;
|
|
|
|
var
|
|
|
|
err: TRegressionError;
|
|
|
|
begin
|
|
|
|
err := MultipleRegression(xValues, yValues, CONF_LEVEL, ARegressionResults);
|
|
|
|
case err of
|
|
|
|
regOK: ;
|
|
|
|
regTooFewValues: ErrorMsg('At least two values required for regression.');
|
|
|
|
regStdDevZero: ErrorMsg('Standard deviation is zero.');
|
|
|
|
end;
|
|
|
|
Result := (err = regOK);
|
|
|
|
|
|
|
|
ARegressionResults.WriteCoeffsReport(AReport, ARowLabels);
|
|
|
|
AReport.Add('');
|
|
|
|
AReport.Add('');
|
|
|
|
|
|
|
|
ARegressionResults.WriteANOVAReport(AReport);
|
|
|
|
AReport.Add('');
|
|
|
|
AReport.Add('');
|
|
|
|
|
|
|
|
ARegressionResults.WriteVarCovarReport(AReport, ARowLabels);
|
|
|
|
AReport.Add('');
|
|
|
|
AReport.Add('');
|
|
|
|
|
|
|
|
ARegressionResults.WriteCorrelationReport(AReport, ARowLabels);
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
2020-10-11 22:31:17 +00:00
|
|
|
procedure TWLSFrm.Reset;
|
|
|
|
var
|
|
|
|
i: integer;
|
|
|
|
begin
|
|
|
|
inherited;
|
|
|
|
|
|
|
|
VarList.Clear;
|
|
|
|
for i := 0 to NoVariables - 1 do
|
|
|
|
VarList.Items.Add(OS3MainFrm.DataGrid.Cells[i+1,0]);
|
|
|
|
IndVarList.Clear;
|
|
|
|
|
2020-10-12 16:49:08 +00:00
|
|
|
DepVarEdit.Clear;
|
|
|
|
WeightVarEdit.Clear;
|
|
|
|
|
|
|
|
if OLSReportFrame <> nil then
|
|
|
|
OLSReportFrame.Clear;
|
|
|
|
if ResidualsRegReportFrame <> nil then
|
|
|
|
ResidualsRegReportFrame.clear;
|
|
|
|
if WLSReportFrame <> nil then
|
|
|
|
WLSReportFrame.Clear;
|
|
|
|
|
2020-10-11 22:31:17 +00:00
|
|
|
WeightChk.Checked := true;
|
2020-10-12 16:49:08 +00:00
|
|
|
UserWeightsChk.Checked := false;
|
|
|
|
OriginChk.Checked := false;
|
|
|
|
Origin2Chk.Checked := false;
|
|
|
|
|
|
|
|
UpdateBtnStates;
|
2020-10-11 22:31:17 +00:00
|
|
|
end;
|
|
|
|
|
|
|
|
|
2020-03-30 18:01:44 +00:00
|
|
|
procedure TWLSFrm.UpdateBtnStates;
|
|
|
|
var
|
|
|
|
i: Integer;
|
|
|
|
lSelected: Boolean;
|
|
|
|
begin
|
2020-10-11 22:31:17 +00:00
|
|
|
inherited;
|
|
|
|
|
2020-03-30 18:01:44 +00:00
|
|
|
lSelected := false;
|
|
|
|
for i:=0 to VarList.Items.Count-1 do
|
|
|
|
if Varlist.Selected[i] then
|
|
|
|
begin
|
|
|
|
lSelected := true;
|
|
|
|
break;
|
|
|
|
end;
|
|
|
|
DepInBtn.Enabled := lSelected and (DepVarEdit.Text = '');
|
|
|
|
IndInBtn.Enabled := lSelected;
|
2020-10-12 16:49:08 +00:00
|
|
|
WeightInBtn.Enabled := lSelected and (WeightVarEdit.Text = '') and UserWeightsChk.Checked;
|
2020-03-30 18:01:44 +00:00
|
|
|
|
|
|
|
lSelected := false;
|
|
|
|
for i:=0 to IndVarList.Items.Count-1 do
|
|
|
|
if IndVarList.Selected[i] then
|
|
|
|
begin
|
|
|
|
lSelected := true;
|
|
|
|
break;
|
|
|
|
end;
|
|
|
|
DepOutBtn.Enabled := (DepVarEdit.Text <> '');
|
|
|
|
IndOutBtn.Enabled := lSelected;
|
2020-10-12 16:49:08 +00:00
|
|
|
WeightOutBtn.Enabled := (WeightVarEdit.Text <> '') and UserWeightsChk.Checked;
|
|
|
|
|
|
|
|
if OLSReportFrame <> nil then
|
|
|
|
OLSReportFrame.UpdateBtnStates;
|
|
|
|
if ResidualsRegReportFrame <> nil then
|
|
|
|
ResidualsRegReportFrame.UpdateBtnStates;
|
|
|
|
if WLSReportFrame <> nil then
|
|
|
|
WLSReportFrame.UpdateBtnStates;
|
|
|
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
procedure TWLSFrm.UserWeightsChkChange(Sender: TObject);
|
|
|
|
begin
|
|
|
|
WeightVarEdit.Enabled := UserWeightsChk.Checked;
|
|
|
|
Label4.Enabled := WeightVarEdit.Enabled;
|
|
|
|
WeightInBtn.Enabled := UserWeightsChk.Checked and (VarList.ItemIndex > -1) and (WeightVarEdit.Text = '');
|
|
|
|
WeightOutBtn.Enabled := UserWeightsChk.Checked and (WeightVarEdit.Text <> '');
|
2020-03-30 18:01:44 +00:00
|
|
|
end;
|
|
|
|
|
|
|
|
|
2020-10-11 22:31:17 +00:00
|
|
|
function TWLSFrm.Validate(out AMsg: String; out AControl: TWinControl): Boolean;
|
|
|
|
begin
|
|
|
|
Result := false;
|
|
|
|
|
|
|
|
if DepVarEdit.Text = '' then
|
|
|
|
begin
|
|
|
|
AControl := DepVarEdit;
|
|
|
|
AMsg := 'No dependent variable selected.';
|
|
|
|
exit;
|
|
|
|
end;
|
|
|
|
|
|
|
|
if IndVarList.Items.Count = 0 then
|
|
|
|
begin
|
|
|
|
AControl := VarList;
|
|
|
|
AMsg := 'No independent variables selected.';
|
|
|
|
exit;
|
|
|
|
end;
|
|
|
|
|
|
|
|
Result := true;
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
procedure TWLSFrm.VarListDblClick(Sender: TObject);
|
|
|
|
var
|
|
|
|
index: Integer;
|
|
|
|
begin
|
|
|
|
index := VarList.ItemIndex;
|
|
|
|
if index > -1 then
|
|
|
|
begin
|
|
|
|
if DepVarEdit.Text = '' then
|
|
|
|
DepVarEdit.Text := VarList.Items[index]
|
|
|
|
else
|
|
|
|
IndVarList.Items.Add(VarList.Items[index]);
|
|
|
|
VarList.Items.Delete(index);
|
|
|
|
UpdateBtnStates;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
procedure TWLSFrm.VarListSelectionChange(Sender: TObject; User: boolean);
|
|
|
|
begin
|
|
|
|
UpdateBtnStates;
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
2020-10-12 16:49:08 +00:00
|
|
|
procedure TWLSFrm.WeightInBtnClick(Sender: TObject);
|
2020-10-11 22:31:17 +00:00
|
|
|
var
|
|
|
|
index: integer;
|
|
|
|
begin
|
|
|
|
index := VarList.ItemIndex;
|
2020-10-12 16:49:08 +00:00
|
|
|
if (index > -1) and (WeightVarEdit.Text = '') then
|
2020-10-11 22:31:17 +00:00
|
|
|
begin
|
2020-10-12 16:49:08 +00:00
|
|
|
WeightVarEdit.Text := VarList.Items[index];
|
2020-10-11 22:31:17 +00:00
|
|
|
VarList.Items.Delete(index);
|
|
|
|
end;
|
|
|
|
UpdateBtnStates;
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
2020-10-12 16:49:08 +00:00
|
|
|
procedure TWLSFrm.WeightOutBtnClick(Sender: TObject);
|
2020-10-11 22:31:17 +00:00
|
|
|
begin
|
2020-10-12 16:49:08 +00:00
|
|
|
if (WeightVarEdit.Text <> '') then
|
2020-10-11 22:31:17 +00:00
|
|
|
begin
|
2020-10-12 16:49:08 +00:00
|
|
|
VarList.Items.Add(WeightVarEdit.Text);
|
|
|
|
WeightVarEdit.Text := '';
|
2020-10-11 22:31:17 +00:00
|
|
|
end;
|
|
|
|
UpdateBtnStates;
|
|
|
|
end;
|
2020-03-30 18:01:44 +00:00
|
|
|
|
2020-10-12 16:17:29 +00:00
|
|
|
|
|
|
|
procedure TWLSFrm.WriteDescriptiveReport(AMemo: TMemo;
|
|
|
|
const ARegressionResults: TBivariateRegressionResults;
|
|
|
|
const XLabel, YLabel: String);
|
|
|
|
var
|
|
|
|
lReport: TStrings;
|
|
|
|
begin
|
|
|
|
lReport := TStringList.Create;
|
|
|
|
try
|
2020-10-17 22:42:41 +00:00
|
|
|
lReport.Add(' Variable Mean Variance Std.Dev. ');
|
|
|
|
lReport.Add('------------ ------------ ------------ ------------');
|
2020-10-12 16:17:29 +00:00
|
|
|
with ARegressionResults do
|
|
|
|
begin
|
2020-10-17 22:42:41 +00:00
|
|
|
lReport.Add('%12s %12.2f %12.2f %12.2f', [xLabel, XMean, XVariance, XStdDev]);
|
|
|
|
lReport.Add('%12s %12.2f %12.2f %12.2f', [yLabel, YMean, YVariance, YStdDev]);
|
2020-10-12 16:17:29 +00:00
|
|
|
lReport.Add('');
|
|
|
|
lReport.Add('Regression:');
|
|
|
|
lReport.Add(' Correlation: %8.3f', [R]);
|
|
|
|
lReport.Add(' Slope: %8.3f', [Slope]);
|
|
|
|
lReport.Add(' Intercept: %8.3f', [Intercept]);
|
|
|
|
lReport.Add(' Standard Error of Estimate: %8.3f', [StdErrorPredicted]);
|
|
|
|
lReport.Add(' Number of good cases: %8d', [Count]);
|
|
|
|
end;
|
|
|
|
AMemo.Lines.Assign(lReport);
|
|
|
|
finally
|
|
|
|
lReport.Free;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
2020-03-30 18:01:44 +00:00
|
|
|
end.
|
|
|
|
|