LazStats: Massive refactoring of LSMRegUnit re-using general regression routines.

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@7782 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz
2020-10-19 08:24:46 +00:00
parent dfffbcf6f8
commit b93c6936bf
8 changed files with 737 additions and 370 deletions

View File

@ -49,6 +49,11 @@
<DebugInfoType Value="dsDwarf2Set"/> <DebugInfoType Value="dsDwarf2Set"/>
<TrashVariables Value="True"/> <TrashVariables Value="True"/>
</Debugging> </Debugging>
<Options>
<Win32>
<GraphicApplication Value="True"/>
</Win32>
</Options>
</Linking> </Linking>
</CompilerOptions> </CompilerOptions>
</Item2> </Item2>

View File

@ -50,9 +50,9 @@ inherited LSMregForm: TLSMregForm
AnchorSideTop.Control = Label1 AnchorSideTop.Control = Label1
AnchorSideTop.Side = asrBottom AnchorSideTop.Side = asrBottom
AnchorSideRight.Control = AllBtn AnchorSideRight.Control = AllBtn
AnchorSideBottom.Control = InProb AnchorSideBottom.Control = InProbEdit
Left = 0 Left = 0
Height = 203 Height = 182
Top = 17 Top = 17
Width = 173 Width = 173
Anchors = [akTop, akLeft, akRight, akBottom] Anchors = [akTop, akLeft, akRight, akBottom]
@ -69,7 +69,7 @@ inherited LSMregForm: TLSMregForm
AnchorSideLeft.Control = AllBtn AnchorSideLeft.Control = AllBtn
AnchorSideLeft.Side = asrCenter AnchorSideLeft.Side = asrCenter
AnchorSideTop.Control = VarList AnchorSideTop.Control = VarList
AnchorSideRight.Control = DepVar AnchorSideRight.Control = DepVarEdit
Left = 187 Left = 187
Height = 26 Height = 26
Top = 17 Top = 17
@ -81,7 +81,7 @@ inherited LSMregForm: TLSMregForm
TabOrder = 1 TabOrder = 1
end end
object Label2: TLabel[8] object Label2: TLabel[8]
AnchorSideLeft.Control = DepVar AnchorSideLeft.Control = DepVarEdit
AnchorSideTop.Control = DepInBtn AnchorSideTop.Control = DepInBtn
Left = 227 Left = 227
Height = 15 Height = 15
@ -91,7 +91,7 @@ inherited LSMregForm: TLSMregForm
Caption = 'Dependent Variable' Caption = 'Dependent Variable'
ParentColor = False ParentColor = False
end end
object DepVar: TEdit[9] object DepVarEdit: TEdit[9]
AnchorSideLeft.Control = IndepVars AnchorSideLeft.Control = IndepVars
AnchorSideTop.Control = Label2 AnchorSideTop.Control = Label2
AnchorSideTop.Side = asrBottom AnchorSideTop.Side = asrBottom
@ -106,7 +106,7 @@ inherited LSMregForm: TLSMregForm
BorderSpacing.Bottom = 12 BorderSpacing.Bottom = 12
ReadOnly = True ReadOnly = True
TabOrder = 3 TabOrder = 3
Text = 'DepVar' Text = 'DepVarEdit'
end end
object Label3: TLabel[10] object Label3: TLabel[10]
AnchorSideLeft.Control = IndepVars AnchorSideLeft.Control = IndepVars
@ -122,11 +122,11 @@ inherited LSMregForm: TLSMregForm
end end
object Label5: TLabel[11] object Label5: TLabel[11]
AnchorSideLeft.Control = ParamsPanel AnchorSideLeft.Control = ParamsPanel
AnchorSideTop.Control = InProb AnchorSideTop.Control = InProbEdit
AnchorSideTop.Side = asrCenter AnchorSideTop.Side = asrCenter
Left = 0 Left = 0
Height = 15 Height = 15
Top = 232 Top = 211
Width = 192 Width = 192
BorderSpacing.Right = 8 BorderSpacing.Right = 8
Caption = 'Minimum probability to enter block:' Caption = 'Minimum probability to enter block:'
@ -138,8 +138,8 @@ inherited LSMregForm: TLSMregForm
AnchorSideRight.Side = asrBottom AnchorSideRight.Side = asrBottom
AnchorSideBottom.Control = ButtonBevel AnchorSideBottom.Control = ButtonBevel
Left = 0 Left = 0
Height = 114 Height = 135
Top = 259 Top = 238
Width = 404 Width = 404
Anchors = [akLeft, akBottom] Anchors = [akLeft, akBottom]
AutoSize = True AutoSize = True
@ -151,72 +151,80 @@ inherited LSMregForm: TLSMregForm
ChildSizing.VerticalSpacing = 2 ChildSizing.VerticalSpacing = 2
ChildSizing.Layout = cclLeftToRightThenTopToBottom ChildSizing.Layout = cclLeftToRightThenTopToBottom
ChildSizing.ControlsPerLine = 2 ChildSizing.ControlsPerLine = 2
ClientHeight = 94 ClientHeight = 115
ClientWidth = 400 ClientWidth = 400
TabOrder = 9 TabOrder = 9
object CPChkBox: TCheckBox object ANOVAChk: TCheckBox
Left = 12 Left = 12
Height = 19 Height = 19
Top = 6 Top = 6
Width = 198
Caption = 'Show ANOVA'
TabOrder = 0
end
object CrossProductsChk: TCheckBox
Left = 218
Height = 19
Top = 6
Width = 170 Width = 170
Caption = 'Show Cross-Products Matrix' Caption = 'Show Cross-Products Matrix'
TabOrder = 0
end
object CovChkBox: TCheckBox
Left = 190
Height = 19
Top = 6
Width = 198
Caption = 'Show Variance-Covariance Matrix'
TabOrder = 1 TabOrder = 1
end end
object CorrsChkBox: TCheckBox object CovChk: TCheckBox
Left = 12 Left = 12
Height = 19 Height = 19
Top = 27 Top = 27
Width = 198
Caption = 'Show Variance-Covariance Matrix'
TabOrder = 2
end
object CorrsChk: TCheckBox
Left = 218
Height = 19
Top = 27
Width = 170 Width = 170
Caption = 'Show Intercorrelation Matrix' Caption = 'Show Intercorrelation Matrix'
TabOrder = 2
end
object MeansChkBox: TCheckBox
Left = 190
Height = 19
Top = 27
Width = 198
Caption = 'Show Means'
TabOrder = 3 TabOrder = 3
end end
object VarChkBox: TCheckBox object MeansChk: TCheckBox
Left = 12 Left = 12
Height = 19 Height = 19
Top = 48 Top = 48
Width = 198
Caption = 'Show Means'
TabOrder = 4
end
object VarChk: TCheckBox
Left = 218
Height = 19
Top = 48
Width = 170 Width = 170
Caption = 'Show Variances' Caption = 'Show Variances'
TabOrder = 4
end
object StdDevChkBox: TCheckBox
Left = 190
Height = 19
Top = 48
Width = 198
Caption = 'Show Standard Deviations'
TabOrder = 5 TabOrder = 5
end end
object MatSaveChkBox: TCheckBox object StdDevChk: TCheckBox
Left = 12 Left = 12
Height = 19 Height = 19
Top = 69 Top = 69
Width = 198
Caption = 'Show Standard Deviations'
TabOrder = 6
end
object MatSaveChk: TCheckBox
Left = 218
Height = 19
Top = 69
Width = 170 Width = 170
Caption = 'Save Correlation Matrix' Caption = 'Save Correlation Matrix'
TabOrder = 6 TabOrder = 7
end end
object PredictChkBox: TCheckBox object PredictChk: TCheckBox
Left = 190 Left = 12
Height = 19 Height = 19
Top = 69 Top = 90
Width = 198 Width = 198
Caption = 'Predictions,residuals,C.I.''s to Grid' Caption = 'Predictions,residuals,C.I.''s to Grid'
TabOrder = 7 TabOrder = 8
end end
end end
object IndepVars: TListBox[13] object IndepVars: TListBox[13]
@ -229,7 +237,7 @@ inherited LSMregForm: TLSMregForm
AnchorSideBottom.Control = VarList AnchorSideBottom.Control = VarList
AnchorSideBottom.Side = asrBottom AnchorSideBottom.Side = asrBottom
Left = 227 Left = 227
Height = 98 Height = 77
Top = 122 Top = 122
Width = 174 Width = 174
Anchors = [akTop, akLeft, akRight, akBottom] Anchors = [akTop, akLeft, akRight, akBottom]
@ -290,21 +298,21 @@ inherited LSMregForm: TLSMregForm
Spacing = 0 Spacing = 0
TabOrder = 5 TabOrder = 5
end end
object InProb: TEdit[17] object InProbEdit: TEdit[17]
AnchorSideLeft.Control = Label5 AnchorSideLeft.Control = Label5
AnchorSideLeft.Side = asrBottom AnchorSideLeft.Side = asrBottom
AnchorSideRight.Side = asrBottom AnchorSideRight.Side = asrBottom
AnchorSideBottom.Control = OptionsGroup AnchorSideBottom.Control = OptionsGroup
Left = 200 Left = 200
Height = 23 Height = 23
Top = 228 Top = 207
Width = 50 Width = 50
Alignment = taRightJustify Alignment = taRightJustify
Anchors = [akLeft, akBottom] Anchors = [akLeft, akBottom]
BorderSpacing.Top = 8 BorderSpacing.Top = 8
BorderSpacing.Right = 8 BorderSpacing.Right = 8
TabOrder = 8 TabOrder = 8
Text = 'InProb' Text = 'InProbEdit'
end end
object AllBtn: TBitBtn[18] object AllBtn: TBitBtn[18]
AnchorSideLeft.Control = ParamsPanel AnchorSideLeft.Control = ParamsPanel
@ -331,19 +339,22 @@ inherited LSMregForm: TLSMregForm
Height = 414 Height = 414
Top = 8 Top = 8
Width = 580 Width = 580
ActivePage = MeanVarStddevPage ActivePage = RegressionPage
Align = alClient Align = alClient
BorderSpacing.Left = 4 BorderSpacing.Left = 4
BorderSpacing.Top = 8 BorderSpacing.Top = 8
BorderSpacing.Right = 8 BorderSpacing.Right = 8
BorderSpacing.Bottom = 8 BorderSpacing.Bottom = 8
TabIndex = 4 TabIndex = 0
TabOrder = 2 TabOrder = 2
object RegressionPage: TTabSheet object RegressionPage: TTabSheet
Caption = 'Regression' Caption = 'Regression'
end end
object ANOVAPage: TTabSheet
Caption = 'ANOVA'
end
object CrossProductsPage: TTabSheet object CrossProductsPage: TTabSheet
Caption = 'Cross-Products Matrix' Caption = 'Cross-Products'
end end
object VarCovarPage: TTabSheet object VarCovarPage: TTabSheet
Caption = 'Variance-Covariance' Caption = 'Variance-Covariance'
@ -355,8 +366,4 @@ inherited LSMregForm: TLSMregForm
Caption = 'Mean, Variance, StdDev' Caption = 'Mean, Variance, StdDev'
end end
end end
object SaveDialog: TSaveDialog[3]
Left = 45
Top = 357
end
end end

View File

@ -7,7 +7,7 @@ interface
uses uses
Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs,
StdCtrls, Buttons, ExtCtrls, ComCtrls, Globals, MainUnit, MatrixLib, StdCtrls, Buttons, ExtCtrls, ComCtrls, Globals, MainUnit, MatrixLib,
DataProcs, DictionaryUnit, BasicStatsParamsFormUnit, ReportFrameUnit; DataProcs, BasicStatsParamsFormUnit, ReportFrameUnit, RegressionUnit;
type type
@ -15,33 +15,34 @@ type
TLSMregForm = class(TBasicStatsParamsForm) TLSMregForm = class(TBasicStatsParamsForm)
AllBtn: TBitBtn; AllBtn: TBitBtn;
ANOVAChk: TCheckBox;
IndepVars: TListBox; IndepVars: TListBox;
CorrsChkBox: TCheckBox; CorrsChk: TCheckBox;
CovChkBox: TCheckBox; CovChk: TCheckBox;
CPChkBox: TCheckBox; CrossProductsChk: TCheckBox;
DepInBtn: TBitBtn; DepInBtn: TBitBtn;
DepOutBtn: TBitBtn; DepOutBtn: TBitBtn;
DepVar: TEdit; DepVarEdit: TEdit;
OptionsGroup: TGroupBox; OptionsGroup: TGroupBox;
InBtn: TBitBtn; InBtn: TBitBtn;
InProb: TEdit; InProbEdit: TEdit;
Label1: TLabel; Label1: TLabel;
Label2: TLabel; Label2: TLabel;
Label3: TLabel; Label3: TLabel;
Label5: TLabel; Label5: TLabel;
MatSaveChkBox: TCheckBox; MatSaveChk: TCheckBox;
MeansChkBox: TCheckBox; MeansChk: TCheckBox;
PageControl: TPageControl; PageControl: TPageControl;
SaveDialog: TSaveDialog;
OutBtn: TBitBtn; OutBtn: TBitBtn;
PredictChkBox: TCheckBox; PredictChk: TCheckBox;
StdDevChkBox: TCheckBox; StdDevChk: TCheckBox;
RegressionPage: TTabSheet; RegressionPage: TTabSheet;
CrossProductsPage: TTabSheet; CrossProductsPage: TTabSheet;
CorrelationsPage: TTabSheet; CorrelationsPage: TTabSheet;
MeanVarStddevPage: TTabSheet; MeanVarStddevPage: TTabSheet;
ANOVAPage: TTabSheet;
VarCovarPage: TTabSheet; VarCovarPage: TTabSheet;
VarChkBox: TCheckBox; VarChk: TCheckBox;
VarList: TListBox; VarList: TListBox;
procedure AllBtnClick(Sender: TObject); procedure AllBtnClick(Sender: TObject);
procedure DepInBtnClick(Sender: TObject); procedure DepInBtnClick(Sender: TObject);
@ -51,9 +52,11 @@ type
procedure OutBtnClick(Sender: TObject); procedure OutBtnClick(Sender: TObject);
procedure VarListDblClick(Sender: TObject); procedure VarListDblClick(Sender: TObject);
procedure VarListSelectionChange(Sender: TObject; {%H-}User: boolean); procedure VarListSelectionChange(Sender: TObject; {%H-}User: boolean);
private private
{ private declarations } { private declarations }
FRegressionFrame: TReportFrame; FRegressionFrame: TReportFrame;
FAnovaFrame: TReportFrame;
FCrossProductsFrame: TReportFrame; FCrossProductsFrame: TReportFrame;
FCorrelationsFrame: TReportFrame; FCorrelationsFrame: TReportFrame;
FVarCovarFrame: TReportFrame; FVarCovarFrame: TReportFrame;
@ -61,11 +64,31 @@ type
IndepVarsCols: IntDyneVec; IndepVarsCols: IntDyneVec;
NoVars: integer; NoVars: integer;
NoBlocks: integer; NoBlocks: integer;
procedure HideTabs; procedure HideTabs;
procedure PredictionToGrid(xData: DblDyneMat; yData: DblDyneVec;
const ARegressionResults: TMultipleRegressionResults; ABadRows: IntDyneVec);
function PrepareData(out AIndepCols: IntDyneVec; out ADepCol: Integer;
out ARowLabels: StrDyneVec; out xValues: DblDyneMat;
out yValues: DblDyneVec; out ABadRows: IntDyneVec): Boolean;
procedure Process_Regression(
const ARowLabels: StrDyneVec; const xValues: DblDyneMat;
const yValues: DblDyneVec; const ABadRows: IntDyneVec);
procedure WriteMeanVarStddevReport(AReport: TStrings; AVarNames: StrDyneVec;
const AMeans, AVars, AStdDevs: DblDyneVec; Flags: Integer);
procedure WriteReportHeader(AReport: TStrings; AVarNames: StrDyneVec);
protected protected
procedure AdjustConstraints; override; procedure AdjustConstraints; override;
procedure Compute; override; procedure Compute; override;
procedure UpdateBtnStates; override; procedure UpdateBtnStates; override;
function Validate(out AMsg: String; out AControl: TWinControl): Boolean; override;
public public
constructor Create(AOwner: TComponent); override; constructor Create(AOwner: TComponent); override;
procedure Reset; override; procedure Reset; override;
@ -80,8 +103,8 @@ implementation
{$R *.lfm} {$R *.lfm}
uses uses
Math, Math, StrUtils,
Utils, MathUnit; Utils, GridProcs, MathUnit, MatrixUnit;
{ TLSMregForm } { TLSMregForm }
@ -100,6 +123,16 @@ begin
FRegressionFrame.BorderSpacing.Right := 0; FRegressionFrame.BorderSpacing.Right := 0;
InitToolbar(FRegressionFrame.ReportToolbar, tpRight); InitToolbar(FRegressionFrame.ReportToolbar, tpRight);
FAnovaFrame := TReportFrame.Create(self);
FAnovaFrame.Name := '';
FAnovaFrame.Parent := AnovaPage;
FAnovaFrame.Align := alClient;
FAnovaFrame.BorderSpacing.Left := 0;
FAnovaFrame.BorderSpacing.Top := 0;
FAnovaFrame.BorderSpacing.Bottom := 0;
FAnovaFrame.BorderSpacing.Right := 0;
InitToolbar(FAnovaFrame.ReportToolbar, tpRight);
FCrossProductsFrame := TReportFrame.Create(self); FCrossProductsFrame := TReportFrame.Create(self);
FCrossProductsFrame.Name := ''; FCrossProductsFrame.Name := '';
FCrossProductsFrame.Parent := CrossProductsPage; FCrossProductsFrame.Parent := CrossProductsPage;
@ -151,7 +184,7 @@ begin
4*CloseBtn.Width + 3*CloseBtn.BorderSpacing.Left 4*CloseBtn.Width + 3*CloseBtn.BorderSpacing.Left
); );
ParamsPanel.Constraints.MinHeight := AllBtn.Top + AllBtn.Height + ParamsPanel.Constraints.MinHeight := AllBtn.Top + AllBtn.Height +
VarList.BorderSpacing.Bottom + InProb.Height + VarList.BorderSpacing.Bottom + InProbEdit.Height +
OptionsGroup.BorderSpacing.Top + OptionsGroup.Height + OptionsGroup.BorderSpacing.Top + OptionsGroup.Height +
ButtonBevel.Height + CloseBtn.BorderSpacing.Top + CloseBtn.Height; ButtonBevel.Height + CloseBtn.BorderSpacing.Top + CloseBtn.Height;
end; end;
@ -168,234 +201,17 @@ begin
end; end;
procedure TLSMregForm.Compute; procedure TLSMRegForm.Compute;
var var
i, j, NCases: integer; indepCols: IntDyneVec = nil;
NoIndepVars, DepVarCol, NEntered: integer; RowLabels: StrDyneVec = nil;
R2, df1, df2: double; xValues: DblDyneMat = nil;
StdErrEst, F, FProbF, OldR2: double; yValues: DblDyneVec = nil;
pdf1, probin, prout: double; badRows: IntDyneVec = nil;
errorcode: boolean; depCol: Integer;
BetaWeights: DblDyneVec = nil;
BWeights: DblDyneVec = nil;
BStdErrs: DblDyneVec = nil;
Bttests: DblDyneVec = nil;
tProbs: DblDyneVec = nil;
cellstring: string;
corrs: DblDyneMat = nil;
Means: DblDyneVec = nil;
Variances: DblDyneVec = nil;
StdDevs: DblDyneVec = nil;
title: string;
IndRowLabels: StrDyneVec = nil;
IndColLabels: StrDyneVec = nil;
IndepInverse: DblDyneMat = nil;
ColEntered: IntDyneVec = nil;
filename: string;
constant: double;
errcode: boolean = false;
anerror: Integer = 0;
lReport: TStrings;
procedure AddHeaderToReport;
begin
lReport.Clear;
lReport.Add('LEAST SQUARES MULTIPLE REGRESSION by Bill Miller');
lReport.Add('');
end;
begin begin
NCases := NoCases; if PrepareData(indepCols, depCol, RowLabels, xValues, yValues, badRows) then
SetLength(corrs,NoVariables+1,NoVariables+1); Process_Regression(RowLabels, xValues, yValues, badRows);
SetLength(IndepInverse,NoVariables,NoVariables+1);
SetLength(IndepVarsCols,NoVariables+1);
SetLength(BWeights,NoVariables+1);
SetLength(BStdErrs,NoVariables+1);
SetLength(Bttests,NoVariables+1);
SetLength(tProbs,NoVariables+1);
SetLength(Means,NoVariables+1);
SetLength(Variances,NoVariables+1);
SetLength(StdDevs,NoVariables+1);
SetLength(IndepVarsCols,NoVariables+1);
SetLength(IndColLabels,NoVariables+1);
SetLength(IndRowLabels,NoVariables+1);
SetLength(BetaWeights,NoVariables+1);
SetLength(ColEntered,NoVariables+2);
probin := StrToFloat(InProb.Text); // probability to include a block
prout := 1.0;
if DepVar.Text = '' then
begin
ErrorMsg('No dependent variable selected.');
exit;
end;
if IndepVars.Items.Count = 0 then
begin
ErrorMsg('No independent variable selected.');
exit;
end;
lReport := TStringList.Create;
try
errorcode := false;
{ get dependendent variable column }
DepVarCol := 0;
NoVars := NoVars + 1;
for j := 1 to NoVariables do
if DepVar.Text = OS3MainFrm.DataGrid.Cells[j,0] then DepVarCol := j;
R2 := 0.0;
OldR2 := 0.0;
pdf1 := 0.0;
NEntered := 0;
{ get independendent variable column }
for i := 0 to IndepVars.Count-1 do
begin
//cellstring := OS3Mainfrm.DataGrid.Cells[i+1,0]; // bug
cellstring := IndepVars.Items[i]; //Bugfix by tatamata
for j := 1 to NoVariables do
begin
if cellstring = OS3MainFrm.DataGrid.Cells[j,0] then
begin
IndepVarsCols[i] := j;
ColEntered[i] := j;
NEntered := NEntered + 1;
IndRowLabels[NEntered-1] := cellstring;
IndColLabels[NEntered-1] := cellstring;
end;
end;
end;
NEntered := NEntered + 1; // dependent variable last
ColEntered[NEntered-1] := DepVarCol;
IndRowLabels[NEntered-1] := OS3MainFrm.DataGrid.Cells[DepVarCol,0];
IndColLabels[NEntered-1] := OS3MainFrm.DataGrid.Cells[DepVarCol,0];
if CPChkBox.Checked then
begin
title := 'Cross-Products Matrix';
AddHeaderToReport;
GridXProd(NEntered, ColEntered, Corrs, errcode, NCases);
MatPrint(Corrs, NEntered, NEntered, title, IndRowLabels, IndColLabels, NCases, lReport);
FCrossProductsFrame.DisplayReport(lReport);
CrossProductsPage.TabVisible := true;
end else
CrossProductsPage.TabVisible := false;
if CovChkBox.Checked then
begin
title := 'Variance-Covariance Matrix';
AddHeaderToReport;
GridCovar(NEntered,ColEntered, Corrs, Means, Variances, StdDevs, errcode, NCases);
MatPrint(Corrs, NEntered, NEntered, title, IndRowLabels, IndColLabels, NCases, lReport);
FVarCovarFrame.DisplayReport(lReport);
VarCovarPage.TabVisible := true;
// lReport.Add(DIVIDER_SMALL);
end;
Correlations(NEntered,ColEntered,Corrs,Means,Variances, StdDevs,errcode,NCases);
if CorrsChkBox.Checked then
begin
title := 'Product-Moment Correlations Matrix';
AddHeaderToReport;
MatPrint(Corrs, NEntered, NEntered, title, IndRowLabels, IndColLabels, NCases, lReport);
FCorrelationsFrame.DisplayReport(lReport);
CorrelationsPage.TabVisible := true;
end else
CorrelationsPage.TabVisible := false;
if MeansChkBox.Checked or VarChkBox.Checked or StdDevChkBox.Checked then
begin
AddHeaderToReport;
if MeansChkBox.Checked then
begin
title := 'MEANS';
DynVectorPrint(Means, NEntered, title, IndColLabels, NCases, lReport);
lReport.Add(DIVIDER_SMALL);
lReport.Add('');
end;
if VarChkBox.Checked then
begin
title := 'VARIANCES';
DynVectorPrint(Variances, NEntered, title, IndColLabels, NCases, lReport);
lReport.Add(DIVIDER_SMALL);
lReport.Add('');
end;
if StdDevChkBox.Checked then
begin
title := 'STANDARD DEVIATIONS';
DynVectorPrint(StdDevs, NEntered, title, IndColLabels, NCases, lReport);
lReport.Add(DIVIDER_SMALL);
lReport.Add('');
end;
FMeanVarStddevFrame.DisplayReport(lReport);
MeanVarStddevPage.TabVisible := true;
end else
MeanVarStddevPage.TabVisible := false;
if errorcode then
begin
ErrorMsg('A selected variable has no variability. Run aborted.');
exit;
end;
NoIndepVars := NEntered - 1;
AddHeaderToReport;
MReg(NoIndepVars, ColEntered, DepVarCol, IndRowLabels, Means, Variances,
StdDevs, BWeights, BetaWeights, BStdErrs, Bttests, tProbs, R2,
StdErrEst, NCases, errorcode, true, lReport);
df1 := NoIndepVars - pdf1;
df2 := NCases - NoIndepVars - 1;
F := ((R2 - OldR2) / (1.0 - R2)) * df2 / df1;
FProbF := ProbF(F,df1,df2);
lReport.Add('');
if FProbF < probIn then
lReport.Add('Entry requirements met')
else
lReport.Add('Entry requirements not met');
lReport.Add('');
lReport.Add(DIVIDER);
lReport.Add('');
{ add [predicted scores, residual scores, etc. to grid if options elected }
if PredictChkBox.Checked then
begin
prout := 1.0;
Correlations(NEntered, ColEntered, Corrs, Means, Variances, StdDevs, errcode, NCases);
MReg2(NCases, NEntered, NoIndepVars, ColEntered, corrs, IndepInverse,
IndRowLabels, R2, BetaWeights, Means, Variances, anerror,
StdErrEst, constant, prout, true, false, false, lReport);
Predict(ColEntered, NEntered, IndepInverse, Means, StdDevs,
BetaWeights, StdErrEst, IndepVarsCols, NoIndepVars);
end;
if MatSaveChkBox.Checked then
begin
SaveDialog.Filter := 'LazStats matrix files (*.mat)|*.mat;*.MAT|All files (*.*)|*.*';
SaveDialog.FilterIndex := 1;
if SaveDialog.Execute then
begin
filename := SaveDialog.FileName;
MatSave(Corrs, NoVars, NoVars, Means, StdDevs, NCases, IndRowLabels, IndColLabels, filename);
end;
end;
FRegressionFrame.DisplayReport(lReport);
finally
lReport.Free;
end;
end; end;
@ -404,9 +220,9 @@ var
index: integer; index: integer;
begin begin
index := VarList.ItemIndex; index := VarList.ItemIndex;
if (index > -1) and (DepVar.Text = '') then if (index > -1) and (DepVarEdit.Text = '') then
begin begin
DepVar.Text := VarList.Items[index]; DepVarEdit.Text := VarList.Items[index];
VarList.Items.Delete(index); VarList.Items.Delete(index);
end; end;
UpdateBtnStates; UpdateBtnStates;
@ -415,10 +231,10 @@ end;
procedure TLSMregForm.DepOutBtnClick(Sender: TObject); procedure TLSMregForm.DepOutBtnClick(Sender: TObject);
begin begin
if DepVar.Text <> '' then if DepVarEdit.Text <> '' then
begin begin
VarList.Items.Add(DepVar.Text); VarList.Items.Add(DepVarEdit.Text);
DepVar.Text := ''; DepVarEdit.Text := '';
end; end;
UpdateBtnStates; UpdateBtnStates;
end; end;
@ -483,6 +299,235 @@ begin
UpdateBtnStates; UpdateBtnStates;
end; end;
procedure TLSMregForm.PredictionToGrid(xData: DblDyneMat; yData: DblDyneVec;
const ARegressionResults: TMultipleRegressionResults; ABadRows: IntDyneVec);
var
zPred, zResid, rawPred, rawResid, stdErrPred, hi95, lo95: DblDyneVec;
begin
PredictMR(xData, yData, ARegressionResults,
zPred, zResid, RawPred, RawResid, StdErrPred, Hi95, Lo95);
AddVariable('Pred.z', zPred, '%8.4f', ABadRows);
AddVariable('z Resid', zResid, '%8.4f', ABadRows);
AddVariable('Raw Pred', rawPred, '%8.3f', ABadRows);
AddVariable('Raw Resid', rawResid, '%8.3f', ABadRows);
AddVariable('StdErr Pred', stdErrPred, '%8.3f', ABadRows);
AddVariable('Low 95%', lo95, '%8.3f', ABadRows);
AddVariable('Top 95%', hi95, '%8.3f', ABadRows);
end;
{ 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
- 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 TLSMregForm.PrepareData(out AIndepCols: IntDyneVec; out ADepCol: Integer;
out ARowLabels: StrDyneVec; out xValues: DblDyneMat; out yValues: DblDyneVec;
out ABadRows: IntDyneVec): Boolean;
var
i, n: Integer;
msg: String;
C: TWinControl;
numIndepCols: Integer;
cols: IntDyneVec = nil;
begin
Result := false;
AIndepCols := nil;
ARowLabels := nil;
xValues := nil;
yvalues := nil;
ABadRows := nil;
if not Validate(msg, C) then
begin
C.SetFocus;
ErrorMsg(msg);
exit;
end;
numIndepCols := IndepVars.Items.Count;
ADepCol := GetVariableIndex(OS3MainFrm.DataGrid, DepVarEdit.Text);
SetLength(AIndepCols, numIndepCols);
SetLength(ARowLabels, numIndepCols + 1); // +1 to add independent column label
for i := 0 to numIndepCols-1 do
begin
AIndepCols[i] := GetVariableIndex(OS3MainFrm.DataGrid, IndepVars.Items[i]);
if AIndepCols[i] = -1 then
begin
ErrorMsg('Dependent variable %s not found.', [IndepVars.Items[i]]);
exit;
end;
ARowLabels[i] := IndepVars.Items[i];
end;
ARowLabels[numIndepCols] := DepVarEdit.Text;
// 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;
for i := 0 to numIndepCols-1 do
if not IsNumericCol(AIndepCols[i]) then
begin
ErrorMsg('Incorrect data type of independent variable "%s"', [ARowLabels[i]]);
exit;
end;
// Prepare list of all column indices to be loaded: x, y
// ADepCol will follow immediately after the x columns.
SetLength(cols, NumIndepCols + 1);
cols[numIndepCols] := ADepCol;
for i := 0 to numIndepCols-1 do cols[i] := AIndepCols[i];
// Determine list of indices of rows containing invalid entries.
SetLength(ABadRows, OS3MainFrm.DataGrid.RowCount);
n := 0;
for i := 1 to OS3MainFrm.DataGrid.RowCount-1 do
if not GoodRecord(OS3MainFrm.DataGrid, i, cols) then
begin
ABadRows[n] := i;
inc(n);
end;
SetLength(ABadRows, n);
// Extract data values; take care to skip invalid values in both x and y
xValues := CollectMatValues(OS3MainFrm.DataGrid, cols);
// The y column has index numIndepCols, i.e. follows after the x columns.
yValues := MatColVector(xValues, numIndepCols);
MatColDelete(xValues, numIndepCols);
Result := true;
end;
{ Runs the least squares regression on the data in xValues and yValues }
procedure TLSMregForm.Process_Regression(const ARowLabels: StrDyneVec;
const xValues: DblDyneMat; const yValues: DblDyneVec;
const ABadRows: IntDyneVec);
var
lReport: TStrings;
regressionRes: TMultipleRegressionResults;
n: Integer;
confLevel: Double;
err: TRegressionError;
flags: Integer;
means: DblDyneVec = nil;
vars: DblDyneVec = nil;
stdDevs: DblDyneVec = nil;
begin
confLevel := 1.0 - StrToFloat(InProbEdit.Text);
err := MultipleRegression(xValues, yValues, confLevel, regressionRes);
case err of
regOK : ;
regTooFewValues : ErrorMsg('At least two values required for regression.');
end;
if err <> regOK then
exit;
// Calculate means, variances, stddevs of all required variables and put them
// in vectors means, vars, stddevs, y data at end.
MatColMeanVarStdDev(xValues, means, vars, stdDevs);
n := Length(means);
SetLength(means, n+1);
SetLength(vars, n+1);
SetLength(stddevs, n+1);
VecMeanVarStdDev(yValues, means[n], vars[n], stddevs[n]);
lReport := TStringList.Create;
try
WriteReportHeader(lReport, ARowLabels);
regressionRes.WriteCoeffsReport(lReport, ARowLabels);
FRegressionFrame.DisplayReport(lReport);
if AnovaChk.Checked then
begin
lReport.Clear;
WriteReportHeader(lReport, ARowLabels);
regressionRes.WriteAnovaReport(lReport);
FAnovaFrame.DisplayReport(lReport);
end;
AnovaPage.TabVisible := AnovaChk.Checked;
if CrossProductsChk.Checked then
begin
lReport.Clear;
WriteReportHeader(lReport, ARowLabels);
regressionRes.WriteCrossProductsReport(lReport, ARowLabels);
FCrossProductsFrame.DisplayReport(lReport);
end;
CrossProductsPage.TabVisible := CrossProductsChk.Checked;
if CovChk.Checked then
begin
lReport.Clear;
WriteReportHeader(lReport, ARowLabels);
regressionRes.WriteVarCovarReport(lReport, ARowLabels);
FVarCovarFrame.DisplayReport(lReport);
end;
VarCovarPage.TabVisible := CovChk.Checked;
if CorrsChk.Checked then
begin
lReport.Clear;
WriteReportHeader(lReport, ARowLabels);
regressionRes.WriteCorrelationReport(lReport, ARowLabels);
FCorrelationsFrame.DisplayReport(lReport);
end;
CorrelationsPage.TabVisible := CorrsChk.Checked;
if MeansChk.Checked or VarChk.Checked or StdDevChk.Checked then
begin
lReport.Clear;
WriteReportHeader(lReport, ARowLabels);
flags := 0;
if MeansChk.Checked then inc(flags, 1);
if VarChk.Checked then inc(flags, 2);
if StdDevChk.Checked then inc(flags, 4);
WriteMeanVarStddevReport(lReport, ARowLabels, means, vars, stdDevs, flags);
FMeanVarStdDevFrame.displayReport(lReport);
end;
MeanVarStdDevPage.TabVisible := MeansChk.Checked or VarChk.Checked or StdDevChk.Checked;
if PredictChk.Checked then
PredictionToGrid(xValues, yValues, regressionRes, ABadRows);
if MatSaveChk.Checked then
begin
Application.ProcessMessages;
with TSaveDialog.Create(nil) do
try
Filter := 'LazStats matrix files (*.mat)|*.mat;*.MAT|All files (*.*)|*.*';
FilterIndex := 1;
if Execute then
begin
n := Length(means);
MatSave(RegressionRes.Correlations, n-1, n-1, means, stdDevs, regressionRes.NumCases, ARowLabels, ARowLabels, Filename);
end;
finally
Free;
end;
MatSaveChk.Checked := false;
end;
finally
lReport.Free;
end;
end;
procedure TLSMregForm.Reset; procedure TLSMregForm.Reset;
var var
i: integer; i: integer;
@ -496,18 +541,19 @@ begin
for i := 1 to NoVariables do for i := 1 to NoVariables do
VarList.Items.Add(OS3MainFrm.DataGrid.Cells[i,0]); VarList.Items.Add(OS3MainFrm.DataGrid.Cells[i,0]);
CPChkBox.Checked := false; AnovaChk.Checked := true;
CovChkBox.Checked := false; CrossProductsChk.Checked := false;
CorrsChkBox.Checked := true; CovChk.Checked := true;
MeansChkBox.Checked := true; CorrsChk.Checked := true;
VarChkBox.Checked := false; MeansChk.Checked := true;
StdDevChkBox.Checked := true; VarChk.Checked := false;
MatSaveChkBox.Checked := false; StdDevChk.Checked := true;
PredictChkBox.Checked := false; MatSaveChk.Checked := false;
PredictChk.Checked := false;
NoVars := 0; NoVars := 0;
DepVar.Text := ''; DepVarEdit.Text := '';
InProb.Text := FormatFloat('0.00', DEFAULT_ALPHA_LEVEL); InProbEdit.Text := FormatFloat('0.00', DEFAULT_ALPHA_LEVEL);
SetLength(IndepVarsCols, NoVariables+1); SetLength(IndepVarsCols, NoVariables+1);
HideTabs; HideTabs;
@ -523,6 +569,8 @@ begin
if Assigned(FRegressionFrame) then if Assigned(FRegressionFrame) then
FRegressionFrame.UpdateBtnStates; FRegressionFrame.UpdateBtnStates;
if Assigned(FAnovaFrame) then
FAnovaFrame.UpdateBtnStates;
if Assigned(FCrossProductsFrame) then if Assigned(FCrossProductsFrame) then
FCrossProductsFrame.UpdateBtnStates; FCrossProductsFrame.UpdateBtnStates;
if Assigned(FCorrelationsFrame) then if Assigned(FCorrelationsFrame) then
@ -536,11 +584,48 @@ begin
DepInBtn.Enabled := lSelected; DepInBtn.Enabled := lSelected;
InBtn.Enabled := lSelected; InBtn.Enabled := lSelected;
OutBtn.Enabled := AnySelected(IndepVars); OutBtn.Enabled := AnySelected(IndepVars);
DepOutBtn.Enabled := DepVar.Text <> ''; DepOutBtn.Enabled := DepVarEdit.Text <> '';
AllBtn.Enabled := VarList.Items.Count > 0; AllBtn.Enabled := VarList.Items.Count > 0;
end; end;
function TLSMregForm.Validate(out AMsg: String; out AControl: TWinControl): Boolean;
var
x: double;
begin
Result := false;
if DepVarEdit.Text = '' then
begin
AControl := DepVarEdit;
AMsg := 'No dependent variable selected.';
exit;
end;
if IndepVars.Items.Count = 0 then
begin
AControl := IndepVars;
AMsg := 'No independent variables selected.';
exit;
end;
if InProbEdit.Text = '' then
begin
AControl := InProbEdit;
AMsg := 'This field cannot be empty.';
exit;
end;
if not TryStrToFloat(InProbEdit.Text, x) then
begin
AControl := InProbEdit;
AMsg := 'Non-numeric value.';
exit;
end;
Result := true;
end;
procedure TLSMregForm.VarListDblClick(Sender: TObject); procedure TLSMregForm.VarListDblClick(Sender: TObject);
var var
index: Integer; index: Integer;
@ -548,8 +633,8 @@ begin
index := VarList.ItemIndex; index := VarList.ItemIndex;
if index > -1 then if index > -1 then
begin begin
if DepVar.Text = '' then if DepVarEdit.Text = '' then
DepVar.Text := VarList.Items[index] DepVarEdit.Text := VarList.Items[index]
else else
IndepVars.Items.Add(VarList.Items[index]); IndepVars.Items.Add(VarList.Items[index]);
VarList.Items.Delete(index); VarList.Items.Delete(index);
@ -564,5 +649,98 @@ begin
end; end;
{ Flags = 1 ... mean; Flags = 2 ... variacne; Flags = 4 = stdDev }
procedure TLSMRegForm.WriteMeanVarStddevReport(AReport: TStrings;
AVarNames: StrDyneVec; const AMeans, AVars, AStdDevs: DblDyneVec;
Flags: Integer);
const
W = 15;
SPACE = ' ';
MASK = SPACE + '%*.3f';
var
s, sL, sLL: String;
i, n: Integer;
begin
s := '';
if Flags and 1 <> 0 then
s := s + 'MEANS, ';
if Flags and 2 <> 0 then
s := s + 'VARIANCES, ';
if Flags and 4 <> 0 then
s := s + 'STANDARD DEVIATIONS, ';
SetLength(s, Length(s)-2); // remove training ', '
//Caption
AReport.Add(s);
n := 1;
s := CenterString('Variable', W);
sL := DupeString('-', W);
if Flags and 1 <> 0 then
begin
s := s + SPACE + CenterString('Mean', W);
sL := sL + SPACE + Dupestring('-', W);
inc(n);
end;
if Flags and 2 <> 0 then
begin
s := s + SPACE + CenterString('Variance', W);
sL := sL + SPACE + Dupestring('-', W);
inc(n);
end;
if Flags and 4 <> 0 then
begin
s := s + SPACE + CenterString('Std.Deviation', W);
sL := sL + SPACE + Dupestring('-', W);
inc(n);
end;
// Divider below caption
sLL := DupeString('-', n*W + (n-1) * Length(SPACE));
AReport.Add(sLL);
// Table headers
AReport.Add(s);
// Table header separating line
AReport.Add(sL);
// Table cells
n := Length(AMeans);
for i := 0 to n-1 do
begin
s := Format('%*s', [W, AVarNames[i]]);
if Flags and 1 <> 0 then
s := s + Format(MASK, [W, AMeans[i]]);
if Flags and 2 <> 0 then
s := s + Format(MASK, [W, AVars[i]]);
if Flags and 4 <> 0 then
s := s + Format(MASK, [W, AStdDevs[i]]);
AReport.Add(s);
if i = n-2 then
AReport.Add(sL);
end;
// Final dividing line below table
AReport.Add(sLL);
end;
procedure TLSMRegForm.WriteReportHeader(AReport: TStrings; AVarNames: StrDyneVec);
var
i, n: Integer;
begin
n := Length(AVarNames);
AReport.Clear;
AReport.Add('LEAST SQUARES REGRESSION RESULTS');
AReport.Add('');
AReport.Add('Dependent variable: ');
AReport.Add(' ' + AVarNames[n-1]);
AReport.Add('Independent variables:');
for i := 0 to n-2 do
AReport.Add(' ' + AVarNames[i]);
AReport.Add('');
end;
end. end.

View File

@ -728,9 +728,9 @@ begin
end; end;
SetLength(ABadRows, n); SetLength(ABadRows, n);
// Extract data values; take care to omit invalid values in both x and y // Extract data values; take care to skip invalid values in both x and y
xValues := CollectMatValues(OS3MainFrm.DataGrid, cols); xValues := CollectMatValues(OS3MainFrm.DataGrid, cols);
// The y column has index numIndepCols, i.e. follows the x columns. // The y column has index numIndepCols, i.e. follows after the x columns.
yValues := MatColVector(xValues, numIndepCols); yValues := MatColVector(xValues, numIndepCols);
MatColDelete(xValues, numIndepCols); MatColDelete(xValues, numIndepCols);
if AWeightCol > -1 then if AWeightCol > -1 then

View File

@ -845,13 +845,13 @@ begin
WriteLn(mat_file, NoCols); WriteLn(mat_file, NoCols);
WriteLn(mat_file, NCases); WriteLn(mat_file, NCases);
for i := 1 to NoRows do WriteLn(mat_file, RowLabels[i-1]); for i := 0 to NoRows-1 do WriteLn(mat_file, RowLabels[i]);
for i := 1 to NoCols do WriteLn(mat_file, ColLabels[i-1]); for i := 0 to NoCols-1 do WriteLn(mat_file, ColLabels[i]);
for i := 1 to NoCols do WriteLn(mat_file, Means[i-1]); for i := 0 to NoCols-1 do WriteLn(mat_file, Means[i]);
for i := 1 to NoCols do WriteLn(mat_file, StdDevs[i-1]); for i := 0 to NoCols-1 do WriteLn(mat_file, StdDevs[i]);
for i := 1 to NoRows do for i := 0 to NoRows-1 do
for j := 1 to NoCols do for j := 0 to NoCols-1 do
WriteLn(mat_file, a[i-1, j-1]); WriteLn(mat_file, a[i, j]);
CloseFile(mat_file); CloseFile(mat_file);
end; { matrix save routine } end; { matrix save routine }

View File

@ -6,7 +6,7 @@ interface
uses uses
Classes, SysUtils, Dialogs, Classes, SysUtils, Dialogs,
Globals, DictionaryUnit, FunctionsLib, DataProcs, MainUnit; Globals, DictionaryUnit, FunctionsLib, GridProcs, DataProcs, MainUnit;
//type //type
// TRegItem = (riMeanVarStdDev, riXTX); // TRegItem = (riMeanVarStdDev, riXTX);
@ -142,6 +142,9 @@ procedure DynIntMatPrint(Mat: IntDyneMat; Rows, Cols: integer; YTitle: string;
procedure SymMatRoots(A : DblDyneMat; M : integer; VAR E : DblDyneVec; VAR V : DblDyneMat); procedure SymMatRoots(A : DblDyneMat; M : integer; VAR E : DblDyneVec; VAR V : DblDyneMat);
procedure matinv(a, vtimesw, v, w: DblDyneMat; n: integer); procedure matinv(a, vtimesw, v, w: DblDyneMat; n: integer);
procedure AddVariable(AVarName: String; AData: DblDyneVec;
ANumFormat: String; const ABadRows: IntDyneVec);
implementation implementation
@ -1113,10 +1116,12 @@ begin
DictionaryFrm.NewVar(col); DictionaryFrm.NewVar(col);
DictionaryFrm.DictGrid.Cells[1,col] := 'Pred.z'; DictionaryFrm.DictGrid.Cells[1,col] := 'Pred.z';
OS3MainFrm.DataGrid.Cells[col,0] := 'Pred.z'; OS3MainFrm.DataGrid.Cells[col,0] := 'Pred.z';
col := NoVariables + 1; col := NoVariables + 1;
DictionaryFrm.NewVar(col); DictionaryFrm.NewVar(col);
DictionaryFrm.DictGrid.Cells[1,col] := 'z Resid.'; DictionaryFrm.DictGrid.Cells[1,col] := 'z Resid.';
OS3MainFrm.DataGrid.Cells[col,0] := 'z Resid.'; OS3MainFrm.DataGrid.Cells[col,0] := 'z Resid.';
for i := 1 to NoCases do for i := 1 to NoCases do
begin begin
zpredicted := 0.0; zpredicted := 0.0;
@ -1134,10 +1139,12 @@ begin
z2 := (z2 - Means[NoVars-1]) / StdDevs[NoVars-1]; z2 := (z2 - Means[NoVars-1]) / StdDevs[NoVars-1];
OS3MainFrm.DataGrid.Cells[col,i] := format('%8.4f',[(z2 - zpredicted)]); OS3MainFrm.DataGrid.Cells[col,i] := format('%8.4f',[(z2 - zpredicted)]);
end; end;
col := NoVariables + 1; col := NoVariables + 1;
DictionaryFrm.NewVar(col); DictionaryFrm.NewVar(col);
DictionaryFrm.DictGrid.Cells[1,col] := 'Pred.Raw'; DictionaryFrm.DictGrid.Cells[1,col] := 'Pred.Raw';
OS3MainFrm.DataGrid.Cells[col,0] := 'Pred.Raw'; OS3MainFrm.DataGrid.Cells[col,0] := 'Pred.Raw';
{ calculate raw predicted scores and store in grid at col } { calculate raw predicted scores and store in grid at col }
for i := 1 to NoCases do for i := 1 to NoCases do
begin begin
@ -1145,11 +1152,13 @@ begin
StdDevs[NoVars-1] + Means[NoVars-1]; StdDevs[NoVars-1] + Means[NoVars-1];
OS3MainFrm.DataGrid.Cells[col,i] := format('%8.3f',[predicted]); OS3MainFrm.DataGrid.Cells[col,i] := format('%8.3f',[predicted]);
end; end;
{ Calculate residuals of predicted raw scores } { Calculate residuals of predicted raw scores }
col := NoVariables +1; col := NoVariables +1;
DictionaryFrm.NewVar(col); DictionaryFrm.NewVar(col);
DictionaryFrm.DictGrid.Cells[1,col] := 'Raw Resid.'; DictionaryFrm.DictGrid.Cells[1,col] := 'Raw Resid.';
OS3MainFrm.DataGrid.Cells[col,0] := 'Raw Resid.'; OS3MainFrm.DataGrid.Cells[col,0] := 'Raw Resid.';
for i := 1 to NoCases do for i := 1 to NoCases do
begin begin
Index := ColNoSelected[NoVars-1]; Index := ColNoSelected[NoVars-1];
@ -1157,19 +1166,23 @@ begin
StrToFloat(Trim(OS3MainFrm.DataGrid.Cells[Index,i])); StrToFloat(Trim(OS3MainFrm.DataGrid.Cells[Index,i]));
OS3MainFrm.DataGrid.Cells[col,i] := Format('%8.3f',[resid]); OS3MainFrm.DataGrid.Cells[col,i] := Format('%8.3f',[resid]);
end; end;
{ Calculate Confidence Interval for raw predicted score } { Calculate Confidence Interval for raw predicted score }
col := NoVariables + 1; col := NoVariables + 1;
DictionaryFrm.NewVar(col); DictionaryFrm.NewVar(col);
DictionaryFrm.DictGrid.Cells[1,col] := 'StdErrPred'; DictionaryFrm.DictGrid.Cells[1,col] := 'StdErrPred';
OS3MainFrm.DataGrid.Cells[col,0] := 'StdErrPred'; OS3MainFrm.DataGrid.Cells[col,0] := 'StdErrPred';
col := NoVariables + 1; col := NoVariables + 1;
DictionaryFrm.NewVar(col); DictionaryFrm.NewVar(col);
DictionaryFrm.DictGrid.Cells[1,col] := 'Low 95%'; DictionaryFrm.DictGrid.Cells[1,col] := 'Low 95%';
OS3MainFrm.DataGrid.Cells[col,0] := 'Low 95%'; OS3MainFrm.DataGrid.Cells[col,0] := 'Low 95%';
col := NoVariables + 1; col := NoVariables + 1;
DictionaryFrm.NewVar(col); DictionaryFrm.NewVar(col);
DictionaryFrm.DictGrid.Cells[1,col] := 'Top 95%'; DictionaryFrm.DictGrid.Cells[1,col] := 'Top 95%';
OS3MainFrm.DataGrid.Cells[col,0] := 'Top 95%'; OS3MainFrm.DataGrid.Cells[col,0] := 'Top 95%';
for i := 1 to NoCases do for i := 1 to NoCases do
begin begin
{ get term1 of the std. err. prediction } { get term1 of the std. err. prediction }
@ -2348,5 +2361,50 @@ begin
rv1 := nil; rv1 := nil;
end; end;
{ Adds a new variable named AColTitle after the last grid column
and writes the specified data to it in the specified number format.
Rows mentioned in ABadRows must be omitted because they are not contained in
AData. }
procedure AddVariable(AVarName: String; AData: DblDyneVec;
ANumFormat: String; const ABadRows: IntDyneVec);
function IsBadRow(ARow: Integer): Boolean;
var
j: Integer;
begin
for j := 0 to High(ABadRows) do
if ARow = ABadRows[j] then
begin
Result := true;
exit;
end;
Result := false;
end;
var
i, j, colIndex, row: Integer;
begin
colIndex := GetVariableIndex(OS3MainFrm.DataGrid, AVarname);
if colIndex = -1 then
begin
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;
row := 1;
for i := 0 to High(AData) do
begin
while IsBadRow(row) do inc(row);
if row >= OS3MainFrm.DataGrid.RowCount then
raise Exception.Create('Bad row error.');
OS3MainFrm.DataGrid.Cells[colIndex, row] := Format(ANumFormat, [AData[i]]);
inc(row);
end;
end;
end. end.

View File

@ -76,6 +76,8 @@ function MatRowVector(A: TDblMatrix; ARowIndex: Integer): TDblVector;
procedure MatSize(A: TDblMatrix; out n, m: Integer); procedure MatSize(A: TDblMatrix; out n, m: Integer);
function MatTransposed(A: TDblMatrix): TDblMatrix; function MatTransposed(A: TDblMatrix): TDblMatrix;
function SubMatrix(A: TDblMatrix; i1,j1, i2,j2: Integer): TDblMatrix;
// Sorting // Sorting
procedure Exchange(var a, b: Double); overload; procedure Exchange(var a, b: Double); overload;
procedure Exchange(var a, b: Integer); overload; procedure Exchange(var a, b: Integer); overload;
@ -685,6 +687,25 @@ begin
end; end;
function SubMatrix(A: TDblMatrix; i1,j1, i2,j2: Integer): TDblMatrix;
var
i, j, n, m: Integer;
begin
MatSize(A, n,m);
i1 := EnsureRange(i1, 0, n);
i2 := EnsureRange(i2, 0, n);
j1 := EnsureRange(j1, 0, m);
j2 := EnsureRange(j2, 0, m);
if i1 > i2 then Exchange(i1, i2);
if j1 > j2 then Exchange(j1, j2);
SetLength(Result, i2-i1+1, j2-j1+1);
for i := i1 to i2 do
for j := j1 to j2 do
Result[i-i1, j-j1] := A[i, j];
end;
{=============================================================================== {===============================================================================
TLUSolver TLUSolver
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------

View File

@ -43,8 +43,10 @@ type
CoeffStdErrors: TDblVector; // Standard errors of the coefficients CoeffStdErrors: TDblVector; // Standard errors of the coefficients
Beta: TDblVector; // Standardized coefficients Beta: TDblVector; // Standardized coefficients
XT_X: TDblMatrix; // Cross-products matrix
VarCovar: TDblMatrix; // Variance-covariance matrix VarCovar: TDblMatrix; // Variance-covariance matrix
Correlations: TDblMatrix; // Correlations matrix Correlations: TDblMatrix; // Correlations matrix
InvIndepCorrs: TDblMatrix; // Inverse of the INDEPENDENT correlation matrix
SStotal, SSreg, SSresid: Double; // Sum of squares SStotal, SSreg, SSresid: Double; // Sum of squares
NumCases, NumDepVars: Integer; // number of cases, number of dependent variables NumCases, NumDepVars: Integer; // number of cases, number of dependent variables
@ -59,24 +61,29 @@ type
Means: TDblVector; Means: TDblVector;
Variances: TDblVector; Variances: TDblVector;
StdDevs: TDblVector; StdDevs: TDblVector;
(*
XMeans: TDblVector; // Means of the x columns XMeans: TDblVector; // Means of the x columns
XVariances: TDblVector; // Variances of the x columns XVariances: TDblVector; // Variances of the x columns
XStdDevs: TDblVector; // Std Deviations of the x columns XStdDevs: TDblVector; // Std Deviations of the x columns
*)
MeanY: Double; // Mean of y column YMean: Double; // Mean of y column
VarianceY: Double; // Variance of y column YVariance: Double; // Variance of y column
StdDevY: Double; // Std Deviation of y column YStdDev: Double; // Std Deviation of y column
procedure WriteANOVAReport(AReport: TStrings); procedure WriteANOVAReport(AReport: TStrings);
procedure WriteCoeffsReport(AReport: TStrings; AVarNames: TStringArray); procedure WriteCoeffsReport(AReport: TStrings; AVarNames: TStringArray);
procedure WriteCorrelationReport(AReport: TStrings; AVarNames: TStringArray); procedure WriteCorrelationReport(AReport: TStrings; AVarNames: TStringArray);
procedure WriteCrossProductsReport(AReport: TStrings; AVarNames: TStringArray);
procedure WriteVarCovarReport(AReport: TStrings; AVarNames: TStringArray); procedure WriteVarCovarReport(AReport: TStrings; AVarNames: TStringArray);
end; end;
function MultipleRegression(const xData: TDblMatrix; const yData: TDblVector; function MultipleRegression(const xData: TDblMatrix; const yData: TDblVector;
AConfLevel: Double; out AResults: TMultipleRegressionResults): TRegressionError; AConfLevel: Double; out AResults: TMultipleRegressionResults): TRegressionError;
procedure PredictMR(const xData: TDblMatrix; const yData: TDblVector;
const ARegressionResults: TMultipleRegressionResults;
out zPred, zResid, RawPred, RawResid, StdErrPred, Hi95, Lo95: TDblVector);
implementation implementation
@ -171,6 +178,7 @@ begin
// Product of transposed augmented with augmented matrix // Product of transposed augmented with augmented matrix
XT_X := XT * X; XT_X := XT * X;
AResults.XT_X := Matcopy(XT_X);
// Product of inverse of XT_X with XT_Y yields the coefficients. Intercept is last. // Product of inverse of XT_X with XT_Y yields the coefficients. Intercept is last.
inv_XT_X := MatInverse(XT_X); inv_XT_X := MatInverse(XT_X);
@ -187,23 +195,19 @@ begin
AResults.Means[i] := XT_X[i, mx] / nx; AResults.Means[i] := XT_X[i, mx] / nx;
AResults.Variances[i] := (XT_X[i, i] - sqr(AResults.Means[i]) * nx) / (nx - 1); AResults.Variances[i] := (XT_X[i, i] - sqr(AResults.Means[i]) * nx) / (nx - 1);
AResults.StdDevs[i] := sqrt(AResults.Variances[i]); AResults.StdDevs[i] := sqrt(AResults.Variances[i]);
{
if AResults.StdDevs[i] = 0.0 then
begin
Result := regStdDevZero;
exit;
end;
}
end; end;
// Variance-covariance matrix // Variance-covariance matrix
SetLength(AResults.VarCovar, mx, mx); with AResults do
SetLength(AResults.Correlations, mx, mx); begin
SetLength(VarCovar, mx, mx);
SetLength(Correlations, mx, mx);
for i := 0 to mx-1 do for i := 0 to mx-1 do
for j := 0 to mx-1 do for j := 0 to mx-1 do
begin begin
AResults.VarCovar[i, j] := (XT_X[i, j] - XT_X[i, mx] * XT_X[j, mx] / nx) / (nx - 1); VarCovar[i, j] := (XT_X[i, j] - XT_X[i, mx] * XT_X[j, mx] / nx) / (nx - 1);
AResults.Correlations[i, j] := AResults.VarCovar[i, j] / (AResults.StdDevs[i] * AResults.StdDevs[j]); Correlations[i, j] := VarCovar[i, j] / (StdDevs[i] * StdDevs[j]);
end;
end; end;
with AResults do with AResults do
@ -213,24 +217,17 @@ begin
DFresid := NumCases - NumDepVars - 1; DFresid := NumCases - NumDepVars - 1;
// Calculate column means of xData // Calculate column means of xData
// MatColMeanVarStdDev(X, XMeans, XVariances, XStdDevs); MatColMeanVarStdDev(xData, xMeans, xVariances, xStdDevs);
// Basic stats of y data column // Basic stats of y data column
VecSumSS(yData, SY, SSY); VecSumSS(yData, SY, SSY);
MeanY := SY / NumCases; yMean := SY / NumCases;
SStotal := SSY - sqr(MeanY) * NumCases; // needed for ANOVA SStotal := SSY - sqr(yMean) * NumCases; // needed for ANOVA
VarianceY := SStotal / (NumCases - 1); yVariance := SStotal / (NumCases - 1);
StdDevY := sqrt(VarianceY); yStdDev := sqrt(yVariance);
{
if StdDevY = 0 then
begin
Result := regStdDevZero;
exit;
end;
}
// Standardized coefficients // Standardized coefficients
Beta := VecMultiply(Coeffs, StdDevs) * (1.0/StdDevY); Beta := VecMultiply(Coeffs, StdDevs) * (1.0/yStdDev);
// Get standard errors, squared multiple correlation, tests of significance // Get standard errors, squared multiple correlation, tests of significance
SetLength(CoeffStdErrors, mx+1); SetLength(CoeffStdErrors, mx+1);
@ -251,6 +248,8 @@ begin
t[i] := Coeffs[i] / CoeffStdErrors[i]; t[i] := Coeffs[i] / CoeffStdErrors[i];
p[i] := ProbT(t[i], DFresid); p[i] := ProbT(t[i], DFresid);
end; end;
InvIndepCorrs := MatInverse(SubMatrix(Correlations, 0, 0, mx-1, mx-1));
end; end;
Result := regOK; Result := regOK;
@ -266,13 +265,13 @@ begin
DFtotal := NumCases - 1; DFtotal := NumCases - 1;
DFresid := DFtotal - DFreg; DFresid := DFtotal - DFreg;
AReport.Add('ANOVA'); AReport.Add('ANOVA');
AReport.Add('------------------------------------------------------------------------------'); AReport.Add('--------------------------------------------------------------------------');
AReport.Add('SOURCE DF Sum of Squares Mean Square F Probability'); AReport.Add('SOURCE DF Sum of Squares Mean Square F Probability');
AReport.Add('---------- --- ---------------- ---------------- ------------ -----------'); AReport.Add('---------- --- ---------------- ---------------- -------- -----------');
AReport.Add('Regression %3d %16.3f %16.3f %12.4f %10.4f', [DFreg, SSreg, SSreg/DFreg, F, Probability]); AReport.Add('Regression %4d %16.3f %16.3f %8.3f %10.3f', [DFreg, SSreg, SSreg/DFreg, F, Probability]);
AReport.Add('Residual %3d %16.3f %16.3f', [DFresid, SSresid, SSresid/DFresid]); AReport.Add('Residual %4d %16.3f %16.3f', [DFresid, SSresid, SSresid/DFresid]);
AReport.Add('Total %3d %16.3f', [DFtotal, SStotal]); AReport.Add('Total %4d %16.3f', [DFtotal, SStotal]);
AReport.Add('------------------------------------------------------------------------------'); AReport.Add('--------------------------------------------------------------------------');
AReport.Add(''); AReport.Add('');
AReport.Add('R2: %10.4f', [R2]); AReport.Add('R2: %10.4f', [R2]);
AReport.Add('Adjusted R2: %10.4f', [AdjR2]); AReport.Add('Adjusted R2: %10.4f', [AdjR2]);
@ -291,9 +290,9 @@ var
i, first, last: Integer; i, first, last: Integer;
begin begin
AReport.Add('COEFFICIENTS'); AReport.Add('COEFFICIENTS');
AReport.Add('------------------------------------------------------------------------------'); AReport.Add('--------------------------------------------------------------------------');
AReport.Add(' Variable Unstandardized Std.Error Standardized t p '); AReport.Add(' Variable Unstandardized Std.Error Standardized t p ');
AReport.Add('------------ -------------- ------------ ------------ --------- ---------'); AReport.Add('------------ -------------- ------------ ------------ ------- -------');
first := 0; first := 0;
last := High(Coeffs); last := High(Coeffs);
@ -307,10 +306,10 @@ begin
else else
varName := Format('VAR.%d', [i+1]); varName := Format('VAR.%d', [i+1]);
AReport.Add('%12s %14.3f %12.3f %12.3f %9.4f %9.4f', AReport.Add('%12s %14.3f %12.3f %12.3f %7.3f %7.3f',
[varName, Coeffs[i], CoeffStdErrors[i], Beta[i], t[i], p[i]]); [varName, Coeffs[i], CoeffStdErrors[i], Beta[i], t[i], p[i]]);
end; end;
AReport.Add('------------------------------------------------------------------------------'); AReport.Add('--------------------------------------------------------------------------');
end; end;
@ -323,12 +322,26 @@ begin
end; end;
{ Writes the cross-product matrix to a "report"
The names of the independent variables are neede in the array AVarNames. }
procedure TMultipleRegressionResults.WriteCrossProductsReport(AReport: TStrings;
AVarNames: TStringArray);
var
saved: String;
begin
saved := AVarNames[High(AVarNames)];
AVarNames[High(AVarNames)] := '(Intercept)';
WriteMatrixReport(AReport, XT_X, 'CROSS-PRODUCT MATRIX', AVarNames);
AVarNames[High(AVarNames)] := saved;
end;
procedure TMultipleRegressionResults.WriteMatrixReport(AReport: TStrings; procedure TMultipleRegressionResults.WriteMatrixReport(AReport: TStrings;
AMatrix: TDblMatrix; ATitle: String; AVarNames: TStringArray); AMatrix: TDblMatrix; ATitle: String; AVarNames: TStringArray);
function GetVarName(i: Integer): String; function GetVarName(i: Integer): String;
begin begin
if i < High(AVarNames) then if i <= High(AVarNames) then
Result := AVarNames[i] Result := AVarNames[i]
else else
Result := Format('VAR.%d', [i+1]); Result := Format('VAR.%d', [i+1]);
@ -376,5 +389,90 @@ begin
end; end;
procedure PredictMR(const xData: TDblMatrix; const yData: TDblVector;
const ARegressionResults: TMultipleRegressionResults;
out zPred, zResid, RawPred, RawResid, StdErrPred, Hi95, Lo95: TDblVector);
var
i, j, k, n, m: Integer;
x, x1, x2, y: Double;
term1, term2, t: Double;
begin
zPred := nil; // to silence the compiler
zResid := nil;
RawPred := nil;
RawResid := nil;
StdErrPred := nil;
Hi95 := nil;
Lo95 := nil;
MatSize(xData, n,m);
// z predicted and zResidual
SetLength(zPred, n);
SetLength(zResid, n);
for i := 0 to n-1 do
begin
zPred[i] := 0;
for j := 0 to m-1 do
begin
x := (xData[i, j] - ARegressionResults.xMeans[j]) / ARegressionResults.xStdDevs[j];
zPred[i] := zPred[i] + ARegressionResults.Beta[j] * x;
end;
y := (yData[i] - ARegressionResults.yMean) / ARegressionResults.yStdDev;
zResid[i] := y - zPred[i];
end;
// Raw predicted and raw residuals
SetLength(RawPred, n);
SetLength(RawResid, n);
for i := 0 to n-1 do
begin
RawPred[i] := ARegressionResults.Coeffs[m]; // intercept
for j := 0 to m-1 do
RawPred[i] := RawPred[i] + ARegressionResults.Coeffs[j] * xData[i, j];
RawResid[i] := yData[i] - RawPred[i];
end;
// Calculate confidence interval for raw predicted score
SetLength(StdErrPred, n);
SetLength(Hi95, n);
SetLength(Lo95, n);
for i := 0 to n-1 do
begin
// Get term1 of the std. err. prediction
term1 := 0.0;
for j := 0 to m-1 do
begin
with ARegressionResults do
begin
x := (xData[i, j] - xMeans[j]) / xStdDevs[j];
term1 := term1 + x * x * InvIndepCorrs[j, j];;
end;
end;
// Get term2 of the std err. of prediction
term2 := 0.0;
for j := 0 to m-1 do
begin
for k := j + 1 to m-1 do
begin
with ARegressionResults do
begin
x1 := (xData[i, j] - xMeans[j]) / xStdDevs[j];
x2 := (xData[i, k] - xMeans[k]) / xStdDevs[k];
term2 := term2 + x1 * x2 * InvIndepCorrs[j, k];
end;
end;
end;
term2 := 2.0 * Term2;
stdErrPred[i] := sqrt(n + 1 + term1 + term2);
stdErrPred[i] := (ARegressionResults.StdErrorEstimate / sqrt(n)) * stdErrPred[i];
t := InverseT(0.975, n - m - 1);
Lo95[i] := RawPred[i] - t*StdErrPred[i];
Hi95[i] := RawPred[i] + t*StdErrPred[i];
end;
end;
end. end.