Files
lazarus-ccr/applications/lazstats/source/forms/analysis/comparisons/abcnestedunit.pas

1044 lines
29 KiB
ObjectPascal
Raw Normal View History

{ Test file: ABCNested.laz (imported from OpenStat sample data zip file)
Dependent: Dep
Factor A : A
Factor B : B
Factor C : C
}
unit ABCNestedUnit;
{$mode objfpc}{$H+}
{$WARN 6058 off : Call to subroutine "$1" marked as inline is not inlined}
interface
uses
Classes, SysUtils, FileUtil, TAStyles, Forms, Controls, Graphics, Dialogs,
StdCtrls, Buttons, ExtCtrls, ComCtrls, LCLVersion,
TACustomSeries,
MainUnit, Globals, ReportFrameUnit, BasicStatsReportAndChartFormUnit;
type
{ TABCNestedForm }
TABCNestedForm = class(TBasicStatsReportAndChartForm)
ChartStyles: TChartStyles;
ShowPlotsChk: TCheckBox;
Plot3DChk: TCheckBox;
FactorCEdit: TEdit;
FactorAEdit: TEdit;
AInBtn: TBitBtn;
AOutBtn: TBitBtn;
FactorBEdit: TEdit;
BInBtn: TBitBtn;
BOutBtn: TBitBtn;
DepEdit: TEdit;
DepInBtn: TBitBtn;
CInBtn: TBitBtn;
DepOutBtn: TBitBtn;
COutBtn: TBitBtn;
PlotOptionsGroup: TGroupBox;
Label1: TLabel;
Label2: TLabel;
Label3: TLabel;
Label4: TLabel;
Label5: TLabel;
Memo1: TLabel;
Panel1: TPanel;
MeansPage: TTabSheet;
VarList: TListBox;
procedure AInBtnClick(Sender: TObject);
procedure AOutBtnClick(Sender: TObject);
procedure BInBtnClick(Sender: TObject);
procedure BOutBtnClick(Sender: TObject);
procedure CInBtnClick(Sender: TObject);
procedure COutBtnClick(Sender: TObject);
procedure DepInBtnClick(Sender: TObject);
procedure DepOutBtnClick(Sender: TObject);
procedure Plot3DChkChange(Sender: TObject);
procedure ShowPlotsChkChange(Sender: TObject);
procedure VarListDblClick(Sender: TObject);
procedure VarListSelectionChange(Sender: TObject; {%H-}User: boolean);
private
CellCount: IntDyneCube;
ASS, BSS, CSS, ASumSqr, BSumSqr, CSumSqr, ASDs, BSDs, CSDs : DblDyneVec;
ACSS,ACSumSqr, ACSDs, ABSS, ABSumSqr, ABSDs : DblDyneMat;
ACount, BCount, CCount : IntDyneVec;
ACCount, ABCount : IntDyneMat;
CellSDs, SS, SumSqr, CellMeans : DblDyneCube;
MinA, MaxA, NoALevels: Integer;
MinB, MaxB, NoBLevels: Integer;
MinC, MaxC, NoCLevels: integer;
SSTot, SumSqrTot, TotMean, MSTot, SSA, MSA, SSB, MSB, SSW, MSW : double;
SSC, MSC, SSAC, MSAC, SSBwAC, SSAB, MSBwAC : double;
TotN, dfA, dfBwA, dfwcell, dftotal, dfC, dfAC, dfBwAC : integer;
AMeans, BMeans, CMeans: DblDyneVec;
ABMeans, ACMeans: DblDyneMat;
function GetVariables(out AValues, BValues, CValues, DepValues: DblDyneVec): Boolean;
procedure GetMemory;
procedure GetSums(const AValues, BValues, CValues, DepValues: DblDyneVec);
procedure ShowMeans;
procedure GetResults;
procedure ShowResults;
procedure ReleaseMemory;
procedure TwoWayPlot;
private
FMeansReportFrame: TReportFrame;
FChartCombobox: TCombobox;
FSeries: TChartSeries;
procedure PopulateChartCombobox;
procedure SelectPlot(Sender: TObject);
protected
procedure AdjustConstraints; override;
procedure Compute; override;
procedure UpdateBtnStates; override;
function Validate(out AMsg: String; out AControl: TWinControl): Boolean; override;
public
constructor Create(AOwner: TComponent); override;
procedure Reset; override;
end;
var
ABCNestedForm: TABCNestedForm;
implementation
{$R *.lfm}
uses
Math,
TAChartUtils, TACustomSource, TALegend, TASeries,
Utils, MathUnit, MatrixUnit, GridProcs, ChartFrameUnit;
{ TABCNestedForm }
constructor TABCNestedForm.Create(AOwner: TComponent);
begin
inherited;
FMeansReportFrame := TReportFrame.Create(MeansPage);
FMeansReportFrame.Parent := MeansPage;
FMeansReportFrame.Align := alClient;
InitToolbar(FMeansReportFrame.ReportToolbar, tpTop);
MeansPage.PageIndex := 1;
FChartFrame.Chart.Margins.Bottom := 0;
FChartFrame.Chart.BottomAxis.AxisPen.Visible := true;
FChartFrame.Chart.BottomAxis.ZPosition := 1;
FChartFrame.Chart.BottomAxis.Grid.Visible := false;
AddComboboxToToolbar(FChartFrame.ChartToolbar, 'Plots:', FChartCombobox);
FChartCombobox.OnSelect := @SelectPlot;
PageControl.ActivePageIndex := 0;
end;
procedure TABCNestedForm.AdjustConstraints;
begin
inherited;
ParamsPanel.Constraints.MinWidth := Max(
4*CloseBtn.Width + 3*CloseBtn.BorderSpacing.Left,
MaxValue([Label2.Width, Label3.Width, Label4.Width, Label5.Width])*2 + AInBtn.Width + VarList.BorderSpacing.Right*2
);
ParamsPanel.Constraints.MinHeight := COutBtn.Top + COutBtn.Height +
ButtonBevel.Height + CloseBtn.Height + CloseBtn.BorderSpacing.Top;
end;
procedure TABCNestedForm.AInBtnClick(Sender: TObject);
var
index: integer;
begin
index := VarList.ItemIndex;
if (index > -1) and (FactorAEdit.Text = '') then
begin
FactorAEdit.Text := VarList.Items[index];
VarList.Items.Delete(index);
end;
UpdateBtnStates;
end;
procedure TABCNestedForm.AOutBtnClick(Sender: TObject);
begin
if FactorAEdit.Text <> '' then
begin
VarList.Items.Add(FactorAEdit.Text);
FactorAEdit.Text := '';
end;
UpdateBtnStates;
end;
procedure TABCNestedForm.BInBtnClick(Sender: TObject);
var
index: integer;
begin
index := VarList.ItemIndex;
if (index > -1) and (FactorBEdit.Text = '') then
begin
FactorBEdit.Text := VarList.Items[index];
VarList.Items.Delete(index);
end;
UpdateBtnStates;
end;
procedure TABCNestedForm.BOutBtnClick(Sender: TObject);
begin
if FactorBEdit.Text <> '' then
begin
VarList.Items.Add(FactorBEdit.Text);
FactorBEdit.Text := '';
end;
UpdateBtnStates;
end;
procedure TABCNestedForm.CInBtnClick(Sender: TObject);
var
index: integer;
begin
index := VarList.ItemIndex;
if (index > -1) and (FactorCEdit.Text = '') then
begin
FactorCEdit.Text := VarList.Items[index];
VarList.Items.Delete(index);
end;
UpdateBtnStates;
end;
procedure TABCNestedForm.COutBtnClick(Sender: TObject);
begin
if FactorCEdit.Text <> '' then
begin
VarList.Items.Add(FactorCEdit.Text);
FactorCEdit.Text := '';
end;
UpdateBtnStates;
end;
procedure TABCNestedForm.Compute;
var
dataA: DblDyneVec = nil;
dataB: DblDyneVec = nil;
dataC: DblDyneVec = nil;
dataDep: DblDyneVec = nil;
begin
if GetVariables(dataA, dataB, dataC, dataDep) then
begin
GetMemory;
GetSums(dataA, dataB, dataC, dataDep);
ShowMeans;
GetResults;
ShowResults;
TwoWayPlot;
ReleaseMemory;
end;
end;
procedure TABCNestedForm.DepInBtnClick(Sender: TObject);
var
index: integer;
begin
index := VarList.ItemIndex;
if (index > -1) and (DepEdit.Text = '') then
begin
DepEdit.Text := VarList.Items[index];
VarList.Items.Delete(index);
end;
UpdateBtnStates;
end;
procedure TABCNestedForm.DepOutBtnClick(Sender: TObject);
begin
if DepEdit.Text <> '' then
begin
VarList.Items.Add(DepEdit.Text);
DepEdit.Text := '';
end;
UpdateBtnStates;
end;
procedure TABCNestedForm.Plot3DChkChange(Sender: TObject);
begin
if FSeries is TBarSeries then
begin
if Plot3dChk.Checked then
TBarSeries(FSeries).Depth := 20
else
TBarSeries(FSeries).Depth := 0;
end;
end;
procedure TABCNestedForm.ShowPlotsChkChange(Sender: TObject);
begin
ChartPage.TabVisible := ShowPlotsChk.Checked;
Plot3DChk.Enabled := ShowPlotsChk.Checked;
end;
procedure TABCNestedForm.PopulateChartCombobox;
var
a, b, c: String;
idx: Integer;
begin
idx := FChartCombobox.ItemIndex;
a := FactorAEdit.Text;
b := FactorBEdit.Text;
c := FactorCEdit.Text;
FChartCombobox.Items.Clear;
FChartCombobox.Items.Add(a);
FChartCombobox.Items.Add(b);
FChartCombobox.Items.Add(c);
FChartCombobox.Items.Add(Format('%s x %s', [a, b]));
FChartCombobox.Items.Add(Format('%s x %s', [a, c]));
FChartCombobox.ItemIndex := EnsureRange(idx, 0, FChartCombobox.Items.Count-1);
end;
function TABCNestedForm.GetVariables(
out AValues, BValues, CValues, DepValues: DblDyneVec): Boolean;
var
ColNoSelected: IntDyneVec = nil;
mn, mx: Double;
msg: String;
begin
Result := false;
SetLength(ColNoSelected, 4);
ColNoSelected[0] := GetVariableIndex(OS3MainFrm.DataGrid, FactorAEdit.Text); // A
ColNoSelected[1] := GetVariableIndex(OS3MainFrm.DataGrid, FactorBEdit.Text); // B
ColNoSelected[2] := GetVariableIndex(OS3MainFrm.DataGrid, FactorCEdit.Text); // C
ColNoSelected[3] := GetVariableindex(OS3MainFrm.DataGrid, DepEdit.Text); // Dependent
AValues := CollectVecValues(OS3MainFrm.DataGrid, ColNoSelected[0], ColNoSelected);
if not CheckFactorCodes(FactorAEdit.Text, AValues, msg) then
begin
ErrorMsg(msg);
exit;
end;
BValues := CollectVecValues(OS3MainFrm.DataGrid, ColNoSelected[1], ColNoSelected);
if not CheckFactorCodes(FactorBEdit.Text, BValues, msg) then
begin
ErrorMsg(msg);
exit;
end;
CValues := CollectVecValues(OS3MainFrm.DataGrid, ColNoSelected[2], ColNoSelected);
if not CheckFactorCodes(FactorCEdit.Text, CValues, msg) then
begin
ErrorMsg(msg);
exit;
end;
DepValues := CollectVecValues(OS3MainFrm.DataGrid, ColNoSelected[3], ColNoSelected);
if (Length(DepValues) <> Length(AValues)) or
(Length(DepValues) <> Length(BValues)) or
(Length(DepValues) <> Length(CValues)) then
begin
ErrorMsg('All variables must contain equal amounts of cases.');
exit;
end;
VecMaxMin(AValues, mx, mn);
MaxA := round(mx);
MinA := round(mn);
VecMaxMin(BValues, mx, mn);
MaxB := round(mx);
MinB := round(mn);
VecMaxMin(CValues, mx, mn);
MaxC := round(mx);
MinC := round(mn);
NoALevels := MaxA - MinA + 1;
NoBLevels := MaxB - MinB + 1;
NoCLevels := MaxC - MinC + 1;
Result := true;
end;
procedure TABCNestedForm.GetMemory;
begin
SS := CubeCreate(NoBLevels, NoALevels, NoCLevels);
SumSqr := CubeCreate(NoBLevels, NoALevels, NoCLevels);
CellCount := IntCubeCreate(NoBLevels, NoALevels, NoCLevels);
CellMeans := CubeCreate(NoBLevels, NoALevels, NoCLevels);
CellSDs := CubeCreate(NoBLevels, NoALevels, NoCLevels);
ASS := VecCreate(NoALevels);
BSS := VecCreate(NoBLevels);
CSS := VecCreate(NoCLevels);
ASumSqr := VecCreate(NoALevels);
BSumSqr := VecCreate(NoBLevels);
CSumSqr := VecCreate(NoCLevels);
AMeans := VecCreate(NoALevels);
BMeans := VecCreate(NoBLevels);
CMeans := VecCreate(NoCLevels);
ACount := IntVecCreate(NoALevels);
BCount := IntVecCreate(NoBLevels);
CCount := IntVecCreate(NoCLevels);
ASDs := VecCreate(NoALevels);
BSDs := VecCreate(NoBLevels);
CSDs := VecCreate(NoCLevels);
ACSS := MatCreate(NoALevels, NoCLevels);
ACSumSqr := MatCreate(NoALevels, NoCLevels);
ACCount := IntMatCreate(NoALevels, NoCLevels);
ACMeans := MatCreate(NoALevels, NoCLevels);
ACSDs := MatCreate(NoALevels, NoCLevels);
ABSS := MatCreate(NoALevels, NoBLevels);
ABSumSqr := MatCreate(NoALevels, NoBLevels);
ABMeans := MatCreate(NoALevels, NoBLevels);
ABCount := IntMatCreate(NoALevels, NoBLevels);
ABSDs := MatCreate(NoALevels,NoBLevels);
end;
procedure TABCNestedForm.GetSums(const AValues, BValues, CValues, DepValues: DblDyneVec);
VAR
Aindex, Bindex, Cindex, i, j, k: integer;
YValue, YValueSqr: double;
begin
// Accumulate sums and sums of squared values
SSTot := 0.0;
SumSqrTot := 0.0;
TotN := 0;
for i := 0 to High(DepValues) do
begin
AIndex := round(AValues[i]) - MinA;
BIndex := round(BValues[i]) - MinB;
CIndex := round(CValues[i]) - MinC;
YValue := DepValues[i];
YValueSqr := YValue * YValue;
SS[Bindex,Aindex,Cindex] := SS[Bindex,Aindex,Cindex] + YValueSqr;
SumSqr[Bindex,Aindex,Cindex] := SumSqr[Bindex,Aindex,Cindex] + YValue; // wp: why no square?
CellCount[Bindex,Aindex,Cindex] := CellCount[Bindex,Aindex,Cindex] + 1;
ACount[Aindex] := ACount[Aindex] + 1;
BCount[Bindex] := BCount[Bindex] + 1;
CCount[Cindex] := CCount[Cindex] + 1;
ASS[Aindex] := ASS[Aindex] + YValueSqr;
BSS[Bindex] := BSS[Bindex] + YValueSqr;
CSS[Cindex] := CSS[Cindex] + YValueSqr;
ASumSqr[Aindex] := ASumSqr[Aindex] + YValue;
BSumSqr[Bindex] := BSumSqr[Bindex] + YValue;
CSumSqr[Cindex] := CSumSqr[Cindex] + YValue;
ACSS[Aindex,Cindex] := ACSS[Aindex,Cindex] + YValueSqr;
ACSumSqr[Aindex,Cindex] := ACSumSqr[Aindex,Cindex] + YValue;
ACCount[Aindex,Cindex] := ACCount[Aindex,Cindex] + 1;
ABSS[Aindex,Bindex] := ABSS[Aindex,Bindex] + YValueSqr;
ABSumSqr[Aindex,Bindex] := ABSumSqr[Aindex,Bindex] + YValue;
ABCount[Aindex,Bindex] := ABCount[Aindex,Bindex] + 1;
SSTot := SSTot + YValueSqr;
SumSqrTot := SumSqrTot + YValue;
TotN := TotN + 1;
end;
// Get cell means and marginal means plus square of sums
for i := 0 to NoBLevels-1 do
begin
for j := 0 to NoALevels-1 do
begin
for k := 0 to NoCLevels-1 do
begin
if CellCount[i,j,k] > 0 then
begin
CellMeans[i,j,k] := SumSqr[i,j,k] / CellCount[i,j,k];
SumSqr[i,j,k] := SumSqr[i,j,k] * SumSqr[i,j,k];
CellSDs[i,j,k] := SS[i,j,k] - (SumSqr[i,j,k] / CellCount[i,j,k]);
CellSDs[i,j,k] := CellSDs[i,j,k] / (CellCount[i,j,k] - 1);
CellSDs[i,j,k] := sqrt(CellSDs[i,j,k]);
end;
end;
end;
end;
for i := 0 to NoBLevels-1 do
begin
if BCount[i] > 0 then
begin
BMeans[i] := BSumSqr[i] / BCount[i];
BSumSqr[i] := BSumSqr[i] * BSumSqr[i];
BSDs[i] := BSS[i] - (BSumSqr[i] / BCount[i]);
BSDs[i] := BSDs[i] / (BCount[i] - 1);
BSDs[i] := sqrt(BSDs[i]);
end;
end;
for i := 0 to NoALevels-1 do
begin
AMeans[i] := ASumSqr[i] / ACount[i];
ASumSqr[i] := ASumSqr[i] * ASumSqr[i];
ASDs[i] := ASS[i] - (ASumSqr[i] / ACount[i]);
ASDs[i] := ASDs[i] / (ACount[i] - 1);
ASDs[i] := Sqrt(ASDs[i]);
end;
for i := 0 to NoCLevels-1 do
begin
CMeans[i] := CSumSqr[i] / CCount[i];
CSumSqr[i] := CSumSqr[i] * CSumSqr[i];
CSDs[i] := CSS[i] - (CSumSqr[i] / CCount[i]);
CSDs[i] := CSDs[i] / (CCount[i] - 1);
CSDs[i] := sqrt(CSDs[i]);
end;
for i := 0 to NoALevels-1 do
begin
for k := 0 to NoCLevels-1 do
begin
ACMeans[i,k] := ACMeans[i,k] / ACCount[i,k];
ACSumSqr[i,k] := ACSumSqr[i,k] * ACSumSqr[i,k];
ACSDs[i,k] := ACSS[i,k] - (ACSumSqr[i,k] / ACCount[i,k]);
ACSDs[i,k] := ACSDs[i,k] / (ACCount[i,k] - 1);
ACSDs[i,k] := sqrt(ACSDs[i,k]);
end;
end;
for i := 0 to NoALevels-1 do
begin
for j := 0 to NoBLevels-1 do
begin
if ABCount[i,j] > 0 then
begin
ABMeans[i,j] := ABSumSqr[i,j] / ABCount[i,j];
ABSumSqr[i,j] := ABSumSqr[i,j] * ABSumSqr[i,j];
ABSDs[i,j] := ABSS[i,j] - (ABSumSqr[i,j] / ABCount[i,j]);
ABSDs[i,j] := ABSDs[i,j] / (ABCount[i,j] - 1);
ABSDs[i,j] := sqrt(ABSDs[i,j]);
end;
end;
end;
TotMean := SumSqrTot / TotN;
SumSqrTot := SumSqrTot * SumSqrTot;
end;
procedure TABCNestedForm.ShowMeans;
var
lReport: TStrings;
i, j, k : integer;
begin
lReport := TStringList.Create;
try
lReport.Add('Nested ANOVA by Bill Miller');
lReport.Add('');
lReport.Add('File analyzed: %s', [OS3MainFrm.FileNameEdit.Text]);
lReport.Add('Factor A: %s', [FactorAEdit.Text]);
lReport.Add('Factor B: %s', [FactorBEdit.Text]);
lReport.Add('Factor C: %s', [FactorCEdit.Text]);
lReport.Add('');
lReport.Add('CELL MEANS');
lReport.Add('-----------------------------------------------------');
lReport.Add('A LEVEL B LEVEL C LEVEL MEAN STD.DEV. ');
lReport.Add('------- ------- ------- ---------- ----------');
for i := 0 to NoALevels-1 do
for j := 0 to NoBLevels-1 do
for k := 0 to NoCLevels-1 do
if CellCount[j,i,k] > 0 then
lReport.Add('%5d %5d %5d %10.3f %10.3f', [i+MinA, j+MinB, k+MinC, CellMeans[j,i,k], CellSDs[j,i,k]]);
lReport.Add('-----------------------------------------------------');
lReport.Add('');
lReport.Add('A MARGIN MEANS');
lReport.Add('---------------------------------');
lReport.Add('A LEVEL MEAN STD.DEV. ');
lReport.Add('------- ---------- ----------');
for i := 0 to NoALevels-1 do
lReport.Add('%5d %10.3f %10.3f', [i+MinA, AMeans[i], ASDs[i]]);
lReport.Add('---------------------------------');
lReport.Add('');
lReport.Add('B MARGIN MEANS');
lReport.Add('---------------------------------');
lReport.Add('B LEVEL MEAN STD.DEV. ');
lReport.Add('------- ---------- ----------');
for i := 0 to NoBLevels-1 do
if BCount[i] > 0 then
lReport.Add('%5d %10.3f %10.3f', [i+MinB, BMeans[i], BSDs[i]]);
lReport.Add('---------------------------------');
lReport.Add('');
lReport.Add('C MARGIN MEANS');
lReport.Add('---------------------------------');
lReport.Add('C LEVEL MEAN STD.DEV. ');
lReport.Add('------- ---------- ----------');
for i := 0 to NoCLevels-1 do
if CCount[i] > 0 then
lReport.Add('%5d %10.3f %10.3f', [i+MinC, CMeans[i], CSDs[i]]);
lReport.Add('---------------------------------');
lReport.Add('');
lReport.Add('AB MARGIN MEANS');
lReport.Add('-------------------------------------------');
lReport.Add('A LEVEL B LEVEL MEAN STD.DEV. ');
lReport.Add('------- ------- ---------- ----------');
for i := 0 to NoALevels-1 do
for j := 0 to NoBLevels-1 do
if ABCount[i,j] > 0 then
lReport.Add('%5d %5d %10.3f %10.3f', [i+MinA, j+MinB, ABMeans[i,j], ABSDs[i,j]]);
lReport.Add('-------------------------------------------');
lReport.Add('');
lReport.Add('AC MARGIN MEANS');
lReport.Add('-------------------------------------------');
lReport.Add('A LEVEL C LEVEL MEAN STD.DEV. ');
lReport.Add('------- ------- ---------- ----------');
for i := 0 to NoALevels-1 do
for j := 0 to NoCLevels-1 do
if ACCount[i,j] > 0 then
lReport.Add('%5d %5d %10.3f %10.3f',[i+MinA, j+MinC, ACMeans[i,j], ACSDs[i,j]]);
lReport.Add('-------------------------------------------');
lReport.Add('');
lReport.Add('GRAND MEAN: %10.3f', [TotMean]);
lReport.Add('');
FMeansReportFrame.DisplayReport(lReport);
finally
lReport.Free;
end;
end;
procedure TABCNestedForm.GetResults;
VAR
temp, temp2, temp3, temp4, constant : double;
NoBLevelsInA, BLevCount, i, j, k, celln : integer;
begin
celln := 0;
for i := 0 to NoALevels-1 do
begin
for j := 0 to NoBLevels-1 do
begin
for k := 0 to NoCLevels-1 do
begin
if CellCount[j,i,k] > celln then celln := CellCount[j,i,k];
end;
end;
end;
// Assume all cells have same n size
// Get number of levels in A
BLevCount := 0;
for i := 0 to NoALevels-1 do
begin
NoBLevelsInA := 0;
for j := 0 to NoBLevels-1 do
begin
if CellCount[j,i,0] > 0 then NoBLevelsInA := NoBLevelsInA + 1;
end;
if NoBLevelsInA > BLevCount then BLevCount := NoBLevelsInA;
end;
dfA := NoALevels - 1;
dfBwA := NoALevels * (BLevCount - 1);
dfC := NoCLevels - 1;
dfAC := (NoALevels-1) * (NoCLevels-1);
dfBwAC := NoALevels * (BLevCount-1) * (NoCLevels -1);
dfwcell := NoALevels * BLevCount * NoCLevels * (celln - 1);
dftotal := TotN - 1;
constant := SumSqrTot / TotN;
SSTot := SSTot - constant;
MSTot := SSTot / dftotal;
// Get A Effects
SSA := 0.0;
for i := 0 to NoALevels-1 do SSA := SSA + (ASumSqr[i] / ACount[i]);
temp := SSA;
SSA := SSA - constant;
MSA := SSA / dfA;
// Get C Effects
SSC := 0.0;
for i := 0 to NoCLevels-1 do SSC := SSC + (CSumSqr[i] / CCount[i]);
temp2 := SSC;
SSC := SSC - constant;
MSC := SSC / dfC;
// Get B within A
SSB := 0.0;
for i := 0 to NoALevels - 1 do
begin
for j := 0 to NoBLevels-1 do
begin
if ABCount[i,j] > 0 then SSB := SSB + (ABSumSqr[i,j] / ABCount[i,j]);
end;
end;
temp3 := SSB;
SSB := SSB - temp;
MSB := SSB / dfBwA;
// Get AC interaction
SSAC := 0.0;
for i := 0 to NoALevels-1 do
begin
for j := 0 to NoCLevels-1 do SSAC := SSAC + ACSumSqr[i,j] / ACCount[i,j]
end;
temp4 := SSAC;
SSAC := SSAC - temp - temp2 + constant;
MSAC := SSAC / dfAC;
// get B within A x C interaction
SSBwAC := 0.0;
for i := 0 to NoALevels-1 do
begin
for j := 0 to NoBLevels-1 do
begin
for k := 0 to NoCLevels-1 do
begin
if CellCount[j,i,k] > 0 then SSBwAC := SSBwAC +
(SumSqr[j,i,k] / CellCount[j,i,k]);
end;
end;
end;
SSBwAC := SSBwAC - temp3 - temp4 + temp;
MSBwAC := SSBwAC / dfBwAC;
SSW := SSTot - SSA - SSB - SSAB - SSAC - SSBwAC;
MSW := SSW / dfwcell;
end;
procedure TABCNestedForm.ShowResults;
var
lReport: TStrings;
F, PF : double;
begin
lReport := TStringList.Create;
try
lReport.Add('Nested ANOVA by Bill Miller');
lReport.Add('');
lReport.Add('File analyzed: %s', [OS3MainFrm.FileNameEdit.Text]);
lReport.Add('Factor A: %s', [FactorAEdit.Text]);
lReport.Add('Factor B: %s', [FactorBEdit.Text]);
lReport.Add('Factor C: %s', [FactorCEdit.Text]);
lReport.Add('');
lReport.Add('ANOVA TABLE');
lReport.Add('-------------------------------------------------------------');
lReport.Add('SOURCE D.F. SS MS F PROB. ');
lReport.Add('--------- ---- ---------- ---------- --------- ---------');
F := MSA / MSW;
PF := ProbF(F,dfA,dfwcell);
lReport.Add('A %4d %10.3f %10.3f %9.3f %9.3f', [dfA, SSA, MSA, F, PF]);
F := MSB / MSW;
PF := ProbF(F,dfBwA,dfwcell);
lReport.Add('B(A) %4d %10.3f %10.3f %9.3f %9.3f', [dfBwA, SSB, MSB, F, PF]);
F := MSC / MSW;
PF := ProbF(F,dfC,dfwcell);
lReport.Add('C %4d %10.3f %10.3f %9.3f %9.3f', [dfC, SSC, MSC, F, PF]);
F := MSAC / MSW;
PF := ProbF(F,dfAC,dfwcell);
lReport.Add('AxC %4d %10.3f %10.3f %9.3f %9.3f', [dfAC, SSAC, MSAC, F, PF]);
F := MSBwAC / MSW;
PF := ProbF(F,dfBwAC,dfwcell);
lReport.Add('B(A)xC %4d %10.3f %10.3f %9.3f %9.3f', [dfBwAC, SSBwAC, MSBwAC, F, PF]);
lReport.Add('w.cells %4d %10.3f %10.3f', [dfwcell, SSW, MSW]);
lReport.Add('Total %4d %10.3f', [dftotal, SSTot]);
lReport.Add('-------------------------------------------------------------');
FReportFrame.DisplayReport(lReport);
finally
lReport.Free;
end;
end;
procedure TABCNestedForm.ReleaseMemory;
begin
ABSDs := nil;
ABCount := nil;
// ABMeans := nil;
ABSumSqr := nil;
ABSS := nil;
ACSDs := nil;
// ACMeans := nil;
ACCount := nil;
ACSumSqr := nil;
ACSS := nil;
CSDs := nil;
BSDs := nil;
ASDs := nil;
CCount := nil;
BCount := nil;
ACount := nil;
// CMeans := nil;
// BMeans := nil;
// AMeans := nil;
CSumSqr := nil;
BSumSqr := nil;
ASumSqr := nil;
CSS := nil;
BSS := nil;
ASS := nil;
CellSDs := nil;
CellMeans := nil;
CellCount := nil;
SumSqr := nil;
SS := nil;
end;
procedure TABCNestedForm.Reset;
var
i: integer;
begin
inherited;
if FMeansReportFrame <> nil then
FMeansReportFrame.Clear;
if FChartCombobox <> nil then
FChartCombobox.Items.Clear;
VarList.Items.Clear;
for i := 1 to NoVariables do
VarList.Items.Add(OS3MainFrm.DataGrid.Cells[i,0]);
FactorAEdit.Clear;
FactorBEdit.Clear;
FactorCEdit.Clear;
DepEdit.Clear;
UpdateBtnStates;
end;
procedure TABCNestedForm.SelectPlot(Sender: TObject);
var
i, j, k, idx: Integer;
item: PChartDataItem;
begin
ChartStyles.Styles.Clear;
FSeries.Clear;
case FChartComboBox.ItemIndex of
0: begin // Plot means vs factor A
FSeries.ListSource.YCount := 1;
for i := 0 to NoALevels-1 do
FSeries.AddXY(MinA + i, AMeans[i], IntToStr(MinA + i));
FChartFrame.SetXTitle(FactorAEdit.Text + ' codes');
FChartFrame.SetTitle('Factor ' + FactorAEdit.Text);
end;
1: begin // Plot means vs factor B
FSeries.ListSource.YCount := 1;
for i := 0 to NoBLevels-1 do
FSeries.AddXY(MinB + i, BMeans[i], IntToStr(MinB + i));
FChartFrame.SetXTitle(FactorBEdit.Text + ' codes');
FChartFrame.SetTitle('Factor ' + FactorBEdit.Text);
end;
2: begin // Plot means vs factor C
FSeries.ListSource.YCount := 1;
for i := 0 to NoCLevels-1 do
FSeries.AddXY(MinC + i, CMeans[i], IntToStr(MinC + i));
FChartFrame.SetXTitle(FactorCEdit.Text + ' codes');
FChartFrame.SetTitle('Factor ' + FactorCEdit.Text);
end;
3: begin // Plot interaction AxB
FSeries.ListSource.YCount := NoALevels;
for j := 0 to NoBLevels-1 do
begin
idx := FSeries.AddXY(MinB + j, NaN, IntToStr(MinB + j));
item := FSeries.Source.Item[idx];
for i := 0 to NoALevels-1 do
item^.SetY(i, ABMeans[i, j]);
end;
FChartFrame.SetTitle(Format('Factor "%s" x Factor "%s"', [
FactorAEdit.Text, FactorBEdit.Text]));
FChartFrame.SetXTitle(FactorBEdit.Text + ' codes');
for i := 0 to NoALevels-1 do
with TChartStyle(ChartStyles.Styles.Add) do
begin
Brush.Color := DATA_COLORS[i mod Length(DATA_COLORS)];
UseBrush := true;
Text := Format('%s = %s', [FactorAEdit.Text, IntToStr(MinA+i)]);
end;
end;
4: begin // Plot interaction AxC
FSeries.ListSource.YCount := NoALevels;
for k := 0 to NoCLevels-1 do
begin
idx := FSeries.AddXY(MinC + k, NaN, IntToStr(MinC + k));
item := FSeries.Source.Item[idx];
for i := 0 to NoALevels-1 do
item^.SetY(i, ACMeans[i, k]);
end;
FChartFrame.SetTitle(Format('Factor "%s" x Factor "%s"', [
FactorAEdit.Text, FactorCEdit.Text]));
FChartFrame.SetXTitle(FactorCEdit.Text + ' codes');
for i := 0 to NoALevels-1 do
with TChartStyle(ChartStyles.Styles.Add) do
begin
Brush.Color := DATA_COLORS[i mod Length(DATA_COLORS)];
UseBrush := true;
Text := Format('%s = %s', [FactorAEdit.Text, IntToStr(MinA+i)]);
end;
end;
end;
if (FSeries is TBarSeries) then
begin
if ChartStyles.Styles.Count > 0 then
begin
TBarSeries(FSeries).Styles := ChartStyles;
FSeries.Legend.Multiplicity := lmStyle;
end else
FSeries.Legend.Multiplicity := lmSingle;
end;
FChartFrame.Chart.BottomAxis.Marks.Source := FSeries.Source;
FChartFrame.Chart.BottomAxis.Marks.Style := smsLabel;
FChartFrame.Chart.Legend.Visible := FSeries.Source.YCount > 1;
FChartFrame.UpdateBtnStates;
end;
procedure TABCNestedForm.TwoWayPlot;
begin
if not ShowPlotsChk.Checked then
begin
ChartPage.TabVisible := false;
exit;
end;
FChartFrame.Clear; // this destroys the series
FChartFrame.SetYTitle('Mean');
FSeries := FChartFrame.PlotXY(ptBars, nil, nil, nil, nil, '', DATA_Colors[0]);
with TBarSeries(FSeries) do
begin
Stacked := false;
{$IF LCL_FullVersion >= 2010000}
DepthBrightnessDelta := -30;
{$IFEND}
end;
if Plot3DChk.Checked then
FSeries.Depth := 20;
FChartCombobox.Parent.Left := 0;
PopulateChartCombobox;
SelectPlot(nil);
ChartPage.TabVisible := true;
end;
procedure TABCNestedForm.UpdateBtnStates;
begin
inherited;
if FMeansReportFrame <> nil then
FMeansReportFrame.UpdateBtnStates;
AInBtn.Enabled := (VarList.ItemIndex > -1) and (FactorAEdit.Text = '');
BInBtn.Enabled := (VarList.ItemIndex > -1) and (FactorBEdit.Text = '');
CInBtn.Enabled := (VarList.ItemIndex > -1) and (FactorCEdit.Text = '');
DepInBtn.Enabled := (VarList.ItemIndex > -1) and (DepEdit.Text = '');
AOutBtn.Enabled := (FactorAEdit.Text <> '');
BOutBtn.Enabled := (FactorBEdit.Text <> '');
COutBtn.Enabled := (FactorCEdit.Text <> '');
DepOutBtn.Enabled := (DepEdit.Text <> '');
end;
function TABCNestedForm.Validate(out AMsg: String;
out AControl: TWinControl): Boolean;
begin
Result := false;
if DepEdit.Text = '' then
begin
AMsg := 'Dependent variable not specified.';
AControl := VarList;
exit;
end;
if FactorAEdit.Text = '' then
begin
AMsg := 'Factor A variable not specified.';
AControl := VarList;
exit;
end;
if FactorBEdit.Text = '' then
begin
AMsg := 'Factor B variable not specified.';
AControl := VarList;
exit;
end;
if FactorCEdit.Text = '' then
begin
AMsg := 'Factor C variable not specified.';
AControl := VarList;
exit;
end;
Result := true;
end;
procedure TABCNestedForm.VarListDblClick(Sender: TObject);
var
index: Integer;
s: String;
begin
index := VarList.ItemIndex;
if index > -1 then begin
s := VarList.Items[index];
if DepEdit.Text = '' then
DepEdit.Text := s
else if FactorAEdit.Text = '' then
FactorAEdit.Text := s
else if FactorBEdit.Text = '' then
FactorBEdit.Text := s
else if FactorCEdit.Text = '' then
FactorCEdit.Text := s;
VarList.Items.Delete(index);
UpdateBtnStates;
end;
end;
procedure TABCNestedForm.VarListSelectionChange(Sender: TObject; User: boolean);
begin
UpdateBtnStates;
end;
end.