2020-03-30 18:01:44 +00:00
|
|
|
// Use file "itemdata2.laz" for testing
|
|
|
|
|
|
|
|
unit WithinANOVAUnit;
|
|
|
|
|
|
|
|
{$mode objfpc}{$H+}
|
|
|
|
|
|
|
|
interface
|
|
|
|
|
|
|
|
uses
|
2020-10-22 22:14:06 +00:00
|
|
|
Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs,
|
|
|
|
StdCtrls, Buttons, ExtCtrls, ComCtrls, Math,
|
|
|
|
MainUnit, FunctionsLib, MatrixLib, Globals,
|
|
|
|
ReportFrameUnit, BasicStatsReportAndChartFormUnit;
|
2020-03-30 18:01:44 +00:00
|
|
|
|
|
|
|
type
|
|
|
|
|
|
|
|
{ TWithinANOVAFrm }
|
|
|
|
|
2020-10-23 17:58:24 +00:00
|
|
|
TWithinANOVAResults = record
|
|
|
|
// Sum of squares
|
|
|
|
SSRows, SScols, SSwithinRows, SStotal, SSresidual: Double;
|
|
|
|
// Mean square errors
|
|
|
|
MSRows, MScols, MSwithinRows, MStotal, MSresidual: Double;
|
|
|
|
// Degrees of freedom
|
|
|
|
DFRows, DFcols, DFWithinRows, DFtotal, DFresidual: Integer;
|
|
|
|
// Grand mean
|
|
|
|
GrandMean: Double;
|
|
|
|
// F value
|
|
|
|
F: Double;
|
|
|
|
// Probability for > F
|
|
|
|
Probability: Double;
|
|
|
|
end;
|
|
|
|
|
2020-10-22 22:14:06 +00:00
|
|
|
TWithinANOVAFrm = class(TBasicStatsReportAndChartForm)
|
2020-03-30 18:01:44 +00:00
|
|
|
AssumpChk: TCheckBox;
|
|
|
|
PlotChk: TCheckBox;
|
|
|
|
RelChk: TCheckBox;
|
|
|
|
GroupBox1: TGroupBox;
|
|
|
|
InBtn: TBitBtn;
|
|
|
|
Label2: TLabel;
|
|
|
|
SelList: TListBox;
|
|
|
|
OutBtn: TBitBtn;
|
|
|
|
Label1: TLabel;
|
2020-10-22 22:14:06 +00:00
|
|
|
ReliabilityPage: TTabSheet;
|
|
|
|
TestAssumptionsPage: TTabSheet;
|
2020-03-30 18:01:44 +00:00
|
|
|
VarList: TListBox;
|
|
|
|
procedure InBtnClick(Sender: TObject);
|
|
|
|
procedure OutBtnClick(Sender: TObject);
|
2020-10-22 22:14:06 +00:00
|
|
|
procedure SelListDblClick(Sender: TObject);
|
|
|
|
procedure VarListDblClick(Sender: TObject);
|
|
|
|
procedure VarListSelectionChange(Sender: TObject; {%H-}User: boolean);
|
|
|
|
|
2020-03-30 18:01:44 +00:00
|
|
|
private
|
2020-10-22 22:14:06 +00:00
|
|
|
FReliabilityReportFrame: TReportFrame;
|
|
|
|
FTestAssumptionsReportFrame: TReportFrame;
|
2020-10-23 17:58:24 +00:00
|
|
|
|
|
|
|
procedure CalcANOVA(
|
|
|
|
const ARowSums, ARowSumsOfSquares, AColSums, AColSumsOfSquares: DblDyneVec;
|
|
|
|
const AGrandSum, AGrandSumOfSquares: Double;
|
|
|
|
out ARowMeans, ARowVariances, AColMeans,AColVariances: DblDyneVec;
|
|
|
|
out AResults: TWithinANOVAResults);
|
|
|
|
|
|
|
|
procedure CalcReliability(const AResults: TWithinANOVAResults;
|
|
|
|
ANumSelected: Integer; out R1, R2, R3, R4: Double);
|
|
|
|
|
|
|
|
procedure GetData(
|
|
|
|
out ASelected: IntDyneVec; out AColLabels: StrDyneVec;
|
|
|
|
out ARowSums, ARowSumsOfSquares, AColSums, AColSumsOfSquares: DblDyneVec;
|
|
|
|
out AGrandSum, AGrandSumOfSquares: Double);
|
|
|
|
|
2020-10-22 22:14:06 +00:00
|
|
|
procedure Plot(ColMeans: DblDyneVec; ColLabels: StrDyneVec);
|
2020-10-23 17:58:24 +00:00
|
|
|
|
|
|
|
procedure TestAssumptions(const ASelected: IntDyneVec;
|
|
|
|
out ASampleVarCovarMat, AssumedVarCovarMat: DblDyneMat;
|
|
|
|
out ADeterminant1, ADeterminant2, Chi2, AProbability: Double;
|
|
|
|
out DF: Integer; out ErrorFound: Boolean);
|
|
|
|
|
|
|
|
procedure WriteANOVAReport(const AColLabels: StrDyneVec;
|
|
|
|
const AColMeans, AColVariances: DblDyneVec; const AResults: TWithinANOVAResults);
|
|
|
|
|
|
|
|
procedure WriteReliabilityReport(const R1, R2, R3, R4: Double);
|
|
|
|
|
|
|
|
procedure WriteTestAssumptionsReport(
|
|
|
|
const ASampleVarCovarMat, AssumedVarCovarMat: DblDyneMat;
|
|
|
|
const AColLabels: StrDyneVec;
|
|
|
|
ADeterminant1, ADeterminant2, Chi2, AProbability: Double; DF: Integer;
|
|
|
|
ErrorFound: Boolean);
|
|
|
|
|
2020-10-22 22:14:06 +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-22 22:14:06 +00:00
|
|
|
constructor Create(AOwner: TComponent); override;
|
|
|
|
procedure Reset; override;
|
2020-03-30 18:01:44 +00:00
|
|
|
end;
|
|
|
|
|
|
|
|
var
|
|
|
|
WithinANOVAFrm: TWithinANOVAFrm;
|
|
|
|
|
2020-10-22 22:14:06 +00:00
|
|
|
|
2020-03-30 18:01:44 +00:00
|
|
|
implementation
|
|
|
|
|
2020-10-22 22:14:06 +00:00
|
|
|
{$R *.lfm}
|
|
|
|
|
2020-09-28 14:05:34 +00:00
|
|
|
uses
|
2020-10-22 22:14:06 +00:00
|
|
|
TAChartUtils, TACustomSeries,
|
|
|
|
GridProcs,
|
2020-10-23 17:58:24 +00:00
|
|
|
Utils, MathUnit, MatrixUnit, ChartFrameUnit;
|
2020-09-28 14:05:34 +00:00
|
|
|
|
2020-03-30 18:01:44 +00:00
|
|
|
|
2020-10-22 22:14:06 +00:00
|
|
|
{ TWithinANOVAFrm }
|
2020-03-30 18:01:44 +00:00
|
|
|
|
2020-10-22 22:14:06 +00:00
|
|
|
constructor TWithinANOVAFrm.Create(AOwner: TComponent);
|
2020-03-30 18:01:44 +00:00
|
|
|
begin
|
2020-10-22 22:14:06 +00:00
|
|
|
inherited;
|
|
|
|
|
|
|
|
FReliabilityReportFrame := TReportFrame.Create(self);
|
|
|
|
FReliabilityReportFrame.Name := '';
|
|
|
|
FReliabilityReportFrame.Parent := ReliabilityPage;
|
|
|
|
FReliabilityReportFrame.Align := alClient;
|
|
|
|
FReliabilityReportFrame.BorderSpacing.Left := 0;
|
|
|
|
FReliabilityReportFrame.BorderSpacing.Top := 0;
|
|
|
|
FReliabilityReportFrame.BorderSpacing.Bottom := 0;
|
|
|
|
FReliabilityReportFrame.BorderSpacing.Right := 0;
|
|
|
|
|
|
|
|
FTestAssumptionsReportFrame := TReportFrame.Create(self);
|
|
|
|
FTestAssumptionsReportFrame.Name := '';
|
|
|
|
FTestAssumptionsReportFrame.Parent := TestAssumptionsPage;
|
|
|
|
FTestAssumptionsReportFrame.Align := alClient;
|
|
|
|
FTestAssumptionsReportFrame.BorderSpacing.Left := 0;
|
|
|
|
FTestAssumptionsReportFrame.BorderSpacing.Top := 0;
|
|
|
|
FTestAssumptionsReportFrame.BorderSpacing.Bottom := 0;
|
|
|
|
FTestAssumptionsReportFrame.BorderSpacing.Right := 0;
|
|
|
|
|
|
|
|
FChartFrame.Chart.Margins.Bottom := 0;
|
|
|
|
|
|
|
|
PageControl.ActivePageIndex := 0;
|
2020-03-30 18:01:44 +00:00
|
|
|
end;
|
|
|
|
|
|
|
|
|
2020-10-22 22:14:06 +00:00
|
|
|
procedure TWithinANOVAFrm.AdjustConstraints;
|
2020-03-30 18:01:44 +00:00
|
|
|
begin
|
2020-10-22 22:14:06 +00:00
|
|
|
inherited;
|
|
|
|
|
|
|
|
ParamsPanel.Constraints.MinWidth := Max(
|
|
|
|
4*CloseBtn.Width + 3*CloseBtn.BorderSpacing.Left,
|
|
|
|
GroupBox1.Width
|
|
|
|
);
|
|
|
|
ParamsPanel.Constraints.MinHeight := OutBtn.Top + 6*OutBtn.Height +
|
|
|
|
VarList.BorderSpacing.Bottom + GroupBox1.Height + ButtonBevel.Height +
|
|
|
|
CloseBtn.BorderSpacing.Top + CloseBtn.Height;
|
2020-03-30 18:01:44 +00:00
|
|
|
end;
|
|
|
|
|
|
|
|
|
2020-10-23 17:58:24 +00:00
|
|
|
procedure TWithinANOVAFrm.CalcANOVA(
|
|
|
|
const ARowSums, ARowSumsOfSquares, AColSums, AColSumsOfSquares: DblDyneVec;
|
|
|
|
const AGrandSum, AGrandSumOfSquares: Double;
|
|
|
|
out ARowMeans, ARowVariances, AColMeans,AColVariances: DblDyneVec;
|
|
|
|
out AResults: TWithinANOVAResults);
|
2020-03-30 18:01:44 +00:00
|
|
|
var
|
2020-10-23 17:58:24 +00:00
|
|
|
S: Double = 0;
|
|
|
|
SS: Double = 0;
|
|
|
|
term1, term2, term3, term4: Double;
|
|
|
|
noSelected: Integer;
|
|
|
|
i, count: Integer;
|
|
|
|
|
2020-03-30 18:01:44 +00:00
|
|
|
begin
|
2020-10-23 17:58:24 +00:00
|
|
|
noSelected := SelList.Items.Count;
|
|
|
|
count := Length(ARowSums);
|
2020-03-30 18:01:44 +00:00
|
|
|
|
2020-10-23 17:58:24 +00:00
|
|
|
term1 := sqr(AGrandSum) / (count * noSelected);
|
2020-03-30 18:01:44 +00:00
|
|
|
|
2020-10-23 17:58:24 +00:00
|
|
|
term2 := AGrandSumOfSquares;
|
2020-03-30 18:01:44 +00:00
|
|
|
|
2020-10-23 17:58:24 +00:00
|
|
|
SS := 0;
|
|
|
|
for i := 0 to count-1 do
|
|
|
|
SS := SS + sqr(ARowSums[i]);
|
|
|
|
term4 := SS / noSelected;
|
2020-03-30 18:01:44 +00:00
|
|
|
|
2020-10-23 17:58:24 +00:00
|
|
|
SS := 0;
|
|
|
|
for i := 0 to noSelected-1 do
|
|
|
|
SS := SS + sqr(AColSums[i]);
|
|
|
|
term3 := SS / count;
|
|
|
|
|
|
|
|
AResults.SSrows := term4 - term1;
|
|
|
|
AResults.SScols := term3 - term1;
|
|
|
|
AResults.SSwithinRows := term2 - term4;
|
|
|
|
AResults.SSresidual := term2 - term3 - term4 + term1;
|
|
|
|
AResults.SStotal := term2 - term1;
|
|
|
|
|
|
|
|
AResults.DFrows := count - 1;
|
|
|
|
AResults.DFcols := noSelected - 1;
|
|
|
|
AResults.DFwithinRows := count * (noSelected - 1);
|
|
|
|
AResults.DFresidual := (count - 1) * (noSelected - 1);
|
|
|
|
AResults.DFtotal := count * noSelected - 1;
|
|
|
|
|
|
|
|
AResults.MSrows := AResults.SSrows / AResults.DFRows;
|
|
|
|
AResults.MScols := AResults.SScols / AResults.DFcols;
|
|
|
|
AResults.MSwithinRows := AResults.SSwithinRows / AResults.DFwithinRows;
|
|
|
|
AResults.MSresidual := AResults.SSresidual / AResults.DFresidual;
|
|
|
|
AResults.MStotal := AResults.SStotal / AResults.DFtotal; // variance of all scores
|
|
|
|
|
|
|
|
AResults.GrandMean := AGrandSum / (count * noSelected);
|
|
|
|
(*
|
|
|
|
AResults.SSRows := VecSum(ARowMeans);
|
|
|
|
|
|
|
|
term1 := sqr(AGrandSum) / (count * noSelected);
|
|
|
|
term2 := AGrandSumOfSquares);
|
2020-03-30 18:01:44 +00:00
|
|
|
|
|
|
|
|
2020-10-22 22:14:06 +00:00
|
|
|
Term1 := sqr(GrandMean) / (count * NoSelected);
|
2020-03-30 18:01:44 +00:00
|
|
|
Term2 := SStot;
|
2020-10-22 22:14:06 +00:00
|
|
|
for i := 0 to count-1 do
|
|
|
|
SSrows := SSrows + sqr(RowMeans[i]);
|
2020-03-30 18:01:44 +00:00
|
|
|
Term4 := SSrows / NoSelected;
|
2020-10-22 22:14:06 +00:00
|
|
|
for i := 0 to NoSelected-1 do
|
|
|
|
SScols := SScols + sqr(ColMeans[i]);
|
2020-03-30 18:01:44 +00:00
|
|
|
Term3 := SScols / count;
|
|
|
|
SSrows := Term4 - Term1;
|
|
|
|
SScols := Term3 - Term1;
|
|
|
|
SSwrows := Term2 - Term4;
|
|
|
|
SSerr := Term2 - Term3 - Term4 + Term1;
|
|
|
|
SStot := Term2 - Term1;
|
|
|
|
dfrows := count - 1;
|
|
|
|
dfcols := NoSelected - 1;
|
|
|
|
dfwrows := count * (NoSelected - 1);
|
|
|
|
dferr := (count - 1) * (NoSelected - 1);
|
|
|
|
dftot := (count * NoSelected) - 1;
|
|
|
|
MSrows := SSrows / dfrows;
|
|
|
|
MScols := SScols / dfcols;
|
|
|
|
MSwrows := SSwrows / dfwrows;
|
|
|
|
MSerr := SSerr / dferr;
|
|
|
|
MStot := SStot / dftot; // variance of all scores
|
|
|
|
GrandMean := GrandMean / (count * NoSelected);
|
|
|
|
for i := 0 to count-1 do
|
|
|
|
begin
|
|
|
|
RowVar[i] := RowVar[i] - (RowMeans[i] * RowMeans[i] / NoSelected);
|
|
|
|
RowVar[i] := RowVar[i] / (NoSelected - 1);
|
|
|
|
RowMeans[i] := RowMeans[i] / NoSelected;
|
|
|
|
end;
|
|
|
|
for i := 0 to NoSelected-1 do
|
|
|
|
begin
|
|
|
|
ColVar[i] := ColVar[i] - (ColMeans[i] * ColMeans[i] / count);
|
|
|
|
ColVar[i] := ColVar[i] / (count - 1);
|
|
|
|
ColMeans[i] := ColMeans[i] / count;
|
|
|
|
end;
|
|
|
|
f1 := MScols / MSerr; // treatment F statistic
|
2020-09-28 14:05:34 +00:00
|
|
|
probf1 := ProbF(f1, dfcols, dferr);
|
2020-10-23 17:58:24 +00:00
|
|
|
*)
|
2020-03-30 18:01:44 +00:00
|
|
|
|
2020-10-23 17:58:24 +00:00
|
|
|
SetLength(ARowMeans, count);
|
|
|
|
SetLength(ARowVariances, count);
|
|
|
|
for i := 0 to count-1 do
|
2020-03-30 18:01:44 +00:00
|
|
|
begin
|
2020-10-23 17:58:24 +00:00
|
|
|
ARowVariances[i] := (ARowSumsOfSquares[i] - (ARowSums[i] * ARowSums[i]) / noSelected) / (noSelected - 1);
|
|
|
|
ARowMeans[i] := ARowSums[i] / noSelected;
|
2020-03-30 18:01:44 +00:00
|
|
|
end;
|
|
|
|
|
2020-10-23 17:58:24 +00:00
|
|
|
SetLength(AColMeans, noSelected);
|
|
|
|
SetLength(AColVariances, noSelected);
|
|
|
|
for i := 0 to noSelected-1 do
|
|
|
|
begin
|
|
|
|
AColVariances[i] := (AColSumsOfSquares[i] - (AColSums[i] * AColSums[i]) / count) / (count - 1);
|
|
|
|
AColMeans[i] := AColSums[i] / count;
|
|
|
|
end;
|
2020-03-30 18:01:44 +00:00
|
|
|
|
2020-10-23 17:58:24 +00:00
|
|
|
with AResults do
|
|
|
|
begin
|
|
|
|
F := MScols / MSresidual; // treatment F statistic
|
|
|
|
Probability := ProbF(F, DFcols, DFresidual);
|
|
|
|
end;
|
|
|
|
end;
|
2020-10-22 22:14:06 +00:00
|
|
|
|
2020-03-30 18:01:44 +00:00
|
|
|
|
2020-10-23 17:58:24 +00:00
|
|
|
procedure TWithinANOVAFrm.CalcReliability(const AResults: TWithinANOVAResults;
|
|
|
|
ANumSelected: Integer; out R1, R2, R3, R4: Double);
|
|
|
|
begin
|
|
|
|
with AResults do
|
|
|
|
begin
|
|
|
|
// unadjusted reliability of test
|
|
|
|
R1 := 1.0 - (MSwithinRows / MSrows);
|
2020-03-30 18:01:44 +00:00
|
|
|
|
2020-10-23 17:58:24 +00:00
|
|
|
// R2 is unadjusted reliability of a single item
|
|
|
|
R2 := (MSrows - MSwithinRows) / (MSrows + (ANumSelected - 1) * MSwithinRows);
|
2020-03-30 18:01:44 +00:00
|
|
|
|
2020-10-23 17:58:24 +00:00
|
|
|
// Cronbach alpha for test
|
|
|
|
R3 := (MSrows - MSresidual) / MSrows;
|
|
|
|
|
|
|
|
// R4 is adjusted reliability of a single item
|
|
|
|
R4 := (MSrows - MSresidual) / (MSrows + (ANumSelected - 1) * MSresidual);
|
2020-03-30 18:01:44 +00:00
|
|
|
end;
|
2020-10-23 17:58:24 +00:00
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
procedure TWithinANOVAFrm.Compute;
|
|
|
|
var
|
|
|
|
j, noSelected, DF: integer;
|
|
|
|
r1, r2, r3, r4: double;
|
|
|
|
grandSum, grandSS: Double;
|
|
|
|
determ1, determ2, chi2, prob: Double;
|
|
|
|
errorfound: boolean;
|
|
|
|
selected: IntDyneVec = nil;
|
|
|
|
colLabels: StrDyneVec = nil;
|
|
|
|
colSums: DblDyneVec = nil;
|
|
|
|
colMeans: DblDyneVec = nil;
|
|
|
|
colSS: DblDyneVec = nil;
|
|
|
|
colVars: DblDyneVec = nil;
|
|
|
|
rowSums: DblDyneVec = nil;
|
|
|
|
rowMeans: DblDyneVec = nil;
|
|
|
|
rowSS: DblDyneVec = nil;
|
|
|
|
rowVars: DblDyneVec = nil;
|
|
|
|
sampleVarCovarMat: DblDyneMat = nil;
|
|
|
|
assumedVarCovarMat: DblDyneMat = nil;
|
|
|
|
res: TWithinANOVAResults;
|
|
|
|
begin
|
|
|
|
noSelected := SelList.Items.Count;
|
|
|
|
|
|
|
|
// Read data and compute sums while reading
|
|
|
|
GetData(selected, colLabels, rowSums, rowSS, colSums, colSS, grandSum, grandSS);
|
|
|
|
|
|
|
|
// Calculate ANOVA
|
|
|
|
CalcANOVA(rowSums, rowSS, colSums, colSS, grandSum, grandSS, rowMeans, rowVars, colMeans, colVars, res);
|
|
|
|
WriteANOVAReport(colLabels, colMeans, colVars, res);
|
2020-03-30 18:01:44 +00:00
|
|
|
|
2020-10-23 17:58:24 +00:00
|
|
|
// Do reliability terms if requested
|
|
|
|
if RelChk.Checked then
|
|
|
|
begin
|
|
|
|
CalcReliability(res, noSelected, r1, r2, r3, r4);
|
|
|
|
WriteReliabilityReport(r1, r2, r3, r4);
|
|
|
|
ReliabilityPage.TabVisible := RelChk.Checked;
|
|
|
|
end;
|
|
|
|
|
|
|
|
// Test assumptions of variance - covariance homogeneity if requested
|
|
|
|
if AssumpChk.Checked then
|
|
|
|
begin
|
|
|
|
TestAssumptions(selected, sampleVarCovarMat, assumedVarCovarMat, determ1, determ2, chi2, prob, DF, errorFound);
|
|
|
|
WriteTestAssumptionsReport(sampleVarCovarMat, assumedVarCovarMat, colLabels, determ1, determ2, chi2, prob, DF, errorFound);
|
|
|
|
end;
|
|
|
|
TestAssumptionsPage.TabVisible := AssumpChk.Checked;
|
|
|
|
|
|
|
|
// Finally, plot values if indicated in options list
|
2020-03-30 18:01:44 +00:00
|
|
|
if PlotChk.Checked then
|
2020-10-22 22:14:06 +00:00
|
|
|
Plot(ColMeans, ColLabels);
|
|
|
|
ChartPage.TabVisible := PlotChk.Checked;
|
2020-10-23 17:58:24 +00:00
|
|
|
|
|
|
|
// Make sure that the chart tab is at the end of the pagecontrol.
|
2020-10-22 22:14:06 +00:00
|
|
|
ChartPage.PageIndex := PageControl.PageCount-1;
|
2020-03-30 18:01:44 +00:00
|
|
|
end;
|
|
|
|
|
2020-10-22 22:14:06 +00:00
|
|
|
|
2020-10-23 17:58:24 +00:00
|
|
|
procedure TWithinANOVAFrm.GetData(
|
|
|
|
out ASelected: IntDyneVec; out AColLabels: StrDyneVec;
|
|
|
|
out ARowSums, ARowSumsOfSquares, AColSums, AColSumsOfSquares: DblDyneVec;
|
|
|
|
out AGrandSum, AGrandSumOfSquares: Double);
|
|
|
|
var
|
|
|
|
i, j, row, count, noSelected: Integer;
|
|
|
|
k: Integer;
|
|
|
|
X, Xsq: Double;
|
|
|
|
begin
|
|
|
|
ARowSums := nil; // to silence FPC 3.2
|
|
|
|
ARowSumsOfSquares := nil;
|
|
|
|
AColSums := nil;
|
|
|
|
AColSumsOfSquares := nil;
|
|
|
|
AColLabels := nil;
|
|
|
|
ASelected := nil;
|
|
|
|
|
|
|
|
noSelected := SelList.Items.Count;
|
|
|
|
SetLength(ASelected, noSelected);
|
|
|
|
SetLength(AColLabels, noSelected);
|
|
|
|
SetLength(AColSums, noSelected);
|
|
|
|
SetLength(AColSumsOfSquares, noSelected);
|
|
|
|
SetLength(ARowSums, NoCases);
|
|
|
|
SetLength(ARowSumsOfSquares, NoCases);
|
|
|
|
|
|
|
|
for i := 0 to noSelected-1 do
|
|
|
|
begin
|
|
|
|
ASelected[i] := GetVariableIndex(OS3MainFrm.DataGrid, SelList.Items[i]);
|
|
|
|
AColLabels[i] := SelList.Items[i];
|
|
|
|
end;
|
|
|
|
|
|
|
|
for i := 0 to noSelected-1 do
|
|
|
|
begin
|
|
|
|
AColSums[i] := 0.0;
|
|
|
|
AColSumsOfSquares[i] := 0.0;
|
|
|
|
end;
|
|
|
|
for j := 0 to NoCases-1 do
|
|
|
|
begin
|
|
|
|
ARowSums[j] := 0.0;
|
|
|
|
ARowSumsOfSquares[j] := 0.0;
|
|
|
|
end;
|
|
|
|
|
|
|
|
AGrandSum := 0;
|
|
|
|
AGrandSumOfSquares := 0;
|
|
|
|
count := 0;
|
|
|
|
row := 0;
|
|
|
|
|
|
|
|
for i := 1 to NoCases do
|
|
|
|
begin
|
|
|
|
if not GoodRecord(OS3MainFrm.DataGrid, i, ASelected) then continue;
|
|
|
|
count := count + 1;
|
|
|
|
for j := 0 to High(ASelected) do
|
|
|
|
begin
|
|
|
|
k := ASelected[j];
|
|
|
|
X := StrToFloat(Trim(OS3MainFrm.DataGrid.Cells[k, i]));
|
|
|
|
Xsq := X*X;
|
|
|
|
ARowSums[row] := ARowSums[row] + X;
|
|
|
|
ARowSumsOfSquares[row] := ARowSumsOfSquares[row] + Xsq;
|
|
|
|
AColSums[j] := AColSums[j] + X;
|
|
|
|
AColSumsOfSquares[j] := AColSumsOfSquares[j] + Xsq;
|
|
|
|
AGrandSum := AGrandSum + X;
|
|
|
|
AGrandSumOfSquares := AGrandSumOfSquares + XSq;
|
|
|
|
end;
|
|
|
|
row := row + 1;
|
|
|
|
end;
|
|
|
|
|
|
|
|
SetLength(ARowSums, count);
|
|
|
|
SetLength(ARowSumsOfSquares, count);
|
|
|
|
// Lengths of AColSums etc already correct.
|
|
|
|
end;
|
|
|
|
|
2020-03-30 18:01:44 +00:00
|
|
|
procedure TWithinANOVAFrm.InBtnClick(Sender: TObject);
|
|
|
|
var
|
|
|
|
i: integer;
|
|
|
|
begin
|
|
|
|
i := 0;
|
|
|
|
while i < VarList.Items.Count do
|
|
|
|
begin
|
|
|
|
if VarList.Selected[i] then
|
|
|
|
begin
|
|
|
|
SelList.Items.Add(VarList.Items[i]);
|
|
|
|
VarList.Items.Delete(i);
|
|
|
|
i := 0;
|
|
|
|
end else
|
|
|
|
inc(i);
|
|
|
|
end;
|
|
|
|
UpdateBtnStates;
|
|
|
|
end;
|
|
|
|
|
2020-10-22 22:14:06 +00:00
|
|
|
|
2020-03-30 18:01:44 +00:00
|
|
|
procedure TWithinANOVAFrm.OutBtnClick(Sender: TObject);
|
|
|
|
var
|
|
|
|
i: integer;
|
|
|
|
begin
|
|
|
|
i := 0;
|
|
|
|
while i < SelList.Items.Count do
|
|
|
|
begin
|
|
|
|
if SelList.Selected[i] then
|
|
|
|
begin
|
|
|
|
VarList.Items.Add(SelList.Items[i]);
|
|
|
|
SelList.Items.Delete(i);
|
|
|
|
i := 0;
|
|
|
|
end else
|
|
|
|
inc(i);
|
|
|
|
end;
|
|
|
|
VarList.ItemIndex := -1;
|
|
|
|
SelList.ItemIndex := -1;
|
|
|
|
UpdateBtnStates;
|
|
|
|
end;
|
|
|
|
|
2020-10-22 22:14:06 +00:00
|
|
|
|
|
|
|
procedure TWithinANOVAFrm.Plot(ColMeans: DblDyneVec; ColLabels: StrDyneVec);
|
|
|
|
var
|
|
|
|
ser: TChartSeries;
|
|
|
|
begin
|
|
|
|
FChartFrame.Clear;
|
|
|
|
|
|
|
|
FChartFrame.SetTitle('WITHIN SUBJECTS ANOVA');
|
|
|
|
FChartFrame.SetXTitle('Repeated Measure Variables');
|
|
|
|
FChartFrame.SetYTitle('Mean');
|
|
|
|
|
|
|
|
ser := FChartFrame.PlotXY(ptBars, nil, ColMeans, ColLabels, nil, '', DATA_COLORS[0]);
|
|
|
|
FChartFrame.Chart.BottomAxis.Marks.Source := ser.Source;
|
|
|
|
FChartFrame.Chart.BottomAxis.Marks.Style := smsLabel;
|
|
|
|
FChartFrame.Chart.Legend.Visible := false;
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
procedure TWithinANOVAFrm.Reset;
|
|
|
|
var
|
|
|
|
i: integer;
|
|
|
|
begin
|
|
|
|
inherited;
|
|
|
|
|
|
|
|
if FReliabilityReportFrame <> nil then
|
|
|
|
FReliabilityReportFrame.Clear;
|
|
|
|
if FTestAssumptionsReportFrame <> nil then
|
|
|
|
FTestAssumptionsReportFrame.Clear;
|
|
|
|
|
|
|
|
VarList.Clear;
|
|
|
|
SelList.Clear;
|
|
|
|
PlotChk.Checked := false;
|
|
|
|
RelChk.Checked := false;
|
|
|
|
AssumpChk.Checked := false;
|
|
|
|
for i := 1 to NoVariables do
|
|
|
|
VarList.Items.Add(OS3MainFrm.DataGrid.Cells[i,0]);
|
|
|
|
|
|
|
|
ReliabilityPage.TabVisible := false;
|
|
|
|
TestAssumptionsPage.TabVisible := false;
|
|
|
|
ChartPage.TabVisible := false;
|
|
|
|
|
|
|
|
UpdateBtnStates;
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
procedure TWithinANOVAFrm.SelListDblClick(Sender: TObject);
|
|
|
|
var
|
|
|
|
index: Integer;
|
|
|
|
begin
|
|
|
|
index := SelList.ItemIndex;
|
|
|
|
if index > -1 then
|
|
|
|
begin
|
|
|
|
VarList.Items.Add(SelList.Items[index]);
|
|
|
|
SelList.Items.Delete(index);
|
|
|
|
UpdateBtnStates;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
2020-10-23 17:58:24 +00:00
|
|
|
procedure TWithinANOVAFrm.TestAssumptions(const ASelected: IntDyneVec;
|
|
|
|
out ASampleVarCovarMat, AssumedVarCovarMat: DblDyneMat;
|
|
|
|
out ADeterminant1, ADeterminant2, Chi2, AProbability: Double;
|
|
|
|
out DF: Integer; out ErrorFound: Boolean);
|
|
|
|
var
|
|
|
|
vcMat: DblDyneMat = nil;
|
|
|
|
workMat: DblDyneMat = nil;
|
|
|
|
colMeans: DblDyneVec = nil;
|
|
|
|
colVars: DblDyneVec = nil;
|
|
|
|
colStdDevs: DblDyneVec = nil;
|
|
|
|
avgVar, avgCov, C2, M2: Double;
|
|
|
|
i, j, noSelected, count: Integer;
|
|
|
|
begin
|
|
|
|
ErrorFound := false;
|
|
|
|
noSelected := Length(ASelected);
|
|
|
|
count := NoCases;
|
|
|
|
|
|
|
|
DF := 0;
|
|
|
|
Chi2 := NaN;
|
|
|
|
AProbability := NaN;
|
|
|
|
|
|
|
|
SetLength(ASampleVarCovarMat, noSelected+1, noSelected+1); // +1 due to augmentation in GridCovar
|
|
|
|
SetLength(AssumedVarCovarMat, noSelected+1, noSelected+1);
|
|
|
|
SetLength(vcMat, noSelected+1, noSelected+1);
|
|
|
|
SetLength(workMat, noSelected+1, noSelected+1);
|
|
|
|
SetLength(colMeans, noSelected+1);
|
|
|
|
SetLength(colVars, noSelected+1);
|
|
|
|
SetLength(colStdDevs, noSelected+1);
|
|
|
|
|
|
|
|
GridCovar(noSelected, ASelected, ASampleVarCovarMat, colMeans, colVars, colStdDevs, ErrorFound, count);
|
|
|
|
if Errorfound then
|
|
|
|
begin
|
|
|
|
ErrorMsg('Zero variance found for a variable.');
|
|
|
|
exit;
|
|
|
|
end;
|
|
|
|
|
|
|
|
// get average of variances into workmat diagonal and average of
|
|
|
|
// covariances into workmat off-diagonals (See Winer, pg 371)
|
|
|
|
avgVar := 0.0;
|
|
|
|
avgCov := 0.0;
|
|
|
|
for i := 0 to noSelected-1 do
|
|
|
|
vcMat[i, i] := ASampleVarCovarMat[i,i];
|
|
|
|
|
|
|
|
for i := 0 to noSelected-2 do
|
|
|
|
begin
|
|
|
|
for j := i+1 to noSelected-1 do
|
|
|
|
begin
|
|
|
|
vcMat[i, j] := ASampleVarCovarMat[i, j];
|
|
|
|
vcMat[j, i] := vcMat[i, j];
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
for i := 0 to noSelected-1 do
|
|
|
|
avgVar := avgVar + ASampleVarCovarMat[i, i];
|
|
|
|
|
|
|
|
for i := 0 to NoSelected-2 do
|
|
|
|
for j := i+1 to NoSelected-1 do
|
|
|
|
avgCov := avgCov + ASampleVarCovarMat[i, j];
|
|
|
|
|
|
|
|
avgVar := avgVar / noSelected;
|
|
|
|
avgCov := avgCov / (noSelected * noSelected - 1) / 2.0;
|
|
|
|
|
|
|
|
for i := 0 to noSelected-1 do
|
|
|
|
workMat[i, i] := avgVar;
|
|
|
|
|
|
|
|
for i := 0 to noSelected-2 do
|
|
|
|
begin
|
|
|
|
for j := i+1 to noSelected-1 do
|
|
|
|
begin
|
|
|
|
workMat[i, j] := avgCov;
|
|
|
|
workMat[j, i] := workMat[i, j];
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
// get determinants of SampleVarCovarMat and workMat
|
|
|
|
Determ(vcMat, noSelected, noSelected, ADeterminant1, ErrorFound);
|
|
|
|
if ADeterminant1 < 0.0 then ADeterminant1 := 0.0;
|
|
|
|
|
|
|
|
Determ(workMat, noSelected, noSelected, ADeterminant2, ErrorFound);
|
|
|
|
if ADeterminant2 < 0.0 then ADeterminant2 := 0.0;
|
|
|
|
|
|
|
|
// Get assumed var-covariance matrix
|
|
|
|
count := NoCases;
|
|
|
|
GridCovar(noSelected, ASelected, AssumedVarCovarMat, colMeans, colVars, colStdDevs, ErrorFound, count);
|
|
|
|
ErrorFound := false;
|
|
|
|
if ((ADeterminant1 > 0.0) and (ADeterminant2 > 0.0)) then
|
|
|
|
M2 := -(NoCases*noSelected - 1) * ln(ADeterminant1 / ADeterminant2)
|
|
|
|
else
|
|
|
|
begin
|
|
|
|
M2 := 0.0;
|
|
|
|
errorFound := true;
|
|
|
|
ErrorMsg('A determinant <= zero was found.');
|
|
|
|
end;
|
|
|
|
|
|
|
|
if not ErrorFound then
|
|
|
|
begin
|
|
|
|
C2 := noSelected * (noSelected+1) * (noSelected + 1) * (2 * noSelected - 3);
|
|
|
|
C2 := C2 / (6 * (count - 1) * (noSelected - 1) * (noSelected * noSelected + noSelected - 4));
|
|
|
|
Chi2 := (1.0 - C2) * M2;
|
|
|
|
DF := (noSelected * noSelected + noSelected - 4) div 2;
|
|
|
|
if ((Chi2 > 0.01) and (Chi2 < 1000.0)) then
|
|
|
|
AProbability := ChiSquaredProb(Chi2, DF)
|
|
|
|
else
|
|
|
|
begin
|
|
|
|
if Chi2 <= 0.0 then AProbability := 1.0;
|
|
|
|
if Chi2 >= 1000.0 then AProbability := 0.0;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
for i := 0 to NoSelected-1 do
|
|
|
|
for j := 0 to NoSelected-1 do
|
|
|
|
AssumedVarCovarMat[i,j] := workMat[i, j];
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
2020-03-30 18:01:44 +00:00
|
|
|
procedure TWithinANOVAFrm.UpdateBtnStates;
|
|
|
|
var
|
|
|
|
i: Integer;
|
|
|
|
lEnabled: Boolean;
|
|
|
|
begin
|
2020-10-22 22:14:06 +00:00
|
|
|
inherited;
|
|
|
|
|
|
|
|
if FReliabilityReportFrame <> nil then
|
|
|
|
FReliabilityReportFrame.UpdateBtnStates;
|
|
|
|
if FTestAssumptionsReportFrame <> nil then
|
|
|
|
FTestAssumptionsReportFrame.UpdateBtnStates;
|
|
|
|
|
2020-03-30 18:01:44 +00:00
|
|
|
lEnabled := false;
|
|
|
|
for i:=0 to VarList.Items.Count-1 do
|
|
|
|
if VarList.Selected[i] then
|
|
|
|
begin
|
|
|
|
lEnabled := true;
|
|
|
|
break;
|
|
|
|
end;
|
|
|
|
InBtn.Enabled := lEnabled;
|
|
|
|
|
|
|
|
lEnabled := false;
|
|
|
|
for i:=0 to SelList.Items.Count-1 do
|
|
|
|
if SelList.Selected[i] then
|
|
|
|
begin
|
|
|
|
lEnabled := true;
|
|
|
|
break;
|
|
|
|
end;
|
|
|
|
OutBtn.Enabled := lEnabled;
|
|
|
|
end;
|
|
|
|
|
2020-10-22 22:14:06 +00:00
|
|
|
|
|
|
|
function TWithinANOVAFrm.Validate(out AMsg: String; out AControl: TWinControl): Boolean;
|
|
|
|
begin
|
|
|
|
Result := false;
|
|
|
|
|
|
|
|
if SelList.Items.Count = 0 then
|
|
|
|
begin
|
|
|
|
AControl := VarList;
|
|
|
|
AMsg := 'No variables selected.';
|
|
|
|
exit;
|
|
|
|
end;
|
|
|
|
if SelList.Items.Count = 1 then
|
|
|
|
begin
|
|
|
|
AControl := VarList;
|
|
|
|
AMsg := 'At least two variables must be selected.';
|
|
|
|
exit;
|
|
|
|
end;
|
|
|
|
|
|
|
|
Result := true;
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
procedure TWithinANOVAFrm.VarListDblClick(Sender: TObject);
|
|
|
|
var
|
|
|
|
index: Integer;
|
|
|
|
begin
|
|
|
|
index := VarList.ItemIndex;
|
|
|
|
if index > -1 then
|
|
|
|
begin
|
|
|
|
SelList.Items.Add(VarList.Items[index]);
|
|
|
|
VarList.Items.Delete(index);
|
|
|
|
UpdateBtnStates;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
2020-03-30 18:01:44 +00:00
|
|
|
procedure TWithinANOVAFrm.VarListSelectionChange(Sender: TObject;
|
|
|
|
User: boolean);
|
|
|
|
begin
|
|
|
|
UpdateBtnStates;
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
2020-10-23 17:58:24 +00:00
|
|
|
{ Write ANOVA results to ReportFrame }
|
|
|
|
procedure TWithinANOVAFrm.WriteANOVAReport(const AColLabels: StrDyneVec;
|
|
|
|
const AColMeans, AColVariances: DblDyneVec; const AResults: TWithinANOVAResults);
|
|
|
|
var
|
|
|
|
lReport: TStrings;
|
|
|
|
noSelected: Integer;
|
|
|
|
i: Integer;
|
|
|
|
begin
|
|
|
|
noSelected := Length(AColMeans);
|
|
|
|
|
|
|
|
lReport := TStringList.Create;
|
|
|
|
try
|
|
|
|
with AResults do
|
|
|
|
begin
|
|
|
|
lReport.Add('TREATMENTS BY SUBJECTS (AxS) ANOVA RESULTS');
|
|
|
|
lReport.Add('');
|
|
|
|
lReport.Add('Data File: ' + OS3MainFrm.FileNameEdit.Text);
|
|
|
|
lReport.Add('');
|
|
|
|
lReport.Add('-----------------------------------------------------------------');
|
|
|
|
lReport.Add('SOURCE DF SS MS F Prob. > F');
|
|
|
|
lReport.Add('-----------------------------------------------------------------');
|
|
|
|
lReport.Add('SUBJECTS %4d %10.3f %10.3f', [DFrows, SSrows, MSrows]);
|
|
|
|
lReport.Add('WITHIN SUBJECTS %4d %10.3f %10.3f', [DFwithinRows, SSwithinRows, MSwithinRows]);
|
|
|
|
lReport.Add(' TREATMENTS %4d %10.3f %10.3f %10.3f %10.3f', [DFcols, SScols, MScols, F, Probability]);
|
|
|
|
lReport.Add(' RESIDUAL %4d %10.3f %10.3f', [DFresidual, SSresidual, MSresidual]);
|
|
|
|
lReport.Add('-----------------------------------------------------------------');
|
|
|
|
lReport.Add('TOTAL %4d %10.3f %10.3f', [DFtotal, SStotal, MStotal]);
|
|
|
|
lReport.Add('-----------------------------------------------------------------');
|
|
|
|
lReport.Add('');
|
|
|
|
lReport.Add('');
|
|
|
|
|
|
|
|
lReport.Add('TREATMENT (COLUMN) MEANS AND STANDARD DEVIATIONS');
|
|
|
|
lReport.Add('');
|
|
|
|
lReport.Add('VARIABLE MEAN STD.DEV. ');
|
|
|
|
lReport.Add('-------- ---------- ----------');
|
|
|
|
|
|
|
|
for i := 1 to NoSelected do
|
|
|
|
lReport.Add('%-8s %10.3f %10.3f', [AColLabels[i-1], AColMeans[i-1], sqrt(AColVariances[i-1])]);
|
|
|
|
|
|
|
|
lReport.Add('');
|
|
|
|
lReport.Add('Mean of all scores: %8.3f', [GrandMean]);
|
|
|
|
lReport.Add(' with standard deviation: %8.3f', [sqrt(MStotal)]);
|
|
|
|
end;
|
|
|
|
|
|
|
|
FReportFrame.DisplayReport(lReport);
|
|
|
|
finally
|
|
|
|
lReport.Free;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
procedure TWithinANOVAFrm.WriteReliabilityReport(const R1, R2, R3, R4: double);
|
|
|
|
var
|
|
|
|
lReport: TStrings;
|
|
|
|
begin
|
|
|
|
lReport := TStringList.Create;
|
|
|
|
try
|
|
|
|
lReport.Add('RELIABILITY ESTIMATES');
|
|
|
|
lReport.Add('');
|
|
|
|
lReport.Add('TYPE OF ESTIMATE VALUE ');
|
|
|
|
lReport.Add('---------------------------- -------');
|
|
|
|
lReport.Add('Unadjusted total reliability %7.3f', [R1]);
|
|
|
|
lReport.Add('Unadjusted item reliability %7.3f', [R2]);
|
|
|
|
lReport.Add('Adjusted total (Cronbach) %7.3f', [R3]);
|
|
|
|
lReport.Add('Adjusted item reliability %7.3f', [R4]);
|
|
|
|
|
|
|
|
FReliabilityReportFrame.DisplayReport(lReport);
|
|
|
|
finally
|
|
|
|
lReport.Free;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
procedure TWithinANOVAFrm.WriteTestAssumptionsReport(
|
|
|
|
const ASampleVarCovarMat, AssumedVarCovarMat: DblDyneMat;
|
|
|
|
const AColLabels: StrDyneVec;
|
|
|
|
ADeterminant1, ADeterminant2, Chi2, AProbability: Double; DF: Integer;
|
|
|
|
ErrorFound: Boolean);
|
|
|
|
var
|
|
|
|
lReport: TStrings;
|
|
|
|
title: String;
|
|
|
|
noSelected: Integer;
|
|
|
|
begin
|
|
|
|
noSelected := SelList.Items.Count;
|
|
|
|
|
|
|
|
lReport := TStringList.Create;
|
|
|
|
try
|
|
|
|
lReport.Add('BOX TEST FOR HOMOGENEITY OF VARIANCE-COVARIANCE MATRIX');
|
|
|
|
lReport.Add('');
|
|
|
|
|
|
|
|
title := 'SAMPLE COVARIANCE MATRIX';
|
|
|
|
MatPrint(ASampleVarCovarMat, noSelected, noSelected, title, AColLabels, AColLabels, NoCases, lReport);
|
|
|
|
lReport.Add('');
|
|
|
|
|
|
|
|
title := 'ASSUMED POPULATION COVARIANCE MATRIX';
|
|
|
|
MatPrint(AssumedVarCovarMat, noSelected, noSelected, title, AColLabels, AColLabels, NoCases, lReport);
|
|
|
|
lReport.Add('');
|
|
|
|
|
|
|
|
lReport.Add('Determinant of variance-covariance matrix: %10.3g', [ADeterminant1]);
|
|
|
|
lReport.Add('Determinant of homogeneity matrix: %10.3g', [ADeterminant2]);
|
|
|
|
if not errorfound then
|
|
|
|
begin
|
|
|
|
lReport.Add('ChiSquare: %10.3f', [Chi2]);
|
|
|
|
lReport.Add(' with %d degrees of freedom', [DF]);
|
|
|
|
lReport.Add('Probability of larger chisquare: %10.3f', [1.0 - AProbability]);
|
|
|
|
end;
|
|
|
|
|
|
|
|
FTestAssumptionsReportFrame.DisplayReport(lReport);
|
|
|
|
finally
|
|
|
|
lReport.Free;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
2020-03-30 18:01:44 +00:00
|
|
|
end.
|
|
|
|
|