LazStats: Refactor two-way ANOVA in BlkAnovaUnit. Use TAChart.

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@7853 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz
2020-11-09 21:52:26 +00:00
parent 6ce0fc13bd
commit bc5987793a
2 changed files with 615 additions and 346 deletions

View File

@ -7,8 +7,8 @@ unit BlkANOVAUnit;
interface interface
uses uses
Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, Classes, SysUtils, FileUtil, Forms, Controls, Graphics, StdCtrls, ExtCtrls,
StdCtrls, Buttons, ExtCtrls, ComCtrls, ComCtrls, Buttons, Dialogs, LCLVersion,
TACustomSeries, TAStyles, TACustomSeries, TAStyles,
MainUnit, Globals, FunctionsLib, GraphLib, MainUnit, Globals, FunctionsLib, GraphLib,
ANOVATestsUnit, ReportFrameUnit, BasicStatsReportAndChartFormUnit; ANOVATestsUnit, ReportFrameUnit, BasicStatsReportAndChartFormUnit;
@ -102,7 +102,7 @@ type
SlcSums: DblDyneVec; // 3 way slice sums SlcSums: DblDyneVec; // 3 way slice sums
SlcCount: IntDyneVec; // 3 way slice counts SlcCount: IntDyneVec; // 3 way slice counts
NoGrpsA, NoGrpsB, NoGrpsC: integer; NoGrpsA, NoGrpsB, NoGrpsC: integer;
OrdMeansA, OrdMeansB, OrdMeansC: DblDyneVec; // reordered means for f1, f2, f3 // OrdMeansA, OrdMeansB, OrdMeansC: DblDyneVec; // reordered means for f1, f2, f3
AllAlpha, PostHocAlpha: double; // alphas for tests AllAlpha, PostHocAlpha: double; // alphas for tests
// wsum : array[1..20,1..20,1..20] of double; // sums for 3 way // wsum : array[1..20,1..20,1..20] of double; // sums for 3 way
// ncnt : array[1..20,1..20,1..20] of integer; // n in 3 way cells // ncnt : array[1..20,1..20,1..20] of integer; // n in 3 way cells
@ -120,10 +120,11 @@ type
procedure OneWayPostHoc; procedure OneWayPostHoc;
procedure OneWayPlot; procedure OneWayPlot;
function Calc2Way: Boolean; procedure Init2Way;
procedure TwoWayTable(AReport: TStrings); function Calc2Way(const DepValues, F1Values, F2Values: DblDyneVec): Boolean;
procedure TwoWayTable;
procedure TwoWayPlot; procedure TwoWayPlot;
procedure TwoWayContrasts(AReport: TStrings); procedure TwoWayContrasts;
function Calc3Way: Boolean; function Calc3Way: Boolean;
procedure ThreeWayTable(AReport: TStrings); procedure ThreeWayTable(AReport: TStrings);
@ -139,6 +140,8 @@ type
FSeries: TChartSeries; FSeries: TChartSeries;
FChartCombobox: TCombobox; FChartCombobox: TCombobox;
FStyles: TChartStyles; FStyles: TChartStyles;
procedure PopulateChartCombobox(ThreeWay: Boolean);
procedure SelectTwoWayPlot(Sender: TObject);
protected protected
procedure AdjustConstraints; override; procedure AdjustConstraints; override;
@ -161,7 +164,7 @@ implementation
uses uses
Math, Math,
TAChartUtils, TASeries, TAChartUtils, TACustomSource, TASeries, TALegend,
Utils, MathUnit, MatrixUnit, ChartFrameUnit, GridProcs; Utils, MathUnit, MatrixUnit, ChartFrameUnit, GridProcs;
{ TBlksAnovaForm } { TBlksAnovaForm }
@ -335,17 +338,17 @@ begin
1 : // Single factor anova 1 : // Single factor anova
begin begin
Init1Way; Init1Way;
if not Calc1Way(DepValues, F1Values) then if Calc1Way(DepValues, F1Values) then
exit; begin
OneWayTable; OneWayTable;
OneWayPostHoc; OneWayPostHoc;
OneWayPlot; OneWayPlot;
end;
exit;
end; end;
2 : // Rwo-way anova 2 : // Rwo-way anova
begin begin
{
SetLength(counts,Nf1cells,Nf2cells); // matrix for 2-way containing cell sizes SetLength(counts,Nf1cells,Nf2cells); // matrix for 2-way containing cell sizes
SetLength(sums,Nf1cells,Nf2cells); // matrix for 2-way containing cell sums SetLength(sums,Nf1cells,Nf2cells); // matrix for 2-way containing cell sums
SetLength(vars,Nf1cells,Nf2cells); // matrix for 2-way containing sums of squares SetLength(vars,Nf1cells,Nf2cells); // matrix for 2-way containing sums of squares
@ -353,17 +356,17 @@ begin
SetLength(ColSums,Nf2cells); // 2 way col sums SetLength(ColSums,Nf2cells); // 2 way col sums
SetLength(RowCount,Nf1cells); // 2 way row count SetLength(RowCount,Nf1cells); // 2 way row count
SetLength(ColCount,Nf2cells); // 2 way col count SetLength(ColCount,Nf2cells); // 2 way col count
SetLength(OrdMeansA,Nf1cells); // ordered means for factor 1 // SetLength(OrdMeansA,Nf1cells); // ordered means for factor 1
SetLength(OrdMeansB,Nf2cells); // ordered means for factor 2 // SetLength(OrdMeansB,Nf2cells); // ordered means for factor 2
}
if not Calc2Way then Init2Way;
exit; if Calc2Way(DepValues, F1Values, F2Values) then
begin
TwoWayTable(lReport); TwoWayTable;
TwoWayContrasts(lReport); TwoWayContrasts;
FReportFrame.DisplayReport(lReport);
TwoWayPlot; TwoWayPlot;
end; end;
end;
3 : // three way anova 3 : // three way anova
begin begin
@ -373,9 +376,9 @@ begin
SetLength(ColCount, Nf2cells); // 2 way col count SetLength(ColCount, Nf2cells); // 2 way col count
SetLength(SlcSums, Nf3cells); // 3 way slice sums SetLength(SlcSums, Nf3cells); // 3 way slice sums
SetLength(SlcCount, Nf3cells); // 3 way slice counts SetLength(SlcCount, Nf3cells); // 3 way slice counts
SetLength(OrdMeansA, Nf1cells); // ordered means for factor 1 // SetLength(OrdMeansA, Nf1cells); // ordered means for factor 1
SetLength(OrdMeansB, Nf2cells); // ordered means for factor 2 // SetLength(OrdMeansB, Nf2cells); // ordered means for factor 2
SetLength(OrdMeansC, Nf3cells); // ordered means for factor 3 // SetLength(OrdMeansC, Nf3cells); // ordered means for factor 3
SetLength(wsum, Nf1cells, Nf2cells, Nf3cells); SetLength(wsum, Nf1cells, Nf2cells, Nf3cells);
SetLength(wx2, Nf1cells, Nf2cells, Nf3cells); SetLength(wx2, Nf1cells, Nf2cells, Nf3cells);
SetLength(ncnt, Nf1cells, Nf2cells, Nf3cells); SetLength(ncnt, Nf1cells, Nf2cells, Nf3cells);
@ -865,44 +868,70 @@ begin
end; end;
*) *)
function TBlksAnovaForm.Calc2Way: Boolean;
procedure TBlksAnovaForm.Init2Way;
begin
RowSums := nil;
ColSums := nil;
RowCount := nil;
ColCount := nil;
counts := nil;
sums := nil;
vars := nil;
SetLength(RowSums, NF1Cells); // 2-way row sums
SetLength(ColSums, NF2Cells); // 2-way column sums
SetLength(RowCount, NF1Cells); // 2-way row counts
SetLength(ColCount, NF2Cells); // 2-way column counts
SetLength(counts, NF1Cells, NF2Cells); // matrix for 2-way containing cell sizes
SetLength(sums, NF1Cells, NF2Cells); // matrix for 2-way containing cell sums
SetLength(vars, NF1Cells, NF2Cells); // matrix for 2-way containing sums of squares
end;
function TBlksAnovaForm.Calc2Way(const DepValues, F1Values, F2Values: DblDyneVec): Boolean;
var var
i, j : integer; i, j: integer;
grpA, grpB : integer; grpA, grpB: integer;
Constant, RowsTotCnt, ColsTotCnt, SSCells : double; constant, rowsTotCnt, colsTotCnt, SSCells: double;
X, X2: Double; X, Xsq: Double;
begin begin
// initialize matrix values // initialize matrix values
NoGrpsA := maxf1 - minf1 + 1; NoGrpsA := MaxF1 - MinF1 + 1;
NoGrpsB := maxf2 - minf2 + 1; NoGrpsB := MaxF2 - MinF2 + 1;
for i := 0 to NoGrpsA-1 do
begin
RowSums[i] := 0.0;
RowCount[i] := 0;
for j := 0 to NoGrpsB-1 do
begin
counts[i, j] := 0;
sums[i, j] := 0.0;
vars[i, j] := 0.0;
end;
end;
for i := 0 to NoGrpsB-1 do {
begin RowSums := Default(DblDyneVec);
ColCount[i] := 0; ColSums := Default(DblDyneVec);
ColSums[i] := 0.0; RowCount := Default(IntDyneVec);
end; ColCount := Default(IntDyneVec);
Counts := Default(IntDyneMat);
Sums := Default(DblDyneMat);
Vars := Default(DblDyneMat);
}
// Get working totals
N := 0; N := 0;
MeanDep := 0.0; MeanDep := 0.0;
SSDep := 0.0; SSDep := 0.0;
SSCells := 0.0; SSCells := 0.0;
RowsTotCnt := 0.0; for i := 0 to High(DepValues) do
ColsTotCnt := 0.0;
// get working totals
for i := 1 to NoCases do
begin begin
grpA := round(F1Values[i]) - MinF1;
grpB := round(F2Values[i]) - MinF2;
X := DepValues[i];
Xsq := X * X;
Counts[grpA, grpB] := Counts[grpA, grpB] + 1;
Sums[grpA, grpB] := Sums[grpA, grpB] + X;
Vars[grpA, grpB] := Vars[grpA, grpB] + Xsq;
RowSums[grpA] := RowSums[grpA] + X;
ColSums[grpB] := ColSums[grpB] + X;
RowCount[grpA] := RowCount[grpA] + 1;
ColCount[grpB] := ColCount[grpB] + 1;
MeanDep := MeanDep + X;
SSDep := SSDep + Xsq;
N := N + 1;
{
if not GoodRecord(OS3MainFrm.DataGrid, i, ColNoSelected) then continue; if not GoodRecord(OS3MainFrm.DataGrid, i, ColNoSelected) then continue;
grpA := round(StrToFloat(Trim(OS3MainFrm.DataGrid.Cells[ColNoSelected[1], i]))); grpA := round(StrToFloat(Trim(OS3MainFrm.DataGrid.Cells[ColNoSelected[1], i])));
grpB := round(StrToFloat(Trim(OS3MainFrm.DataGrid.Cells[ColNoSelected[2], i]))); grpB := round(StrToFloat(Trim(OS3MainFrm.DataGrid.Cells[ColNoSelected[2], i])));
@ -910,6 +939,7 @@ begin
X2 := X*X; X2 := X*X;
grpA := grpA - minf1 + 1; grpA := grpA - minf1 + 1;
grpB := grpB - minf2 + 1; grpB := grpB - minf2 + 1;
counts[grpA-1,grpB-1] := counts[grpA-1,grpB-1] + 1; counts[grpA-1,grpB-1] := counts[grpA-1,grpB-1] + 1;
sums[grpA-1,grpB-1] := sums[grpA-1,grpB-1] + X; sums[grpA-1,grpB-1] := sums[grpA-1,grpB-1] + X;
vars[grpA-1,grpB-1] := vars[grpA-1,grpB-1] + X2; vars[grpA-1,grpB-1] := vars[grpA-1,grpB-1] + X2;
@ -920,34 +950,42 @@ begin
MeanDep := MeanDep + X; MeanDep := MeanDep + X;
SSDep := SSDep + X2; SSDep := SSDep + X2;
N := N + 1; N := N + 1;
}
end; end;
// Calculate results // Calculate results
SSF1 := 0;
RowsTotCnt := 0;
for i := 0 to NoGrpsA-1 do for i := 0 to NoGrpsA-1 do
begin begin
SSF1 := SSF1 + ((RowSums[i] * RowSums[i]) / RowCount[i]); SSF1 := SSF1 + sqr(RowSums[i]) / RowCount[i];
RowsTotCnt := RowsTotCnt + RowCount[i]; RowsTotCnt := RowsTotCnt + RowCount[i];
end; end;
SSF2 := 0;
ColsTotCnt := 0;
for j := 0 to NoGrpsB-1 do for j := 0 to NoGrpsB-1 do
begin begin
SSF2 := SSF2 + ((ColSums[j] * ColSums[j]) / ColCount[j]); SSF2 := SSF2 + sqr(ColSums[j]) / ColCount[j];
ColsTotCnt := ColsTotCnt + ColCount[j]; ColsTotCnt := ColsTotCnt + ColCount[j];
end; end;
SSCells := 0;
for i := 0 to NoGrpsA-1 do for i := 0 to NoGrpsA-1 do
begin
for j := 0 to NoGrpsB-1 do for j := 0 to NoGrpsB-1 do
if counts[i,j] > 0 then if Counts[i, j] > 0 then
SSCells := SSCells + ((sums[i,j] * sums[i,j]) / counts[i,j]); SSCells := SSCells + sqr(sums[i, j]) / Counts[i, j];
end;
if N > 0 then Constant := (MeanDep * MeanDep) / N else Constant := 0.0; if N > 0 then
SSF1 := SSF1 - Constant; constant := sqr(MeanDep) / N
SSF2 := SSF2 - Constant; else
SSF1F2 := SSCells - SSF1 - SSF2 - Constant; constant := 0.0;
SSF1 := SSF1 - constant;
SSF2 := SSF2 - constant;
SSF1F2 := SSCells - SSF1 - SSF2 - constant;
SSErr := SSDep - SSCells; SSErr := SSDep - SSCells;
SSDep := SSDep - Constant; SSDep := SSDep - constant; // Must be after SSErr!
if (SSF1F2 < 0) or (SSF1 < 0) or (SSF2 < 0) then if (SSF1F2 < 0) or (SSF1 < 0) or (SSF2 < 0) then
begin begin
@ -961,15 +999,18 @@ begin
DFF2 := NoGrpsB - 1; DFF2 := NoGrpsB - 1;
DFF1F2 := DFF1 * DFF2; DFF1F2 := DFF1 * DFF2;
DFErr := DFTot - DFF1 - DFF2 - DFF1F2; DFErr := DFTot - DFF1 - DFF2 - DFF1F2;
MSF1 := SSF1 / DFF1; MSF1 := SSF1 / DFF1;
MSF2 := SSF2 / DFF2; MSF2 := SSF2 / DFF2;
MSF1F2 := SSF1F2 / DFF1F2; MSF1F2 := SSF1F2 / DFF1F2;
MSErr := SSErr / DFErr; MSErr := SSErr / DFErr;
MSDep := SSDep / DFTot; MSDep := SSDep / DFTot;
OmegaF1 := (SSF1 - DFF1 * MSErr) / (SSDep + MSErr); OmegaF1 := (SSF1 - DFF1 * MSErr) / (SSDep + MSErr);
OmegaF2 := (SSF2 - DFF2 * MSErr) / (SSDep + MSErr); OmegaF2 := (SSF2 - DFF2 * MSErr) / (SSDep + MSErr);
OmegaF1F2 := (SSF1F2 - DFF1F2 * MSErr) / (SSDep + MSErr); OmegaF1F2 := (SSF1F2 - DFF1F2 * MSErr) / (SSDep + MSErr);
Omega := OmegaF1 + OmegaF2 + OmegaF1F2; Omega := OmegaF1 + OmegaF2 + OmegaF1F2;
MeanDep := MeanDep / N; MeanDep := MeanDep / N;
// F tests for fixed effects // F tests for fixed effects
@ -978,42 +1019,42 @@ begin
FF1 := abs(MSF1 / MSErr); FF1 := abs(MSF1 / MSErr);
FF2 := abs(MSF2 / MSErr); FF2 := abs(MSF2 / MSErr);
FF1F2 := abs(MSF1F2 / MSErr); FF1F2 := abs(MSF1F2 / MSErr);
ProbF1 := probf(FF1,DFF1,DFErr); ProbF1 := ProbF(FF1, DFF1, DFErr);
ProbF2 := probf(FF2,DFF2,DFErr); ProbF2 := ProbF(FF2, DFF2, DFErr);
ProbF1F2 := probf(FF1F2,DFF1F2,DFErr); ProbF1F2 := ProbF(FF1F2, DFF1F2, DFErr);
end; end
else
// F tests if both factors are random // F tests if both factors are random
if (Fact1Combo.ItemIndex = 1) and (Fact2Combo.ItemIndex = 1) then if (Fact1Combo.ItemIndex = 1) and (Fact2Combo.ItemIndex = 1) then
begin begin
FF1 := abs(MSF1 / MSF1F2); FF1 := abs(MSF1 / MSF1F2);
FF2 := abs(MSF2 / MSF1F2); FF2 := abs(MSF2 / MSF1F2);
FF1F2 := abs(MSF1F2 / MSErr); FF1F2 := abs(MSF1F2 / MSErr);
ProbF1 := probf(FF1,DFF1,DFF1F2); ProbF1 := ProbF(FF1, DFF1, DFF1F2);
ProbF2 := probf(FF2,DFF2,DFF1F2); ProbF2 := ProbF(FF2, DFF2, DFF1F2);
ProbF3 := probf(FF1F2,DFF1F2,DFErr); ProbF3 := ProbF(FF1F2, DFF1F2, DFErr);
end; end
else
// F test if factor A is random // F test if factor A is random and factor B is fixed
if (Fact1Combo.ItemIndex = 1) and (Fact2Combo.ItemIndex = 0) then if (Fact1Combo.ItemIndex = 1) and (Fact2Combo.ItemIndex = 0) then
begin begin
FF1 := abs(MSF1 / MSErr); FF1 := abs(MSF1 / MSErr);
FF2 := abs(MSF2 / MSF1F2); FF2 := abs(MSF2 / MSF1F2);
FF1F2 := abs(MSF1F2 / MSErr); FF1F2 := abs(MSF1F2 / MSErr);
ProbF1 := probf(FF1,DFF1,DFErr); ProbF1 := ProbF(FF1, DFF1, DFErr);
ProbF2 := probf(FF2,DFF2,DFF1F2); ProbF2 := ProbF(FF2, DFF2, DFF1F2);
ProbF3 := probf(FF1F2,DFF1F2,DFErr); ProbF3 := ProbF(FF1F2, DFF1F2, DFErr);
end; end
else
// F test if factor b is random // F test if factor A is fixed and factor B is random
if (Fact1Combo.ItemIndex = 0) and (Fact2Combo.ItemIndex = 1) then if (Fact1Combo.ItemIndex = 0) and (Fact2Combo.ItemIndex = 1) then
begin begin
FF1 := abs(MSF1 / MSF1F2); FF1 := abs(MSF1 / MSF1F2);
FF2 := abs(MSF2 / MSErr); FF2 := abs(MSF2 / MSErr);
FF1F2 := abs(MSF1F2 / MSErr); FF1F2 := abs(MSF1F2 / MSErr);
ProbF1 := probf(FF1,DFF1,DFF1F2); ProbF1 := ProbF(FF1, DFF1, DFF1F2);
ProbF2 := probf(FF2,DFF2,DFErr); ProbF2 := ProbF(FF2, DFF2, DFErr);
ProbF3 := probf(FF1F2,DFF1F2,DFErr); ProbF3 := ProbF(FF1F2, DFF1F2, DFErr);
end; end;
if (ProbF1 > 1.0) then ProbF1 := 1.0; if (ProbF1 > 1.0) then ProbF1 := 1.0;
@ -1029,62 +1070,60 @@ begin
Result := true; Result := true;
end; end;
procedure TBlksAnovaForm.TwoWayTable(AReport: TStrings); procedure TBlksAnovaForm.TwoWayTable;
const
FIXED_RANDOM: array[0..1] of string = ('fixed', 'random');
var var
lReport: TStrings;
groupsize: integer; groupsize: integer;
MinVar, MaxVar, sumvars, sumDFrecip: double; MinVar, MaxVar, sumvars, sumDFrecip: double;
i, j: integer; i, j: integer;
XBar, V, S, RowSS, ColSS: double; XBar, V, S, RowSS, ColSS: double;
sumfreqlogvar, c, bartlett, cochran, hartley, chiprob: double; sumfreqlogvar, c, bartlett, cochran, hartley, chiprob: double;
begin begin
AReport.Add('Two Way Analysis of Variance'); lReport := TStringList.Create;
AReport.Add(''); try
AReport.Add('Variable analyzed: %s', [DepVarEdit.Text]); lReport.Add('TWO-WAY ANALYSIS OF VARIANCE');
AReport.Add(''); lReport.Add('');
lReport.Add('Variable analyzed: %s', [DepVarEdit.Text]);
outline := format('Factor A (rows) variable: %s',[Factor1Edit.Text]); lReport.Add('Factor A (rows) variable: %s (%s levels)',[
if Fact1Combo.ItemIndex = 0 then Factor1Edit.Text, FIXED_RANDOM[Fact1Combo.ItemIndex]
outline := outline + ' (Fixed Levels)' ]);
else lReport.Add('Factor B (columns) variable: %s (%s levels)', [
outline := outline + ' (Random Levels)'; Factor2Edit.Text, FIXED_RANDOM[Fact2Combo.ItemIndex]
AReport.Add(outline); ]);
lReport.Add('');
outline := format('Factor B (columns) variable: %s',[Factor2Edit.Text]); lReport.Add('SOURCE D.F. SS MS F PROB.> F Omega Squared');
if Fact2Combo.ItemIndex = 0 then lReport.Add('');
outline := outline + ' (Fixed Levels)' lReport.Add('Among Rows %4.0f %8.3f %8.3f %8.3f %6.3f %6.3f', [DFF1, SSF1, MSF1, FF1, ProbF1, OmegaF1]);
else lReport.Add('Among Columns %4.0f %8.3f %8.3f %8.3f %6.3f %6.3f', [DFF2, SSF2, MSF2, FF2, ProbF2, OmegaF2]);
outline := outline + ' (Random Levels)'; lReport.Add('Interaction %4.0f %8.3f %8.3f %8.3f %6.3f %6.3f', [DFF1F2, SSF1F2, MSF1F2, FF1F2, ProbF1F2, OmegaF1F2]);
AReport.Add(outline); lReport.Add('Within Groups %4.0f %8.3f %8.3f', [DFErr, SSErr, MSErr]);
AReport.Add(''); lReport.Add('Total %4.0f %8.3f %8.3f', [DFTot, SSDep, MSDep]);
lReport.Add('');
AReport.Add('SOURCE D.F. SS MS F PROB.> F Omega Squared'); lReport.Add('Omega squared for combined effects = %8.3f', [Omega]);
AReport.Add(''); lReport.Add('');
AReport.Add('Among Rows %4.0f %8.3f %8.3f %8.3f %6.3f %6.3f', [DFF1, SSF1, MSF1, FF1, ProbF1, OmegaF1]);
AReport.Add('Among Columns %4.0f %8.3f %8.3f %8.3f %6.3f %6.3f', [DFF2, SSF2, MSF2, FF2, ProbF2, OmegaF2]);
AReport.Add('Interaction %4.0f %8.3f %8.3f %8.3f %6.3f %6.3f', [DFF1F2, SSF1F2, MSF1F2, FF1F2, ProbF1F2, OmegaF1F2]);
AReport.Add('Within Groups %4.0f %8.3f %8.3f', [DFErr, SSErr, MSErr]);
AReport.Add('Total %4.0f %8.3f %8.3f', [DFTot, SSDep, MSDep]);
AReport.Add('');
AReport.Add('Omega squared for combined effects = %8.3f', [Omega]);
AReport.Add('');
if (Fact1Combo.ItemIndex = 0) and (Fact2Combo.ItemIndex = 0) then if (Fact1Combo.ItemIndex = 0) and (Fact2Combo.ItemIndex = 0) then
AReport.Add('Note: Denominator of F ratio is MSErr'); lReport.Add('Note: Denominator of F ratio is MSErr');
if (Fact1Combo.ItemIndex = 1) and (Fact2Combo.ItemIndex = 1) then if (Fact1Combo.ItemIndex = 1) and (Fact2Combo.ItemIndex = 1) then
AReport.Add('Note: Denominator of F ratio is MSAxB'); lReport.Add('Note: Denominator of F ratio is MSAxB');
if (Fact1Combo.ItemIndex = 0) and (Fact2Combo.ItemIndex = 1) then if (Fact1Combo.ItemIndex = 0) and (Fact2Combo.ItemIndex = 1) then
begin begin
AReport.Add('Note: Denominator of F ratio for A is MSAxB'); lReport.Add('Note: Denominator of F ratio for A is MSAxB');
AReport.Add('and denominator for B and AxB is MSErr'); lReport.Add(' and denominator for B and AxB is MSErr');
end; end;
if (Fact1Combo.ItemIndex = 1) and (Fact2Combo.ItemIndex = 0) then if (Fact1Combo.ItemIndex = 1) and (Fact2Combo.ItemIndex = 0) then
begin begin
AReport.Add('Note: Denominator of F ratio for B is MSAxB'); lReport.Add('Note: Denominator of F ratio for B is MSAxB');
AReport.Add('and denominator for A and AxB is MSErr'); lReport.Add('and denominator for A and AxB is MSErr');
end; end;
AReport.Add(''); lReport.Add('');
AReport.Add('Descriptive Statistics'); lReport.Add('');
AReport.Add(''); lReport.Add('DESCRIPTIVE STATISTICS');
AReport.Add('GROUP Row Col. N MEAN VARIANCE STD.DEV.'); lReport.Add('');
lReport.Add('GROUP Row Col. N MEAN VARIANCE STD.DEV.');
groupsize := counts[0, 0]; groupsize := counts[0, 0];
equal_grp := true; equal_grp := true;
MaxVar := 0.0; MaxVar := 0.0;
@ -1114,7 +1153,7 @@ begin
sumfreqlogvar := sumfreqlogvar + ((counts[i,j] - 1.0) * ln(V)); sumfreqlogvar := sumfreqlogvar + ((counts[i,j] - 1.0) * ln(V));
if counts[i,j] <> groupsize then equal_grp := false; if counts[i,j] <> groupsize then equal_grp := false;
end; end;
AReport.Add('Cell %3d %3d %3d %8.3f %8.3f %8.3f', [minf1+i, minf2+j, counts[i,j], XBar, V, S]); lReport.Add('Cell %3d %3d %3d %8.3f %8.3f %8.3f', [minf1+i, minf2+j, counts[i,j], XBar, V, S]);
end; end;
end; end;
@ -1122,31 +1161,31 @@ begin
for i := 0 to NoGrpsA-1 do for i := 0 to NoGrpsA-1 do
begin begin
XBar := RowSums[i] / RowCount[i]; XBar := RowSums[i] / RowCount[i];
OrdMeansA[i] := XBar; // OrdMeansA[i] := XBar;
RowSS := 0.0; RowSS := 0.0;
for j := 0 to NoGrpsB-1 do RowSS := RowSS + vars[i,j]; for j := 0 to NoGrpsB-1 do RowSS := RowSS + vars[i,j];
V := RowSS - (RowSums[i] * RowSums[i] / RowCount[i]); V := RowSS - (RowSums[i] * RowSums[i] / RowCount[i]);
V := V / (RowCount[i] - 1.0); V := V / (RowCount[i] - 1.0);
S := sqrt(V); S := sqrt(V);
AReport.Add('Row %3d %3d %8.3f %8.3f %8.3f', [minf1+i, RowCount[i], XBar, V, S]); lReport.Add('Row %3d %3d %8.3f %8.3f %8.3f', [minf1+i, RowCount[i], XBar, V, S]);
end; end;
//Display means, variances and standard deviations for columns //Display means, variances and standard deviations for columns
for j := 0 to NoGrpsB-1 do for j := 0 to NoGrpsB-1 do
begin begin
XBar := ColSums[j] / ColCount[j]; XBar := ColSums[j] / ColCount[j];
OrdMeansB[j] := XBar; // OrdMeansB[j] := XBar;
ColSS := 0.0; ColSS := 0.0;
for i := 0 to NoGrpsA-1 do ColSS := ColSS + vars[i,j]; for i := 0 to NoGrpsA-1 do ColSS := ColSS + vars[i,j];
if ColCount[j] > 0 then V := ColSS - (ColSums[j] * ColSums[j] / ColCount[j]); if ColCount[j] > 0 then V := ColSS - (ColSums[j] * ColSums[j] / ColCount[j]);
if ColCount[j] > 1 then V := V / (ColCount[j] - 1.0); if ColCount[j] > 1 then V := V / (ColCount[j] - 1.0);
if V > 0.0 then S := sqrt(V); if V > 0.0 then S := sqrt(V);
AReport.Add('Col %3d %3d %8.3f %8.3f %8.3f', [minf2+j, ColCount[j], XBar, V, S]); lReport.Add('Col %3d %3d %8.3f %8.3f %8.3f', [minf2+j, ColCount[j], XBar, V, S]);
end; end;
AReport.Add('TOTAL %3d %8.3f %8.3f %8.3f', [N, MeanDep, MSDep, sqrt(MSDep)]); lReport.Add('TOTAL %3d %8.3f %8.3f %8.3f', [N, MeanDep, MSDep, sqrt(MSDep)]);
AReport.Add(''); lReport.Add('');
AReport.Add(''); lReport.Add('');
c := 1.0 + (1.0 / (3.0 * NoGrpsA * NoGrpsB - 1.0)) * (sumDFrecip - (1.0 / DFErr)); c := 1.0 + (1.0 / (3.0 * NoGrpsA * NoGrpsB - 1.0)) * (sumDFrecip - (1.0 / DFErr));
bartlett := (2.303 / c) * ((DFErr * ln(MSErr)) - sumfreqlogvar); bartlett := (2.303 / c) * ((DFErr * ln(MSErr)) - sumfreqlogvar);
@ -1154,15 +1193,185 @@ begin
cochran := maxvar / sumvars; cochran := maxvar / sumvars;
hartley := maxvar / minvar; hartley := maxvar / minvar;
AReport.Add(DIVIDER); lReport.Add(DIVIDER);
AReport.Add('TESTS FOR HOMOGENEITY OF VARIANCE'); lReport.Add('TESTS FOR HOMOGENEITY OF VARIANCE');
AReport.Add(DIVIDER_SMALL); lReport.Add(DIVIDER_SMALL);
AReport.Add('Hartley Fmax test statistic: %.2f with deg.s freedom: %d and %d.', [hartley, NoGrpsA*NoGrpsB, groupsize-1]); lReport.Add('Hartley Fmax test statistic: %.2f with deg.s freedom: %d and %d.', [hartley, NoGrpsA*NoGrpsB, groupsize-1]);
AReport.Add('Cochran C statistic: %.2f with deg.s freedom: %d and %d.', [cochran, NoGrpsA*NoGrpsB, groupsize - 1]); lReport.Add('Cochran C statistic: %.2f with deg.s freedom: %d and %d.', [cochran, NoGrpsA*NoGrpsB, groupsize - 1]);
AReport.Add('Bartlett Chi-square statistic: %.2f with %d D.F.; prob. larger value %.3f', [bartlett, NoGrpsA*NoGrpsB - 1, chiprob]); lReport.Add('Bartlett Chi-square statistic: %.2f with %d D.F.; prob. larger value %.3f', [bartlett, NoGrpsA*NoGrpsB - 1, chiprob]);
AReport.Add(DIVIDER); lReport.Add(DIVIDER);
FReportFrame.DisplayReport(lReport);
finally
lReport.Free;
end;
end; end;
procedure TBlksAnovaForm.PopulateChartCombobox(ThreeWay: Boolean);
var
a, b, c: String;
i, idx: Integer;
begin
a := Factor1Edit.Text;
b := Factor2Edit.Text;
c := Factor3Edit.Text;
idx := FChartCombobox.ItemIndex;
FChartCombobox.Items.Clear;
FChartCombobox.Items.Add(a);
FChartCombobox.Items.Add(b);
if ThreeWay then
FChartCombobox.Items.Add(c);
{
if InteractChk.Checked then
begin
}
if ThreeWay then
begin
for i := 0 to NF3Cells-1 do
FChartCombobox.Items.Add(Format('%s * %s vs %s with %s=%d', [a, b, a, c, Round(MinF3) + i]));
for i := 0 to NF3Cells-1 do
FChartCombobox.Items.Add(Format('%s * %s vs %s with %s=%d', [a, b, b, c, Round(MinF3) + i]));
for i := 0 to NF2Cells-1 do
FChartCombobox.Items.Add(Format('%s * %s vs %s with %s=%d', [a, c, a, b, Round(MinF2) + i]));
for i := 0 to NF2Cells-1 do
FChartCombobox.Items.Add(Format('%s * %s vs %s with %s=%d', [a, c, c, b, Round(MinF2) + i]));
for i := 0 to NF1Cells-1 do
FChartCombobox.Items.Add(Format('%s * %s vs %s with %s=%d', [b, c, b, a, Round(MinF1) + i]));
for i := 0 to NF1Cells-1 do
FChartCombobox.Items.Add(Format('%s * %s vs %s with %s=%d', [b, c, c, a, Round(MinF1) + i]));
end else
begin
FChartCombobox.Items.Add(Format('%s * %s vs %s', [a, b, a]));
FChartCombobox.Items.Add(Format('%s * %s vs %s', [a, b, b]));
end;
{
end;
}
FChartComboBox.ItemIndex := EnsureRange(idx, 0, FChartComboBox.Items.Count-1);
end;
procedure TBlksAnovaForm.SelectTwoWayPlot(Sender: TObject);
var
i, j, idx: Integer;
item: PChartDataItem;
begin
FStyles.Styles.Clear;
FSeries.Clear;
case FChartCombobox.ItemIndex of
0: begin // Plot means vs factor A
FSeries.ListSource.YCount := 1;
for i := 0 to NF1Cells-1 do
FSeries.AddXY(minF1 + i, RowSums[i] / RowCount[i], IntToStr(MinF1 + i));
FChartFrame.SetXTitle(Factor1Edit.Text + ' codes');
FChartFrame.SetTitle(Factor1Edit.Text);
end;
1: begin // Plot means vs factor B
FSeries.ListSource.YCount := 1;
for j := 0 to NF2Cells-1 do
FSeries.AddXY(minF2 + j, ColSums[j] / ColCount[j], IntToStr(MinF2 + j));
FChartFrame.SetXTitle(Factor2Edit.Text + ' codes');
FChartFrame.SetTitle(Factor2Edit.Text);
end;
2: begin // Plot interaction A*B vs A
FSeries.ListSource.YCount := NF2Cells;
for i := 0 to NF1Cells-1 do
begin
idx := FSeries.AddXY(minF1 + i, NaN, IntToStr(minF1 + i));
item := FSeries.Source.Item[idx];
for j := 0 to NF2Cells-1 do
item^.SetY(j, sums[i, j] / counts[i, j]);
end;
FChartFrame.SetTitle(Format('Factor "%s" x Factor "%s"', [Factor1Edit.Text, Factor2Edit.Text]));
FChartFrame.SetXTitle(Factor1Edit.Text + ' codes');
for j := 0 to NF2cells-1 do
with TChartStyle(FStyles.Styles.Add) do
begin
Brush.Color := DATA_COLORS[j mod Length(DATA_COLORS)];
UseBrush := true;
Text := Format('%s %s', [Factor2Edit.Text, IntToStr(MinF2 + j)]);
end;
end;
3: begin // Plot means vs interaction A*B vs B
FSeries.ListSource.YCount := NF1Cells;
for j := 0 to NF2Cells-1 do
begin
idx := FSeries.AddXY(minF2 + j, NaN, IntToStr(minF2 + j));
item := FSeries.Source.Item[idx];
for i := 0 to NF1Cells-1 do
item^.SetY(i, sums[i, j] / counts[i, j]);
end;
FChartFrame.SetTitle(Format('Factor "%s" x Factor "5s"', [Factor1Edit.Text, Factor2Edit.Text]));
FChartFrame.SetXTitle(Factor2Edit.Text + ' codes');
for i := 0 to NF1Cells-1 do
with TChartStyle(FStyles.styles.Add) do
begin
Brush.Color := DATA_COLORS[i mod Length(DATA_COLORS)];
UseBrush := True;
Text := Format('%s %s', [Factor1Edit.Text, IntToStr(MinF1 + i)]);
end;
end;
end; // case
if (FSeries is TBarSeries) then
begin
if FStyles.Styles.Count > 0 then
begin
TBarSeries(FSeries).Styles := FStyles;
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 TBlksAnovaForm.TwoWayPlot;
begin
{
if not ShowPlotsChk.Checked then
begin
ChartPage.TabVisible := false;
exit;
end;
}
FChartFrame.Clear;
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;
{$ENDIF}
end;
{
if Plot3DChk.Checked then
FSeries.Depth := 20;
}
FChartCombobox.Parent.Visible := true;
PopulateChartCombobox(false);
FChartCombobox.OnChange := @SelectTwoWayPlot;
SelectTwoWayPlot(nil);
{
ChartPage.TabVisible := true;
}
end;
(*
procedure TBlksAnovaForm.TwoWayPlot; procedure TBlksAnovaForm.TwoWayPlot;
var var
i, j : integer; i, j : integer;
@ -1275,6 +1484,7 @@ begin
GraphFrm.Xpoints := nil; GraphFrm.Xpoints := nil;
GraphFrm.Ypoints := nil; GraphFrm.Ypoints := nil;
end; end;
*)
function TBlksAnovaForm.Calc3Way: Boolean; function TBlksAnovaForm.Calc3Way: Boolean;
var var
@ -1865,7 +2075,7 @@ begin
for i := 0 to NoGrpsA-1 do for i := 0 to NoGrpsA-1 do
begin begin
XBar := RowSums[i] / RowCount[i]; XBar := RowSums[i] / RowCount[i];
OrdMeansA[i] := XBar; // OrdMeansA[i] := XBar;
RowSS := 0.0; RowSS := 0.0;
for j := 0 to NoGrpsB-1 do for j := 0 to NoGrpsB-1 do
for k := 0 to NoGrpsC-1 do RowSS := RowSS + wx2[i,j,k]; for k := 0 to NoGrpsC-1 do RowSS := RowSS + wx2[i,j,k];
@ -1879,7 +2089,7 @@ begin
for j := 0 to NoGrpsB-1 do for j := 0 to NoGrpsB-1 do
begin begin
XBar := ColSums[j] / ColCount[j]; XBar := ColSums[j] / ColCount[j];
OrdMeansB[j] := XBar; // OrdMeansB[j] := XBar;
ColSS := 0.0; ColSS := 0.0;
for i := 0 to NoGrpsA-1 do for i := 0 to NoGrpsA-1 do
for k := 0 to NoGrpsC-1 do ColSS := ColSS + wx2[i,j,k]; for k := 0 to NoGrpsC-1 do ColSS := ColSS + wx2[i,j,k];
@ -1893,7 +2103,7 @@ begin
for k := 0 to NoGrpsC-1 do for k := 0 to NoGrpsC-1 do
begin begin
XBar := SlcSums[k] / SlcCount[k]; XBar := SlcSums[k] / SlcCount[k];
OrdMeansC[k] := XBar; // OrdMeansC[k] := XBar;
SlcSS := 0.0; SlcSS := 0.0;
for i := 0 to NoGrpsA-1 do for i := 0 to NoGrpsA-1 do
for j := 0 to NoGrpsB-1 do SlcSS := SlcSS + wx2[i,j,k]; for j := 0 to NoGrpsB-1 do SlcSS := SlcSS + wx2[i,j,k];
@ -2137,20 +2347,31 @@ begin
end; end;
procedure TBlksAnovaForm.TwoWayContrasts(AReport: TStrings); procedure TBlksAnovaForm.TwoWayContrasts;
var var
i, j : integer; lReport: TStrings;
value : double; i, j: integer;
variances : DblDyneVec = nil; value: double;
RowSS, ColSS : double; variances: DblDyneVec = nil;
RowSS, ColSS: double;
totalCells: Integer;
begin begin
SetLength(variances, totcells); if not (ScheffeChk.Checked or TukeyHSDChk.Checked or TukeyBChk.Checked or
TukeyKramerChk.Checked or NewmanKeulsChk.Checked or
BonferroniChk.Checked or OrthoContrastsChk.Checked) then
begin
PostHocPage.TabVisible := false;
exit;
end;
totalCells := NF1Cells + NF2Cells + NF3Cells;
SetLength(variances, totalCells);
lReport := TStringList.Create;
try
// Do row comparisons // Do row comparisons
if (NF1cells > 2) then if (NF1cells > 2) and (ProbF1 < allAlpha) and (Fact2Combo.ItemIndex = 0) then
if ProbF1 < allAlpha then
if Fact2Combo.ItemIndex = 0 then
begin begin
for i := 0 to NoGrpsA-1 do for i := 0 to NoGrpsA-1 do
begin begin
@ -2160,133 +2381,178 @@ begin
variances[i] := variances[i] / (RowCount[i] - 1.0); variances[i] := variances[i] / (RowCount[i] - 1.0);
end; end;
AReport.Add(''); lReport.Add('COMPARISONS AMONG ROWS');
AReport.Add('COMPARISONS AMONG ROWS');
// get smallest group size // Get smallest group size
value := 1e308; value := 1e308;
for i := 0 to NF1cells-1 do if RowCount[i] < value then value := RowCount[i]; for i := 0 to NF1Cells-1 do
if RowCount[i] < value then value := RowCount[i];
if ScheffeChk.Checked then if ScheffeChk.Checked then
ScheffeTest(MSErr, RowSums, RowCount, minf1, maxf1, N, posthocAlpha, AReport); ScheffeTest(MSErr, RowSums, RowCount, minf1, maxf1, N, posthocAlpha, lReport);
if TukeyHSDChk.Checked and equal_grp then if TukeyHSDChk.Checked and equal_grp then
Tukey(MSErr, DFErr, value, RowSums, RowCount, minf1, maxf1, posthocAlpha, AReport); Tukey(MSErr, DFErr, value, RowSums, RowCount, minf1, maxf1, posthocAlpha, lReport);
if TukeyBChk.Checked and equal_grp then if TukeyBChk.Checked and equal_grp then
TukeyBTest(MSErr, DFErr, RowSums, RowCount, minf1, maxf1, value, posthocAlpha, AReport); TukeyBTest(MSErr, DFErr, RowSums, RowCount, minf1, maxf1, value, posthocAlpha, lReport);
if TukeyKramerChk.Checked and equal_grp then if TukeyKramerChk.Checked and equal_grp then
Tukey_Kramer(MSErr, DFErr, value, RowSums, RowCount, minf1, maxf1, posthocAlpha, AReport); Tukey_Kramer(MSErr, DFErr, value, RowSums, RowCount, minf1, maxf1, posthocAlpha, lReport);
if NewmanKeulsChk.Checked and equal_grp then if NewmanKeulsChk.Checked and equal_grp then
Newman_Keuls(MSErr, DFErr, value, RowSums, RowCount, minf1, maxf1, posthocAlpha, AReport); Newman_Keuls(MSErr, DFErr, value, RowSums, RowCount, minf1, maxf1, posthocAlpha, lReport);
if BonferroniChk.Checked then if BonferroniChk.Checked then
Bonferroni(RowSums, RowCount, variances, minf1, maxf1, posthocAlpha, AReport); Bonferroni(RowSums, RowCount, variances, minf1, maxf1, posthocAlpha, lReport);
if OrthoContrastsChk.Checked then if OrthoContrastsChk.Checked then
Contrasts(MSErr, DFErr, RowSums, RowCount, minf1, maxf1, AllAlpha, posthocAlpha, AReport); Contrasts(MSErr, DFErr, RowSums, RowCount, minf1, maxf1, AllAlpha, posthocAlpha, lReport);
end; end;
// Do column comparisons // Do column comparisons
if (NF2cells > 2) and (ProbF2 < allAlpha) and (Fact2Combo.ItemIndex = 0) then if (NF2Cells > 2) and (ProbF2 < allAlpha) and (Fact2Combo.ItemIndex = 0) then
begin begin
for j := 0 to NoGrpsB-1 do for j := 0 to NoGrpsB-1 do
begin begin
ColSS := 0.0; ColSS := 0.0;
for i := 0 to NoGrpsA-1 do ColSS := ColSS + vars[i,j]; for i := 0 to NoGrpsA-1 do
ColSS := ColSS + vars[i,j];
variances[j] := ColSS - (ColSums[j] * ColSums[j] / ColCount[j]); variances[j] := ColSS - (ColSums[j] * ColSums[j] / ColCount[j]);
variances[j] := variances[j] / (ColCount[j] - 1.0); variances[j] := variances[j] / (ColCount[j] - 1.0);
end; end;
AReport.Add('');
AReport.Add('COMPARISONS AMONG COLUMNS'); if lReport.Count <> 0 then
value := 1e20; lReport.Add('');
lReport.Add('COMPARISONS AMONG COLUMNS');
value := 1e308;
for i := 0 to NF2cells-1 do for i := 0 to NF2cells-1 do
if ColCount[i] < value then value := ColCount[i]; if ColCount[i] < value then value := ColCount[i];
if ScheffeChk.Checked then if ScheffeChk.Checked then
ScheffeTest(MSErr, ColSums, ColCount, minf2, maxf2, N, posthocAlpha, AReport); ScheffeTest(MSErr, ColSums, ColCount, minf2, maxf2, N, posthocAlpha, lReport);
if TukeyHSDChk.Checked and equal_grp then if TukeyHSDChk.Checked and equal_grp then
Tukey(MSErr, DFErr, value, ColSums, ColCount, minf2, maxf2, posthocAlpha, AReport); Tukey(MSErr, DFErr, value, ColSums, ColCount, minf2, maxf2, posthocAlpha, lReport);
if TukeyBChk.Checked and equal_grp then if TukeyBChk.Checked and equal_grp then
TukeyBTest(MSErr, DFErr, ColSums, ColCount, minf2, maxf2, value, posthocAlpha, AReport); TukeyBTest(MSErr, DFErr, ColSums, ColCount, minf2, maxf2, value, posthocAlpha, lReport);
if TukeyKramerChk.Checked and equal_grp then if TukeyKramerChk.Checked and equal_grp then
Tukey_Kramer(MSErr, DFErr, value, ColSums, ColCount, minf2, maxf2, posthocAlpha, AReport); Tukey_Kramer(MSErr, DFErr, value, ColSums, ColCount, minf2, maxf2, posthocAlpha, lReport);
if NewmanKeulsChk.Checked and equal_grp then if NewmanKeulsChk.Checked and equal_grp then
Newman_Keuls(MSErr, DFErr, value, ColSums, ColCount, minf2, maxf2, posthocAlpha, AReport); Newman_Keuls(MSErr, DFErr, value, ColSums, ColCount, minf2, maxf2, posthocAlpha, lReport);
if BonferroniChk.Checked then if BonferroniChk.Checked then
Bonferroni(ColSums, ColCount, variances, minf2, maxf2, posthocAlpha, AReport); Bonferroni(ColSums, ColCount, variances, minf2, maxf2, posthocAlpha, lReport);
if OrthoContrastsChk.Checked then if OrthoContrastsChk.Checked then
Contrasts(MSErr, DFErr, ColSums, ColCount, minf2, maxf2, AllAlpha, postHocAlpha, AReport); Contrasts(MSErr, DFErr, ColSums, ColCount, minf2, maxf2, AllAlpha, postHocAlpha, lReport);
end; end;
// do simple effects for columns within each row // do simple effects for columns within each row
if (ProbF3 < allAlpha) and (Fact1Combo.ItemIndex = 0) and (Fact2Combo.ItemIndex = 0) then if (ProbF3 < allAlpha) and (Fact1Combo.ItemIndex = 0) and (Fact2Combo.ItemIndex = 0) then
begin begin
AReport.Add(''); if lReport.Count <> 0 then
AReport.Add('COMPARISONS AMONG COLUMNS WITHIN EACH ROW'); lReport.Add('');
for i := 0 to NF1cells-1 do lReport.Add('COMPARISONS AMONG COLUMNS WITHIN EACH ROW');
for i := 0 to NF1Cells-1 do
begin begin
AReport.Add(''); lReport.Add('');
AReport.Add('ROW %d COMPARISONS',[i+1]); lReport.Add('ROW %d COMPARISONS',[i+1]);
// move cell sums and counts to cellsums and cellcnts // move cell sums and counts to cellsums and cellcnts
for j := 0 to NF2cells-1 do for j := 0 to NF2Cells-1 do
begin begin
cellsums[j] := sums[i,j]; cellSums[j] := Sums[i,j];
cellcnts[j] := counts[i,j]; cellCnts[j] := Counts[i,j];
cellvars[j] := vars[i,j]; cellVars[j] := Vars[i,j];
end; end;
value := 1e308; value := 1e308;
for j := 0 to NF2cells-1 do for j := 0 to NF2cells-1 do
if cellcnts[j] < value then value := cellcnts[j]; if cellCnts[j] < value then value := cellCnts[j];
if ScheffeChk.Checked then if ScheffeChk.Checked then
ScheffeTest(MSErr, cellsums, cellcnts, minf2, maxf2, N, posthocAlpha, AReport); ScheffeTest(MSErr, cellSums, cellCnts, MinF2, MaxF2, N, posthocAlpha, lReport);
if TukeyHSDChk.Checked and equal_grp then if TukeyHSDChk.Checked and equal_grp then
Tukey(MSErr, DFErr, value, cellsums, cellcnts, minf2, maxf2, posthocAlpha, AReport); Tukey(MSErr, DFErr, value, cellSums, cellCnts, MinF2, MaxF2, posthocAlpha, lReport);
if TukeyBChk.Checked and equal_grp then if TukeyBChk.Checked and equal_grp then
TukeyBTest(MSErr, DFErr, cellsums, cellcnts, minf2, maxf2, value, posthocAlpha, AReport); TukeyBTest(MSErr, DFErr, cellSums, cellCnts, MinF2, MaxF2, value, posthocAlpha, lReport);
if TukeyKramerChk.Checked and equal_grp then if TukeyKramerChk.Checked and equal_grp then
Tukey_Kramer(MSErr, DFErr, value, cellsums, cellcnts, minf2, maxf2, posthocAlpha, AReport); Tukey_Kramer(MSErr, DFErr, value, cellSums, cellCnts, MinF2, MaxF2, posthocAlpha, lReport);
if NewmanKeulsChk.Checked and equal_grp then if NewmanKeulsChk.Checked and equal_grp then
Newman_Keuls(MSErr, DFErr, value, cellsums, cellcnts, minf2, maxf2, posthocAlpha, AReport); Newman_Keuls(MSErr, DFErr, value, cellSums, cellCnts, MinF2, MaxF2, posthocAlpha, lReport);
if BonferroniChk.Checked then if BonferroniChk.Checked then
Bonferroni(cellsums, cellcnts, cellvars, minf2, maxf2, posthocAlpha, AReport); Bonferroni(cellSums, cellCnts, cellVars, MinF2, MaxF2, posthocAlpha, lReport);
if OrthoContrastsChk.Checked then if OrthoContrastsChk.Checked then
Contrasts(MSErr, DFErr, cellsums, cellcnts, minf2, maxf2, allAlpha, PostHocAlpha, AReport); Contrasts(MSErr, DFErr, cellSums, cellCnts, MinF2, MaxF2, allAlpha, PostHocAlpha, lReport);
end; end;
end; end;
// do simple effects for rows within each column // do simple effects for rows within each column
if (ProbF3 < allAlpha) and (Fact1Combo.ItemIndex = 0) and (Fact2Combo.ItemIndex = 0) then if (ProbF3 < allAlpha) and (Fact1Combo.ItemIndex = 0) and (Fact2Combo.ItemIndex = 0) then
begin begin
AReport.Add(''); if lReport.Count > 0 then
AReport.Add('COMPARISONS AMONG ROWS WITHIN EACH COLUMN'); lReport.Add('');
for j := 0 to NF2cells-1 do lReport.Add('COMPARISONS AMONG ROWS WITHIN EACH COLUMN');
for j := 0 to NF2Cells-1 do
begin begin
AReport.Add(''); lReport.Add('');
AReport.Add('COLUMN %d COMPARISONS', [j+1]); lReport.Add('COLUMN %d COMPARISONS', [j+1]);
// move cell sums and counts to cellsums and cellcnts // move cell sums and counts to cellsums and cellcnts
for i := 0 to NF1cells-1 do for i := 0 to NF1Cells-1 do
begin begin
cellsums[i] := sums[i,j]; cellSums[i] := Sums[i,j];
cellcnts[i] := counts[i,j]; cellCnts[i] := Counts[i,j];
cellvars[i] := vars[i,j]; cellVars[i] := Vars[i,j];
end; end;
value := 1e308; value := 1e308;
for i := 0 to NF1cells-1 do for i := 0 to NF1Cells-1 do
if cellcnts[j] < value then value := cellcnts[j]; if cellCnts[j] < value then value := cellCnts[j];
if ScheffeChk.Checked then if ScheffeChk.Checked then
ScheffeTest(MSErr, cellsums, cellcnts, minf1, maxf1, N, posthocAlpha, AReport); ScheffeTest(MSErr, cellSums, cellCnts, MinF1, MaxF1, N, posthocAlpha, lReport);
if TukeyHSDChk.Checked and equal_grp then if TukeyHSDChk.Checked and equal_grp then
Tukey(MSErr, DFErr, value, cellsums, cellcnts, minf1, maxf1, posthocAlpha, AReport); Tukey(MSErr, DFErr, value, cellSums, cellCnts, MinF1, MaxF1, posthocAlpha, lReport);
if TukeyBChk.Checked and equal_grp then if TukeyBChk.Checked and equal_grp then
TukeyBTest(MSErr, DFErr, cellsums, cellcnts, minf1, maxf1, value, posthocAlpha, AReport); TukeyBTest(MSErr, DFErr, cellSums, cellCnts, MinF1, MaxF1, value, posthocAlpha, lReport);
if TukeyKramerChk.Checked and equal_grp then if TukeyKramerChk.Checked and equal_grp then
Tukey_Kramer(MSErr, DFErr, value, cellsums, cellcnts, minf1, maxf1, posthocAlpha, AReport); Tukey_Kramer(MSErr, DFErr, value, cellSums, cellCnts, MinF1, MaxF1, posthocAlpha, lReport);
if NewmanKeulsChk.Checked and equal_grp then if NewmanKeulsChk.Checked and equal_grp then
Newman_Keuls(MSErr, DFErr, value, cellsums, cellcnts, minf1, maxf1, posthocAlpha, AReport); Newman_Keuls(MSErr, DFErr, value, cellSums, cellCnts, MinF1, MaxF1, posthocAlpha, lReport);
if BonferroniChk.Checked then if BonferroniChk.Checked then
Bonferroni(cellsums, cellcnts, cellvars, minf1, maxf1, posthocAlpha, AReport); Bonferroni(cellSums, cellCnts, cellVars, MinF1, MaxF1, posthocAlpha, lReport);
if OrthoContrastsChk.Checked then if OrthoContrastsChk.Checked then
Contrasts(MSErr, DFErr, cellsums, cellcnts, minf1, maxf1, allAlpha, postHocAlpha, AReport); Contrasts(MSErr, DFErr, cellSums, cellCnts, MinF1, MaxF1, allAlpha, postHocAlpha, lReport);
end; end;
end; end;
variances := nil;
FPosthocReportFrame.DisplayReport(lReport);
finally
lReport.Free;
end;
PostHocPage.TabVisible := true;
end; end;
procedure TBlksAnovaForm.ThreeWayContrasts(AReport: TStrings); procedure TBlksAnovaForm.ThreeWayContrasts(AReport: TStrings);
var var
i, j, k: integer; i, j, k: integer;

View File

@ -438,9 +438,9 @@ begin
SetLength(ColSums, NF2Cells); // 2-way column sums SetLength(ColSums, NF2Cells); // 2-way column sums
SetLength(RowCount, NF1Cells); // 2-way row counts SetLength(RowCount, NF1Cells); // 2-way row counts
SetLength(ColCount, NF2Cells); // 2-way column counts SetLength(ColCount, NF2Cells); // 2-way column counts
SetLength(counts, Nf1cells, Nf2cells); // matrix for 2-way containing cell sizes SetLength(counts, NF1Cells, NF2Cells); // matrix for 2-way containing cell sizes
SetLength(sums, Nf1cells, Nf2cells); // matrix for 2-way containing cell sums SetLength(sums, NF1Cells, NF2Cells); // matrix for 2-way containing cell sums
SetLength(vars, Nf1cells, Nf2cells); // matrix for 2-way containing sums of squares SetLength(vars, NF1Cells, NF2Cells); // matrix for 2-way containing sums of squares
end; end;
@ -519,9 +519,9 @@ begin
else else
Constant := 0.0; Constant := 0.0;
SSDep := SSDep - Constant;
SSF1 := SSF1 - Constant; SSF1 := SSF1 - Constant;
SSF2 := SSF2 - Constant; SSF2 := SSF2 - Constant;
SSDep := SSDep - Constant;
SSErr := SSDep - (SSF1 + SSF2); SSErr := SSDep - (SSF1 + SSF2);
SSNonAdd := (SSNonAdd * SSNonAdd) / ((SSF1 * SSF2) / (NoGrpsA * NoGrpsB) ); SSNonAdd := (SSNonAdd * SSNonAdd) / ((SSF1 * SSF2) / (NoGrpsA * NoGrpsB) );
MSNonAdd := SSNonAdd; MSNonAdd := SSNonAdd;
@ -538,14 +538,17 @@ begin
DFF2 := NoGrpsB - 1; DFF2 := NoGrpsB - 1;
DFErr := DFF1 * DFF2; DFErr := DFF1 * DFF2;
DFBalance := DFErr - 1; DFBalance := DFErr - 1;
MSF1 := SSF1 / DFF1; MSF1 := SSF1 / DFF1;
MSF2 := SSF2 / DFF2; MSF2 := SSF2 / DFF2;
MSErr := SSErr / DFErr; MSErr := SSErr / DFErr;
MSDep := SSDep / DFTot; MSDep := SSDep / DFTot;
MSBalance := SSBalance / DFBalance; MSBalance := SSBalance / DFBalance;
OmegaF1 := (SSF1 - DFF1 * MSErr) / (SSDep + MSErr); OmegaF1 := (SSF1 - DFF1 * MSErr) / (SSDep + MSErr);
OmegaF2 := (SSF2 - DFF2 * MSErr) / (SSDep + MSErr); OmegaF2 := (SSF2 - DFF2 * MSErr) / (SSDep + MSErr);
Omega := OmegaF1 + OmegaF2; Omega := OmegaF1 + OmegaF2;
MeanDep := MeanDep / N; MeanDep := MeanDep / N;
// F tests for fixed effects // F tests for fixed effects