diff --git a/applications/lazstats/source/forms/analysis/comparisons/blkanovaunit.lfm b/applications/lazstats/source/forms/analysis/comparisons/blkanovaunit.lfm index 8e4703b5c..83a5fcb55 100644 --- a/applications/lazstats/source/forms/analysis/comparisons/blkanovaunit.lfm +++ b/applications/lazstats/source/forms/analysis/comparisons/blkanovaunit.lfm @@ -641,15 +641,16 @@ inherited BlksAnovaForm: TBlksAnovaForm Height = 537 Width = 485 ActivePage = PosthocPage + TabIndex = 2 inherited ReportPage: TTabSheet Caption = 'ANOVA Results' end - object PosthocPage: TTabSheet[1] + inherited ChartPage: TTabSheet + Caption = 'Plots' + end + object PosthocPage: TTabSheet[2] Caption = 'Post-Hoc' TabVisible = False end - inherited ChartPage: TTabSheet[2] - Caption = 'Plots' - end end end diff --git a/applications/lazstats/source/forms/analysis/comparisons/blkanovaunit.pas b/applications/lazstats/source/forms/analysis/comparisons/blkanovaunit.pas index f4afe5852..f417b7719 100644 --- a/applications/lazstats/source/forms/analysis/comparisons/blkanovaunit.pas +++ b/applications/lazstats/source/forms/analysis/comparisons/blkanovaunit.pas @@ -73,9 +73,8 @@ type procedure VarListSelectionChange(Sender: TObject; {%H-}User: boolean); private { private declarations } - NoSelected, N: integer; + N: integer; ColNoSelected: IntDyneVec; - outline, cellstring: string; SSDep, SSErr, SSF1, SSF2, SSF3, SSF1F2, SSF1F3, SSF2F3, SSF1F2F3: double; MSDep, MSErr, MSF1, MSF2, MSF3, MSF1F2, MSF1F3, MSF2F3, MSF1F2F3: double; DFTot, DFErr, DFF1, DFF2, DFF3, DFF1F2, DFF1F3, DFF2F3, DFF1F2F3: double; @@ -87,11 +86,11 @@ type //DepVarCol, F1Col, F2Col, F3Col, Nf1cells, Nf2cells, Nf3cells: integer; MeanDep, MeanF1, MeanF2, MeanF3: double; - minf1, maxf1, minf2, maxf2, minf3, maxf3, nofactors, totcells: integer; + minf1, maxf1, minf2, maxf2, minf3, maxf3, nofactors: integer; + equal_grp: boolean; // check for equal groups for post-hoc tests cellcnts: IntDyneVec; // array of cell counts cellvars: DblDyneVec; // arrray of cell sums of squares then variances cellsums: DblDyneVec; // array of cell sums then means - equal_grp: boolean; // check for equal groups for post-hoc tests counts: IntDyneMat; // matrix for 2-way containing cell sizes sums: DblDyneMat; // matrix for 2-way containing cell sums vars: DblDyneMat; // matrix for 2-way containing sums of squares @@ -101,15 +100,15 @@ type ColCount: IntDyneVec; // 2 way col count SlcSums: DblDyneVec; // 3 way slice sums SlcCount: IntDyneVec; // 3 way slice counts + WSum, WX2: DblDyneCube; + NCnt: IntDyneCube; NoGrpsA, NoGrpsB, NoGrpsC: integer; // OrdMeansA, OrdMeansB, OrdMeansC: DblDyneVec; // reordered means for f1, f2, f3 AllAlpha, PostHocAlpha: double; // alphas for tests // 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 // wx2 : array[1..20,1..20,1..20] of double; // sums of squares for 3 way cells - wsum, wx2: DblDyneCube; - ncnt: IntDyneCube; - OKterms: array[1..14] of integer; + OKterms: array[1..14] of Boolean; procedure Init; function GetLevels(out DepValues, F1Values, F2Values, F3Values: DblDyneVec): Boolean; @@ -126,10 +125,11 @@ type procedure TwoWayPlot; procedure TwoWayContrasts; - function Calc3Way: Boolean; - procedure ThreeWayTable(AReport: TStrings); + procedure Init3Way; + function Calc3Way(const DepValues, F1Values, F2Values, F3Values: DblDyneVec): Boolean; + procedure ThreeWayTable; procedure ThreeWayPlot; - procedure ThreeWayContrasts(AReport: TStrings); + procedure ThreeWayContrasts; procedure BrownForsytheOneWay(AReport: TStrings); procedure WelchOneWay(AReport: TStrings); @@ -140,8 +140,10 @@ type FSeries: TChartSeries; FChartCombobox: TCombobox; FStyles: TChartStyles; + procedure GetDataIndices(out ix, iy, iz: Integer); procedure PopulateChartCombobox(ThreeWay: Boolean); procedure SelectTwoWayPlot(Sender: TObject); + procedure SelectThreeWayPlot(Sender: TObject); protected procedure AdjustConstraints; override; @@ -167,6 +169,10 @@ uses TAChartUtils, TACustomSource, TASeries, TALegend, Utils, MathUnit, MatrixUnit, ChartFrameUnit, GridProcs; +const + FIXED_RANDOM: array[0..1] of string = ('fixed', 'random'); + + { TBlksAnovaForm } constructor TBlksAnovaForm.Create(AOwner: TComponent); @@ -277,36 +283,8 @@ end; procedure TBlksAnovaForm.Compute; var - i: integer; - lReport: TStrings; - DepVarCol, F1Col, F2Col, F3Col: Integer; DepValues, F1Values, F2Values, F3Values: DblDyneVec; begin - // initialize values - SSDep := 0.0; - SSF1 := 0.0; - SSF2 := 0.0; - SSF3 := 0.0; - SSF1F2 := 0.0; - SSF1F3 := 0.0; - SSF2F3 := 0.0; - SSF1F2F3 := 0.0; - MeanDep := 0.0; - MeanF1 := 0.0; - MeanF2 := 0.0; - MeanF3 := 0.0; - Nf1cells := 0; - Nf2cells := 0; - Nf3cells := 0; - N := 0; - NoSelected := 0; - minf1 := 0; - maxf1 := 0; - minf2 := 0; - maxf2 := 0; - minf3 := 0; - maxf3 := 0; - // Get column numbers of dependent variable and factors Init; allAlpha := StrToFloat(OverallAlphaEdit.Text); @@ -317,85 +295,42 @@ begin if not GetLevels(DepValues, F1Values, F2Values, F3Values) then exit; - lReport := TStringList.Create; - try - - // Allocate space - SetLength(cellcnts, totcells); // array of cell counts - SetLength(cellvars, totcells); // arrray of cell sums of squares then variances - SetLength(cellsums, totcells); // array of cell sums then means - - // Initialize array values - for i := 0 to totcells-1 do - begin - cellsums[i] := 0.0; - cellvars[i] := 0.0; - cellcnts[i] := 0; - end; - - // do analysis - case nofactors of - 1 : // Single factor anova + // Do analysis + case nofactors of + 1 : // Single factor anova + begin + Init1Way; + if Calc1Way(DepValues, F1Values) then begin - Init1Way; - if Calc1Way(DepValues, F1Values) then - begin - OneWayTable; - OneWayPostHoc; - OneWayPlot; - end; - end; + OneWayTable; + OneWayPostHoc; + OneWayPlot; + end; + end; - 2 : // Rwo-way anova + 2 : // Rwo-way anova + begin + Init2Way; + if Calc2Way(DepValues, F1Values, F2Values) then begin - { - 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 - SetLength(RowSums,Nf1cells); // 2 way row sums - SetLength(ColSums,Nf2cells); // 2 way col sums - SetLength(RowCount,Nf1cells); // 2 way row count - SetLength(ColCount,Nf2cells); // 2 way col count -// SetLength(OrdMeansA,Nf1cells); // ordered means for factor 1 -// SetLength(OrdMeansB,Nf2cells); // ordered means for factor 2 - } - Init2Way; - if Calc2Way(DepValues, F1Values, F2Values) then - begin - TwoWayTable; - TwoWayContrasts; - TwoWayPlot; - end; - end; - - 3 : // three way anova - begin - SetLength(RowSums, Nf1cells); // 2 way row sums - SetLength(ColSums, Nf2cells); // 2 way col sums - SetLength(RowCount, Nf1cells); // 2 way row count - SetLength(ColCount, Nf2cells); // 2 way col count - SetLength(SlcSums, Nf3cells); // 3 way slice sums - SetLength(SlcCount, Nf3cells); // 3 way slice counts -// SetLength(OrdMeansA, Nf1cells); // ordered means for factor 1 -// SetLength(OrdMeansB, Nf2cells); // ordered means for factor 2 -// SetLength(OrdMeansC, Nf3cells); // ordered means for factor 3 - SetLength(wsum, Nf1cells, Nf2cells, Nf3cells); - SetLength(wx2, Nf1cells, Nf2cells, Nf3cells); - SetLength(ncnt, Nf1cells, Nf2cells, Nf3cells); - - if not Calc3Way then - exit; - - ThreeWayTable(lReport); - ThreeWayContrasts(lReport); - FReportFrame.DisplayReport(lReport); - ThreeWayPlot; + TwoWayTable; + TwoWayContrasts; + TwoWayPlot; end; end; - finally - lReport.Free; + 3 : // three way anova + begin + Init3Way; + if Calc3Way(DepValues, F1Values, F2Values, F3Values) then + begin + ThreeWayTable; + ThreeWayContrasts; + ThreeWayPlot; + end; + end; end; + end; procedure TBlksAnovaForm.DepOutClick(Sender: TObject); @@ -408,11 +343,13 @@ begin UpdateBtnStates; end; + procedure TBlksAnovaForm.VarChange(Sender: TObject); begin UpdateBtnStates; end; + procedure TBlksAnovaForm.Fact1OutClick(Sender: TObject); begin if Factor1Edit.Text <> '' then @@ -423,6 +360,7 @@ begin end; end; + procedure TBlksAnovaForm.Fact2InClick(Sender: TObject); var index: integer; @@ -436,6 +374,7 @@ begin end; end; + procedure TBlksAnovaForm.Fact2OutClick(Sender: TObject); begin if Factor2Edit.Text <> '' then @@ -446,6 +385,7 @@ begin end; end; + procedure TBlksAnovaForm.Fact3InClick(Sender: TObject); var index: integer; @@ -459,6 +399,7 @@ begin end; end; + procedure TBlksAnovaForm.Fact3OutClick(Sender: TObject); begin if Factor3Edit.Text <> '' then @@ -485,31 +426,6 @@ end; procedure TBlksAnovaForm.Init; begin - // initialize values - SSDep := 0.0; - SSF1 := 0.0; - SSF2 := 0.0; - SSF3 := 0.0; - SSF1F2 := 0.0; - SSF1F3 := 0.0; - SSF2F3 := 0.0; - SSF1F2F3 := 0.0; - MeanDep := 0.0; - MeanF1 := 0.0; - MeanF2 := 0.0; - MeanF3 := 0.0; - Nf1cells := 0; - Nf2cells := 0; - Nf3cells := 0; - N := 0; - NoSelected := 0; - minf1 := 0; - maxf1 := 0; - minf2 := 0; - maxf2 := 0; - minf3 := 0; - maxf3 := 0; - if Factor2Edit.Text = '' then NoFactors := 1 else if Factor3Edit.Text = '' then @@ -517,7 +433,7 @@ begin else NoFactors := 3; - // Get column numbers of dependent variable and factors + // Get column numbers of dependent variable and factors SetLength(ColNoSelected, NoFactors + 1); // because DepVar is at index 0 ColNoSelected[0] := GetVariableIndex(OS3MainFrm.DataGrid, DepVarEdit.Text); ColNoSelected[1] := GetVariableIndex(OS3MainFrm.DataGrid, Factor1Edit.Text); @@ -544,7 +460,7 @@ begin F2Values := nil; F3Values := nil; - // Extrace dependent variable values + // Extract dependent variable values DepValues := CollectVecValues(OS3MainFrm.DataGrid, ColNoSelected[0], ColNoSelected); // Extract factor 1 values @@ -582,7 +498,6 @@ begin end else NF3cells := 0; - totcells := Nf1cells + Nf2cells + Nf3cells; Result := true; end; @@ -595,7 +510,7 @@ begin SetLength(cellCnts, NF1Cells); SetLength(cellSums, NF1Cells); - SetLength(CellVars, NF1Cells); + SetLength(cellVars, NF1Cells); end; @@ -604,13 +519,7 @@ var i, j: integer; X, Xsq: Double; begin - // Initialize matrix values - { - cellCnts := Default(IntDyneVec); - cellSums := Default(DblDyneVec); - cellVars := Default(DblDyneVec); - } - // get working totals + // Get working totals N := 0; MeanDep := 0; SSDep := 0; @@ -673,18 +582,21 @@ begin lReport.Add('Dependent variable is: %s', [DepVarEdit.Text]); lReport.Add('Independent variable is: %s', [Factor1Edit.Text]); lReport.Add(''); - lReport.Add(DIVIDER_SMALL_AUTO); - lReport.Add('SOURCE D.F. SS MS F PROB.>F OMEGA SQR.'); - lReport.Add(DIVIDER_SMALL_AUTO); - lReport.Add('BETWEEN %4.0f%10.2f%10.2f%10.2f%10.2f%10.2f', [DFF1, SSF1, MSF1, F, ProbF1, Omega]); - lReport.Add('WITHIN %4.0f%10.2f%10.2f', [DFErr, SSErr, MSErr]); - lReport.Add('TOTAL %4.0f%10.2f', [DFTot, SSDep]); - lReport.Add(DIVIDER_SMALL_AUTO); + + lReport.Add('-----------------------------------------------------------------------------'); + lReport.Add('SOURCE D.F. SS MS F PROB.> F Omega Sqr.'); + lReport.Add('------------- ---- ---------- ---------- ---------- -------- ----------'); + lReport.Add('Between %4.0f %10.3f %10.3f %10.3f %8.3f %8.3f', [DFF1, SSF1, MSF1, FF1, ProbF1, OmegaF1]); + lReport.Add('Within %4.0f %10.3f %10.3f', [DFErr, SSErr, MSErr]); + lReport.Add('Total %4.0f %10.3f', [DFTot, SSDep]); + lReport.Add('-----------------------------------------------------------------------------'); + + lReport.Add(''); lReport.Add(''); lReport.Add('MEANS AND VARIABILITY OF THE DEPENDENT VARIABLE'); lReport.Add('FOR LEVELS OF THE INDEPENDENT VARIABLE'); - lReport.Add(''); - lReport.Add('GROUP MEAN VARIANCE STD.DEV. N'); + lReport.Add('---------------------------------------------------'); + lReport.Add('GROUP MEAN VARIANCE STD.DEV. N'); lReport.Add('----- --------- ---------- ---------- ---------'); // xxxx xxxxxxxxx xxxxxxxxxx xxxxxxxxxx xxxx @@ -716,22 +628,22 @@ begin if cellvars[i] < minVar then minVar := cellVars[i]; sumVar :=sumVar + cellVars[i]; sumDFRecip := sumDFRecip + 1.0 / (cellCnts[i] - 1); - sumFreqLogVar := sumFreqLogVar + (cellCnts[i] - 1) * Log10(cellVars[i]); + sumFreqLogVar := sumFreqLogVar + (cellCnts[i] - 1) * ln(cellVars[i]); // wp: was log10, but all the other s ahve ln() here end; if cellCnts[i] > 0 then - lReport.Add('%4d %9.2f %10.2f %10.2f %4d', [ + lReport.Add('%5d %9.2f %10.2f %10.2f %7d', [ i+1, cellSums[i] / cellCnts[i], cellVars[i], sqrt(cellVars[i]), cellCnts[i] ]); end; lReport.Add('---------------------------------------------------'); - lReport.Add('TOTAL%9.2f %10.2f %10.2f %4d', [MeanDep, MSDep, sqrt(MSDep), N]); + lReport.Add('TOTAL %9.2f %10.2f %10.2f %7d', [MeanDep, MSDep, sqrt(MSDep), N]); lReport.Add('---------------------------------------------------'); lReport.Add(''); c := 1.0 + (1.0 / (3 * DFF1)) * (sumDFRecip - (1.0 / DFErr)); - bartlett := (2.303 / c) * (DFErr * Log10(MSErr) - sumFreqLogVar); + bartlett := (2.303 / c) * (DFErr * ln(MSErr) - sumFreqLogVar); // wp: was log10(),but all the others use ln() here chiProb := 1.0 - ChiSquaredProb(bartlett, round(DFF1)); cochran := maxVar / sumVar; hartley := maxVar / minVar; @@ -740,10 +652,10 @@ begin lReport.Add(''); lReport.Add('TESTS FOR HOMOGENEITY OF VARIANCE'); lReport.Add(''); - lReport.Add('Hartley Fmax test statistic: %8.2f (%d and %d d.f.)', [hartley, NF1cells, maxSize-1]); - lReport.Add('Cochran C statistic: %8.2f (%d and %d d.f.)', [cochran, Nf1cells, maxSize-1]); - lReport.Add('Bartlett Chi-square: %8.2f (%.0f d.f)', [bartlett, DFF1]); - lReport.Add(' probability > Chi-Square: %8.3f', [chiprob]); + lReport.Add('Hartley Fmax test statistic: %8.3f (%d and %d degrees of freedom)', [hartley, NF1cells, maxSize-1]); + lReport.Add('Cochran C statistic: %8.3f (%d and %d degrees of freedom)', [cochran, Nf1cells, maxSize-1]); + lReport.Add('Bartlett Chi-square: %8.3f (%.0f degrees of freedom)', [bartlett, DFF1]); + lReport.Add(' probability > Chi-Square: %8.3f', [chiprob]); FReportFrame.DisplayReport(lReport); finally @@ -870,22 +782,32 @@ end; procedure TBlksAnovaForm.Init2Way; +var + totalcells: Integer; begin RowSums := nil; ColSums := nil; RowCount := nil; ColCount := nil; - counts := nil; - sums := nil; - vars := nil; + Counts := nil; + Sums := nil; + Vars := nil; + cellCnts := nil; + cellVars := nil; + cellSums := 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 + 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 + + totalCells := NF1Cells + NF2Cells + NF3Cells; + SetLength(cellCnts, totalCells); // array of cell counts + SetLength(cellSums, totalCells); // array of cell sums then means + SetLength(cellVars, totalCells); // array of cell sums of squares then variances end; @@ -900,16 +822,6 @@ begin NoGrpsA := MaxF1 - MinF1 + 1; NoGrpsB := MaxF2 - MinF2 + 1; - { - RowSums := Default(DblDyneVec); - ColSums := Default(DblDyneVec); - RowCount := Default(IntDyneVec); - ColCount := Default(IntDyneVec); - Counts := Default(IntDyneMat); - Sums := Default(DblDyneMat); - Vars := Default(DblDyneMat); - } - // Get working totals N := 0; MeanDep := 0.0; @@ -931,26 +843,6 @@ begin MeanDep := MeanDep + X; SSDep := SSDep + Xsq; N := N + 1; - { - if not GoodRecord(OS3MainFrm.DataGrid, i, ColNoSelected) then continue; - grpA := round(StrToFloat(Trim(OS3MainFrm.DataGrid.Cells[ColNoSelected[1], i]))); - grpB := round(StrToFloat(Trim(OS3MainFrm.DataGrid.Cells[ColNoSelected[2], i]))); - X := StrToFloat(Trim(OS3MainFrm.DataGrid.Cells[ColNoSelected[0], i])); - X2 := X*X; - grpA := grpA - minf1 + 1; - grpB := grpB - minf2 + 1; - - counts[grpA-1,grpB-1] := counts[grpA-1,grpB-1] + 1; - sums[grpA-1,grpB-1] := sums[grpA-1,grpB-1] + X; - vars[grpA-1,grpB-1] := vars[grpA-1,grpB-1] + X2; - RowSums[GrpA-1] := RowSums[GrpA-1] + X; - ColSums[GrpB-1] := ColSums[GrpB-1] + X; - RowCount[GrpA-1] := RowCount[GrpA-1] + 1; - ColCount[GrpB-1] := ColCount[GrpB-1] + 1; - MeanDep := MeanDep + X; - SSDep := SSDep + X2; - N := N + 1; - } end; // Calculate results @@ -1071,8 +963,6 @@ begin end; procedure TBlksAnovaForm.TwoWayTable; -const - FIXED_RANDOM: array[0..1] of string = ('fixed', 'random'); var lReport: TStrings; groupsize: integer; @@ -1086,7 +976,6 @@ begin lReport.Add('TWO-WAY ANALYSIS OF VARIANCE'); lReport.Add(''); lReport.Add('Variable analyzed: %s', [DepVarEdit.Text]); - lReport.Add('Factor A (rows) variable: %s (%s levels)',[ Factor1Edit.Text, FIXED_RANDOM[Fact1Combo.ItemIndex] ]); @@ -1095,15 +984,17 @@ begin ]); lReport.Add(''); - lReport.Add('SOURCE D.F. SS MS F PROB.> F Omega Squared'); - lReport.Add(''); - lReport.Add('Among Rows %4.0f %8.3f %8.3f %8.3f %6.3f %6.3f', [DFF1, SSF1, MSF1, FF1, ProbF1, OmegaF1]); - lReport.Add('Among Columns %4.0f %8.3f %8.3f %8.3f %6.3f %6.3f', [DFF2, SSF2, MSF2, FF2, ProbF2, OmegaF2]); - lReport.Add('Interaction %4.0f %8.3f %8.3f %8.3f %6.3f %6.3f', [DFF1F2, SSF1F2, MSF1F2, FF1F2, ProbF1F2, OmegaF1F2]); - lReport.Add('Within Groups %4.0f %8.3f %8.3f', [DFErr, SSErr, MSErr]); - lReport.Add('Total %4.0f %8.3f %8.3f', [DFTot, SSDep, MSDep]); - lReport.Add(''); - lReport.Add('Omega squared for combined effects = %8.3f', [Omega]); + lReport.Add( '--------------------------------------------------------------------------------'); + lReport.Add( 'SOURCE D.F. SS MS F PROB.> F Omega Squared'); + lReport.Add( '------------- ---- ---------- ---------- ---------- -------- -------------'); + lReport.Add( 'Among Rows %4.0f %10.3f %10.3f %10.3f %8.3f %10.3f', [DFF1, SSF1, MSF1, FF1, ProbF1, OmegaF1]); + lReport.Add( 'Among Columns %4.0f %10.3f %10.3f %10.3f %8.3f %10.3f', [DFF2, SSF2, MSF2, FF2, ProbF2, OmegaF2]); + lReport.Add( 'Interaction %4.0f %10.3f %10.3f %10.3f %8.3f %10.3f', [DFF1F2, SSF1F2, MSF1F2, FF1F2, ProbF1F2, OmegaF1F2]); + lReport.Add( 'Within Groups %4.0f %10.3f %10.3f', [DFErr, SSErr, MSErr]); + lReport.Add( 'Total %4.0f %10.3f %10.3f', [DFTot, SSDep, MSDep]); + lReport.Add( '--------------------------------------------------------------------------------'); + lReport.Add( ''); + lReport.Add('Omega squared for combined effects; %8.3f', [Omega]); lReport.Add(''); if (Fact1Combo.ItemIndex = 0) and (Fact2Combo.ItemIndex = 0) then lReport.Add('Note: Denominator of F ratio is MSErr'); @@ -1120,10 +1011,13 @@ begin lReport.Add('and denominator for A and AxB is MSErr'); end; lReport.Add(''); + lReport.Add(DIVIDER_AUTO); lReport.Add(''); lReport.Add('DESCRIPTIVE STATISTICS'); - lReport.Add(''); - lReport.Add('GROUP Row Col. N MEAN VARIANCE STD.DEV.'); +// lReport.Add(''); + lReport.Add('------------------------------------------------------'); + lReport.Add('GROUP Row Col. N MEAN VARIANCE STD.DEV.'); + lReport.Add('----- --- ---- ----- --------- -------- --------'); groupsize := counts[0, 0]; equal_grp := true; MaxVar := 0.0; @@ -1149,11 +1043,11 @@ begin sumvars := sumvars + V; if V > MaxVar then MaxVar := V; if V < MinVar then MinVar := V; - sumDFrecip := sumDFrecip + (1.0 / (counts[i,j] - 1.0)); - sumfreqlogvar := sumfreqlogvar + ((counts[i,j] - 1.0) * ln(V)); + sumDFrecip := sumDFrecip + (1.0 / (counts[i,j] - 1)); + sumfreqlogvar := sumfreqlogvar + ((counts[i,j] - 1) * ln(V)); if counts[i,j] <> groupsize then equal_grp := false; end; - lReport.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 %4d %9.3f %8.3f %8.3f', [MinF1+i, MinF2+j, counts[i,j], XBar, V, S]); end; end; @@ -1161,45 +1055,45 @@ begin for i := 0 to NoGrpsA-1 do begin XBar := RowSums[i] / RowCount[i]; -// OrdMeansA[i] := XBar; RowSS := 0.0; for j := 0 to NoGrpsB-1 do RowSS := RowSS + vars[i,j]; V := RowSS - (RowSums[i] * RowSums[i] / RowCount[i]); - V := V / (RowCount[i] - 1.0); + V := V / (RowCount[i] - 1); S := sqrt(V); - lReport.Add('Row %3d %3d %8.3f %8.3f %8.3f', [minf1+i, RowCount[i], XBar, V, S]); + lReport.Add('Row %3d %4d %9.3f %8.3f %8.3f', [minf1+i, RowCount[i], XBar, V, S]); end; //Display means, variances and standard deviations for columns for j := 0 to NoGrpsB-1 do begin XBar := ColSums[j] / ColCount[j]; -// OrdMeansB[j] := XBar; ColSS := 0.0; 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] > 1 then V := V / (ColCount[j] - 1.0); + if ColCount[j] > 1 then V := V / (ColCount[j] - 1); if V > 0.0 then S := sqrt(V); - lReport.Add('Col %3d %3d %8.3f %8.3f %8.3f', [minf2+j, ColCount[j], XBar, V, S]); + lReport.Add('Col %3d %4d %9.3f %8.3f %8.3f', [minf2+j, ColCount[j], XBar, V, S]); end; - lReport.Add('TOTAL %3d %8.3f %8.3f %8.3f', [N, MeanDep, MSDep, sqrt(MSDep)]); - lReport.Add(''); + lReport.Add('------------------------------------------------------'); + lReport.Add('TOTAL %4d %9.3f %8.3f %8.3f', [N, MeanDep, MSDep, sqrt(MSDep)]); + lReport.Add('------------------------------------------------------'); lReport.Add(''); c := 1.0 + (1.0 / (3.0 * NoGrpsA * NoGrpsB - 1.0)) * (sumDFrecip - (1.0 / DFErr)); bartlett := (2.303 / c) * ((DFErr * ln(MSErr)) - sumfreqlogvar); - chiprob := 1.0 - chisquaredprob(bartlett,round(NoGrpsA * NoGrpsB - 1)); + chiprob := 1.0 - ChiSquaredProb(bartlett, round(NoGrpsA * NoGrpsB - 1)); cochran := maxvar / sumvars; hartley := maxvar / minvar; - lReport.Add(DIVIDER); + lReport.Add(DIVIDER_AUTO); + lReport.Add(''); lReport.Add('TESTS FOR HOMOGENEITY OF VARIANCE'); - lReport.Add(DIVIDER_SMALL); - lReport.Add('Hartley Fmax test statistic: %.2f with deg.s freedom: %d and %d.', [hartley, NoGrpsA*NoGrpsB, groupsize-1]); - lReport.Add('Cochran C statistic: %.2f with deg.s freedom: %d and %d.', [cochran, NoGrpsA*NoGrpsB, groupsize - 1]); - lReport.Add('Bartlett Chi-square statistic: %.2f with %d D.F.; prob. larger value %.3f', [bartlett, NoGrpsA*NoGrpsB - 1, chiprob]); - lReport.Add(DIVIDER); + lReport.Add(''); //DIVIDER_SMALL_AUTO); + lReport.Add('Hartley Fmax test statistic: %8.3f with %d and %d degrees of freedom.', [hartley, NoGrpsA*NoGrpsB, groupsize-1]); + lReport.Add('Cochran C statistic: %8.3f with %d and %d degrees of freedom.', [cochran, NoGrpsA*NoGrpsB, groupsize - 1]); + lReport.Add('Bartlett Chi-square statistic: %8.3f with %d degrees of freedom; prob. > value: %.3f', [bartlett, NoGrpsA*NoGrpsB - 1, chiprob]); +// lReport.Add(DIVIDER_AUTO); FReportFrame.DisplayReport(lReport); finally @@ -1486,180 +1380,180 @@ begin end; *) -function TBlksAnovaForm.Calc3Way: Boolean; + +procedure TBlksAnovaForm.Init3Way; var - i, j, k : integer; - grpA, grpB, grpC : integer; - Constant, RowsTotCnt, ColsTotCnt, SlcsTotCnt, SSCells : double; - p, n2 : double; + totalCells: Integer; +begin + RowSums := nil; + ColSums := nil; + SlcSums := nil; + RowCount := nil; + ColCount := nil; + SlcCount := nil; + WSum := nil; + WX2 := nil; + NCnt := nil; + cellCnts := nil; + cellSums := nil; + cellVars := nil; + + SetLength(RowSums, NF1Cells); // 2 way row sums + SetLength(RowCount, NF1Cells); // 2 way row count + SetLength(ColSums, NF2Cells); // 2 way col sums + SetLength(ColCount, NF2Cells); // 2 way col count + SetLength(SlcSums, NF3Cells); // 3 way slice sums + SetLength(SlcCount, NF3Cells); // 3 way slice counts + SetLength(WSum, NF1Cells, NF2Cells, NF3Cells); + SetLength(WX2, NF1Cells, NF2Cells, NF3Cells); + SetLength(NCnt, NF1Cells, NF2Cells, NF3Cells); + + totalCells := NF1Cells + NF2Cells + NF3Cells; + SetLength(cellCnts, totalCells); // array of cell counts + SetLength(cellSums, totalCells); // array of cell sums then means + SetLength(cellVars, totalCells); // array of cell sums of squares then variances + +end; + + +function TBlksAnovaForm.Calc3Way(const DepValues, F1Values, F2Values, F3Values: DblDyneVec): Boolean; +var + i, j, k: integer; + grpA, grpB, grpC: integer; + Constant, RowsTotCnt, ColsTotCnt, SlcsTotCnt, SSCells: double; + p, n2: double; X, Xsq: Double; begin - // initialize matrix values - NoGrpsA := maxf1 - minf1 + 1; - NoGrpsB := maxf2 - minf2 + 1; - NoGrpsC := maxf3 - minf3 + 1; - - for i := 0 to NoGrpsA-1 do - begin - RowSums[i] := 0.0; - RowCount[i] := 0; - for j := 0 to NoGrpsB-1 do - begin - for k := 0 to NoGrpsC-1 do - begin - wsum[i,j,k] := 0.0; - ncnt[i,j,k] := 0; - wx2[i,j,k] := 0.0; - end; - end; - end; - - for i := 0 to NoGrpsB-1 do - begin - ColCount[i] := 0; - ColSums[i] := 0.0; - end; - - for i := 0 to NoGrpsC-1 do - begin - SlcCount[i] := 0; - SlcSums[i] := 0.0; - end; + NoGrpsA := MaxF1 - MinF1 + 1; + NoGrpsB := MaxF2 - MinF2 + 1; + NoGrpsC := MaxF3 - MinF3 + 1; + // Get working totals N := 0; - MeanDep := 0.0; - SSDep := 0.0; - RowsTotCnt := 0.0; - ColsTotCnt := 0.0; - SlcsTotCnt := 0.0; - SSF1 := 0.0; - SSF2 := 0.0; - SSF3 := 0.0; - SSF1F2 := 0.0; - SSF1F3 := 0.0; - SSF2F3 := 0.0; - SSF1F2F3 := 0.0; - SSCells := 0.0; - - // get working totals - for i := 1 to NoCases do + MeanDep := 0; + SSDep := 0; + for i := 0 to High(DepValues) do begin - if not GoodRecord(OS3MainFrm.DataGrid, i, ColNoSelected) then continue; - grpA := round(StrToFloat(Trim(OS3MainFrm.DataGrid.Cells[ColNoSelected[1], i]))); - grpB := round(StrToFloat(Trim(OS3MainFrm.DataGrid.Cells[ColNoSelected[2], i]))); - grpC := round(StrToFloat(Trim(OS3MainFrm.DataGrid.Cells[ColNoSelected[3], i]))); - X := StrToFloat(Trim(OS3MainFrm.DataGrid.Cells[ColNoSelected[0], i])); - Xsq := X*X; - grpA := grpA - minf1 + 1; - grpB := grpB - minf2 + 1; - grpC := grpC - minf3 + 1; - ncnt[grpA-1,grpB-1,grpC-1] := ncnt[grpA-1,grpB-1,grpC-1] + 1; - wsum[grpA-1,grpB-1,grpC-1] := wsum[grpA-1,grpB-1,grpc-1] + X; - wx2[grpA-1,grpB-1,grpC-1] := wx2[grpA-1,grpB-1,grpC-1] + Xsq; - RowSums[GrpA-1] := RowSums[GrpA-1] + X; - ColSums[GrpB-1] := ColSums[GrpB-1] + X; - SlcSums[GrpC-1] := SlcSums[GrpC-1] + X; - RowCount[GrpA-1] := RowCount[GrpA-1] + 1; - ColCount[GrpB-1] := ColCount[GrpB-1] + 1; - SlcCount[GrpC-1] := SlcCount[GrpC-1] + 1; + grpA := round(F1Values[i]) - MinF1; + grpB := round(F2Values[i]) - MinF2; + grpC := round(F3Values[i]) - MinF3; + X := DepValues[i]; + Xsq := X * X; + NCnt[grpA, grpB, grpC] := NCnt[grpA, grpB, grpC] + 1; + WSum[grpA, grpB, grpC] := WSum[grpA, grpB, grpc] + X; + WX2[grpA, grpB, grpC] := WX2[grpA, grpB, grpC] + Xsq; + RowSums[grpA] := RowSums[grpA] + X; + ColSums[grpB] := ColSums[grpB] + X; + SlcSums[grpC] := SlcSums[grpC] + X; + RowCount[grpA] := RowCount[grpA] + 1; + ColCount[grpB] := ColCount[grpB] + 1; + SlcCount[grpC] := SlcCount[grpC] + 1; MeanDep := MeanDep + X; SSDep := SSDep + Xsq; N := N + 1; end; // Calculate results + constant := sqr(MeanDep) / N; - Constant := (MeanDep * MeanDep) / N; - - // get ss for rows + // Get SS for rows + SSF1 := 0; + RowsTotCnt := 0; for i := 0 to NoGrpsA-1 do begin - SSF1 := SSF1 + ((RowSums[i] * RowSums[i]) / RowCount[i]); + SSF1 := SSF1 + sqr(RowSums[i]) / RowCount[i]; RowsTotCnt := RowsTotCnt + RowCount[i]; end; - SSF1 := SSF1 - Constant; + SSF1 := SSF1 - constant; - // get ss for columns + // Get SS for columns + SSF2 := 0; + ColsTotCnt := 0; for j := 0 to NoGrpsB-1 do begin - SSF2 := SSF2 + ((ColSums[j] * ColSums[j]) / ColCount[j]); + SSF2 := SSF2 + sqr(ColSums[j]) / ColCount[j]; ColsTotCnt := ColsTotCnt + ColCount[j]; end; - SSF2 := SSF2 - Constant; + SSF2 := SSF2 - constant; - // get ss for slices + // Get SS for slices + SSF3 := 0; + SlcsTotCnt := 0; for k := 0 to NoGrpsC-1 do begin - SSF3 := SSF3 + ((SlcSums[k] * SlcSums[k]) / SlcCount[k]); + SSF3 := SSF3 + sqr(SlcSums[k]) / SlcCount[k]; SlcsTotCnt := SlcsTotCnt + SlcCount[k]; end; - SSF3 := SSF3 - Constant; + SSF3 := SSF3 - constant; - // get ss for row x col interaction - p := 0.0; - n2 := 0.0; + // Get SS for row-col interaction + SSF1F2 := 0; for i := 0 to NoGrpsA-1 do begin for j := 0 to NoGrpsB-1 do begin - for k := 0 to NoGrpsC-1 do - begin - p := p + wsum[i,j,k]; - n2 := n2 + ncnt[i,j,k]; - end; - SSF1F2 := SSF1F2 + ((p * p) / n2); p := 0.0; n2 := 0.0; + for k := 0 to NoGrpsC-1 do + begin + p := p + WSum[i, j, k]; + n2 := n2 + NCnt[i, j, k]; + end; + SSF1F2 := SSF1F2 + sqr(p) / n2; end; end; - SSF1F2 := SSF1F2 - SSF1 - SSF2 - Constant; + SSF1F2 := SSF1F2 - SSF1 - SSF2 - constant; - // get ss for row x slice interaction + // Get SS for row-slice interaction + SSF1F3 := 0; for i := 0 to NoGrpsA-1 do begin for k := 0 to NoGrpsC-1 do begin - for j := 0 to NoGrpsB-1 do - begin - p := p + wsum[i,j,k]; - n2 := n2 + ncnt[i,j,k]; - end; - SSF1F3 := SSF1F3 + ((p * p) / n2); p := 0.0; n2 := 0.0; + for j := 0 to NoGrpsB-1 do + begin + p := p + WSum[i, j, k]; + n2 := n2 + NCnt[i, j, k]; + end; + SSF1F3 := SSF1F3 + sqr(p) / n2; end; end; - SSF1F3 := SSF1F3 - SSF1 - SSF3 - Constant; + SSF1F3 := SSF1F3 - SSF1 - SSF3 - constant; - // get ss for columns x slices interaction + // Get SS for column-slice interaction + SSF2F3 := 0; for j := 0 to NoGrpsB-1 do begin for k := 0 to NoGrpsC-1 do begin - for i := 0 to NoGrpsA-1 do - begin - p := p + wsum[i,j,k]; - n2 := n2 + ncnt[i,j,k]; - end; - SSF2F3 := SSF2F3 + ((p * p) / n2); p := 0.0; n2 := 0.0; + for i := 0 to NoGrpsA-1 do + begin + p := p + WSum[i, j, k]; + n2 := n2 + NCnt[i, j, k]; + end; + SSF2F3 := SSF2F3 + sqr(p) / n2; end; end; - SSF2F3 := SSF2F3 - SSF2 - SSF3 - Constant; + SSF2F3 := SSF2F3 - SSF2 - SSF3 - constant; - // get ss for cells + // Get SS for cells + SSCells := 0; for i := 0 to NoGrpsA-1 do for j := 0 to NoGrpsB-1 do for k := 0 to NoGrpsC-1 do - SSCells := SSCells + ((wsum[i,j,k] * wsum[i,j,k]) / ncnt[i,j,k]); + SSCells := SSCells + sqr(wsum[i, j, k]) / ncnt[i, j, k]; - SSF1F2F3 := SSCells - SSF1 - SSF2 - SSF3 - SSF1F2 - SSF1F3 - SSF2F3 - Constant; + SSF1F2F3 := SSCells - SSF1 - SSF2 - SSF3 - SSF1F2 - SSF1F3 - SSF2F3 - constant; SSErr := SSDep - SSCells; - SSDep := SSDep - Constant; + SSDep := SSDep - constant; - if (SSF1 < 0.0) or (SSF2 < 0.0) or (SSF3 < 0.0) or (SSF1F2 < 0.0) or - (SSF1F3 < 0.0) or (SSF2F3 < 0.0) or (SSF1F2F3 < 0.0) then + if (SSF1 < 0.0) or (SSF2 < 0.0) or (SSF3 < 0.0) or + (SSF1F2 < 0.0) or (SSF1F3 < 0.0) or (SSF2F3 < 0.0) or + (SSF1F2F3 < 0.0) then begin ErrorMsg('ERROR! A negative SS found. Unbalanced Design? Ending analysis.'); Result := false; @@ -1675,6 +1569,7 @@ begin DFF2F3 := DFF2 * DFF3; DFF1F2F3 := DFF1 * DFF2 * DFF3; DFErr := DFTot - DFF1 - DFF2 - DFF3 - DFF1F2 - DFF1F3 - DFF2F3 - DFF1F2F3; + MSF1 := SSF1 / DFF1; MSF2 := SSF2 / DFF2; MSF3 := SSF3 / DFF3; @@ -1684,6 +1579,7 @@ begin MSF1F2F3 := SSF1F2F3 / DFF1F2F3; MSErr := SSErr / DFErr; MSDep := SSDep / DFTot; + OmegaF1 := (SSF1 - DFF1 * MSErr) / (SSDep + MSErr); OmegaF2 := (SSF2 - DFF2 * MSErr) / (SSDep + MSErr); OmegaF3 := (SSF3 - DFF3 * MSErr) / (SSDep + MSErr); @@ -1704,40 +1600,40 @@ begin FF1F3 := abs(MSF1F3 / MSErr); FF2F3 := abs(MSF2F3 / MSErr); FF1F2F3 := abs(MSF1F2F3 / MSErr); - ProbF1 := probf(FF1,DFF1,DFErr); - ProbF2 := probf(FF2,DFF2,DFErr); - ProbF3 := probf(FF3,DFF3,DFErr); - ProbF1F2 := probf(FF1F2,DFF1F2,DFErr); - ProbF1F3 := probf(FF1F3,DFF1F3,DFErr); - ProbF2F3 := probf(FF2F3,DFF2F3,DFErr); - ProbF1F2F3 := probf(FF1F2F3,DFF1F2F3,DFErr); + ProbF1 := ProbF(FF1, DFF1, DFErr); + ProbF2 := ProbF(FF2, DFF2, DFErr); + ProbF3 := ProbF(FF3, DFF3, DFErr); + ProbF1F2 := ProbF(FF1F2, DFF1F2, DFErr); + ProbF1F3 := ProbF(FF1F3, DFF1F3, DFErr); + ProbF2F3 := ProbF(FF2F3, DFF2F3, DFErr); + ProbF1F2F3 := ProbF(FF1F2F3, DFF1F2F3, DFErr); end; // F tests if all factors are random - for i := 1 to 14 do OKterms[i] := 1; // initialize as OK + for i := 1 to 14 do OKterms[i] := true; // initialize as OK if (Fact1Combo.ItemIndex = 1) and (Fact2Combo.ItemIndex = 1) and (Fact3Combo.ItemIndex = 1) then begin - if (MSF1F2 + MSF1F3 - MSF1F2F3) < 0.0 - then OKTerms[1] := 0 + if (MSF1F2 + MSF1F3 - MSF1F2F3) <= 0.0 + then OKTerms[1] := false else FF1 := abs(MSF1 / (MSF1F2 + MSF1F3 - MSF1F2F3)); - if (MSF1F2 + MSF2F3 - MSF1F2F3) < 0.0 - then OKTerms[2] := 0 + if (MSF1F2 + MSF2F3 - MSF1F2F3) <= 0.0 + then OKTerms[2] := false else FF2 := abs(MSF2 / (MSF1F2 + MSF2F3 - MSF1F2F3)); - if (MSF1F3 + MSF2F3 - MSF1F2F3) < 0.0 - then OKTerms[3] := 0 + if (MSF1F3 + MSF2F3 - MSF1F2F3) <= 0.0 + then OKTerms[3] := false else FF3 := abs(MSF3 / (MSF1F3 + MSF2F3 - MSF1F2F3)); FF1F2 := abs(MSF1F2 / MSF1F2F3); FF1F3 := abs(MSF1F3 / MSF1F2F3); FF2F3 := abs(MSF2F3 / MSF1F2F3); FF1F2F3 := abs(MSF1F2F3 / MSErr); - ProbF1 := probf(FF1,DFF1,DFF1F2F3); - ProbF2 := probf(FF2,DFF2,DFF1F2F3); - ProbF3 := probf(FF3,DFF3,DFF1F2F3); - ProbF1F2 := probf(FF1F2,DFF1F2,DFF1F2F3); - probF1F3 := probf(FF1F3,DFF1F3,DFF1F2F3); - probF2F3 := probf(FF2F3,DFF2F3,DFF1F2F3); - probF1F2F3 := probf(FF1F2F3,DFF1F2F3,DFErr); + ProbF1 := ProbF(FF1, DFF1, DFF1F2F3); + ProbF2 := ProbF(FF2, DFF2, DFF1F2F3); + ProbF3 := ProbF(FF3, DFF3, DFF1F2F3); + ProbF1F2 := ProbF(FF1F2, DFF1F2, DFF1F2F3); + probF1F3 := ProbF(FF1F3, DFF1F3, DFF1F2F3); + probF2F3 := ProbF(FF2F3, DFF2F3, DFF1F2F3); + probF1F2F3 := ProbF(FF1F2F3, DFF1F2F3, DFErr); end; // F test if factor A is random, B and C Fixed @@ -1750,13 +1646,13 @@ begin FF1F3 := abs(MSF1F3 / MSErr); FF2F3 := abs(MSF2F3 / MSF1F2F3); FF1F2F3 := abs(MSF1F2F3 / MSErr); - ProbF1 := probf(FF1,DFF1,DFErr); - ProbF2 := probf(FF2,DFF2,DFF1F2); - ProbF3 := probf(FF3,DFF3,DFF1F3); - ProbF1F2 := probf(FF1F2,DFF1F2,DFErr); - ProbF1F3 := probf(FF1F3,DFF1F3,DFErr); - ProbF2F3 := probf(FF2F3,DFF2F3,DFF1F2F3); - ProbF1F2F3 := probf(FF1F2F3,DFF1F2F3,DFErr); + ProbF1 := ProbF(FF1, DFF1, DFErr); + ProbF2 := ProbF(FF2, DFF2, DFF1F2); + ProbF3 := ProbF(FF3, DFF3, DFF1F3); + ProbF1F2 := ProbF(FF1F2, DFF1F2, DFErr); + ProbF1F3 := ProbF(FF1F3, DFF1F3, DFErr); + ProbF2F3 := ProbF(FF2F3, DFF2F3, DFF1F2F3); + ProbF1F2F3 := ProbF(FF1F2F3, DFF1F2F3, DFErr); end; // F test if factor b is random and A and C are Fixed @@ -1769,13 +1665,13 @@ begin FF1F3 := abs(MSF1F3 / MSF1F2F3); FF2F3 := abs(MSF2F3 / MSErr); FF1F2F3 := abs(MSF1F2F3 / MSErr); - ProbF1 := probf(FF1,DFF1,DFF1F2); - ProbF2 := probf(FF2,DFF2,DFErr); - ProbF3 := probf(FF3,DFF3,DFF2F3); - ProbF1F2 := probf(FF1F2,DFF1F2,DFErr); - ProbF1F3 := probf(FF1F3,DFF1F3,DFF1F2F3); - ProbF2F3 := probf(FF2F3,DFF2F3,DFErr); - ProbF1F2F3 := probf(FF1F2F3,DFF1F2F3,DFErr); + ProbF1 := ProbF(FF1, DFF1, DFF1F2); + ProbF2 := ProbF(FF2, DFF2, DFErr); + ProbF3 := ProbF(FF3, DFF3, DFF2F3); + ProbF1F2 := ProbF(FF1F2, DFF1F2, DFErr); + ProbF1F3 := ProbF(FF1F3, DFF1F3, DFF1F2F3); + ProbF2F3 := ProbF(FF2F3, DFF2F3, DFErr); + ProbF1F2F3 := ProbF(FF1F2F3, DFF1F2F3, DFErr); end; // F test if factor c is random and A and B are Fixed @@ -1788,20 +1684,20 @@ begin FF1F3 := abs(MSF1F3 / MSErr); FF2F3 := abs(MSF2F3 / MSErr); FF1F2F3 := abs(MSF1F2F3 / MSErr); - ProbF1 := probf(FF1,DFF1,DFF1F3); - ProbF2 := probf(FF2,DFF2,DFF2F3); - ProbF3 := probf(FF3,DFF3,DFErr); - ProbF1F2 := probf(FF1F2,DFF1F2,DFF1F2F3); - ProbF1F3 := probf(FF1F3,DFF1F3,DFErr); - ProbF2F3 := probf(FF2F3,DFF2F3,DFErr); - ProbF1F2F3 := probf(FF1F2F3,DFF1F2F3,DFErr); + ProbF1 := ProbF(FF1, DFF1, DFF1F3); + ProbF2 := ProbF(FF2, DFF2, DFF2F3); + ProbF3 := ProbF(FF3, DFF3, DFErr); + ProbF1F2 := ProbF(FF1F2, DFF1F2, DFF1F2F3); + ProbF1F3 := ProbF(FF1F3, DFF1F3, DFErr); + ProbF2F3 := ProbF(FF2F3, DFF2F3, DFErr); + ProbF1F2F3 := ProbF(FF1F2F3, DFF1F2F3, DFErr); end; // F tests if A is fixed, B and C are random if (Fact1Combo.ItemIndex = 0) and (Fact2Combo.ItemIndex = 1) and (Fact3Combo.ItemIndex = 1) then begin - if (MSF1F3 + MSF1F2 - MSF1F2F3) < 0.0 - then OKTerms[1] := 0 + if (MSF1F3 + MSF1F2 - MSF1F2F3) <= 0.0 + then OKTerms[1] := false else FF1 := abs(MSF1 / (MSF1F3 + MSF1F2 - MSF1F2F3)); FF2 := abs(MSF2 / MSF2F3); FF3 := abs(MSF3 / MSF2F3); @@ -1810,14 +1706,14 @@ begin FF2F3 := abs(MSF2F3 / MSErr); FF1F2F3 := abs(MSF1F2F3 / MSErr); if (DFF1F3 + DFF1F2 - DFF1F2F3) <= 0 - then OKTerms[8] := 0 - else ProbF1 := probf(FF1,DFF1,(DFF1F3 + DFF1F2 - DFF1F2F3)); - ProbF2 := probf(FF2,DFF2,DFF2F3); - ProbF3 := probf(FF3,DFF3,DFF2F3); - ProbF1F2 := probf(FF1F2,DFF1F2,DFF1F2F3); - ProbF1F3 := probf(FF1F3,DFF1F3,DFF1F2F3); - ProbF2F3 := probf(FF2F3,DFF2F3,DFErr); - ProbF1F2F3 := probf(FF1F2F3,DFF1F2F3,DFErr); + then OKTerms[8] := false + else ProbF1 := ProbF(FF1, DFF1, DFF1F3 + DFF1F2 - DFF1F2F3); + ProbF2 := ProbF(FF2, DFF2, DFF2F3); + ProbF3 := ProbF(FF3, DFF3, DFF2F3); + ProbF1F2 := ProbF(FF1F2, DFF1F2, DFF1F2F3); + ProbF1F3 := ProbF(FF1F3, DFF1F3, DFF1F2F3); + ProbF2F3 := ProbF(FF2F3, DFF2F3, DFErr); + ProbF1F2F3 := ProbF(FF1F2F3, DFF1F2F3, DFErr); end; // F tests if B is fixed, A and C are random @@ -1825,7 +1721,7 @@ begin begin FF1 := abs(MSF2 / MSF1F3); if (MSF2F3 + MSF1F2 - MSF1F2F3) <= 0.0 - then OKTerms[2] := 0 + then OKTerms[2] := false else FF2 := abs(MSF1 / (MSF2F3 + MSF1F2 - MSF1F2F3)); FF3 := abs(MSF3 / MSF1F3); FF1F2 := abs(MSF1F2 / MSF1F2F3); @@ -1834,13 +1730,13 @@ begin FF1F2F3 := abs(MSF1F2F3 / MSErr); ProbF1 := probf(FF2,DFF2,DFF1F3); if (DFF2F3 + DFF1F2 - DFF1F2F3) <= 0 - then OKTerms[9] := 0 - else ProbF2 := probf(FF1,DFF1,(DFF2F3 + DFF1F2 - DFF1F2F3)); - ProbF3 := probf(FF3,DFF3,DFF1F3); - ProbF1F2 := probf(FF1F2,DFF1F2,DFF1F2F3); - ProbF1F3 := probf(FF1F3,DFF1F3,DFErr); - ProbF2F3 := probf(FF2F3,DFF2F3,DFF1F2F3); - ProbF1F2F3 := probf(FF1F2F3,DFF1F2F3,DFErr); + then OKTerms[9] := false + else ProbF2 := ProbF(FF1, DFF1, DFF2F3 + DFF1F2 - DFF1F2F3); + ProbF3 := ProbF(FF3, DFF3, DFF1F3); + ProbF1F2 := ProbF(FF1F2, DFF1F2, DFF1F2F3); + ProbF1F3 := Probf(FF1F3, DFF1F3, DFErr); + ProbF2F3 := ProbF(FF2F3, DFF2F3, DFF1F2F3); + ProbF1F2F3 := ProbF(FF1F2F3, DFF1F2F3, DFErr); end; // F tests if C is fixed A and B are random @@ -1849,7 +1745,7 @@ begin FF1 := abs(MSF1 / MSF1F2); FF2 := abs(MSF2 / MSF1F2); if (MSF2F3 + MSF1F3 - MSF1F2F3) <= 0.0 - then OKTerms[3] := 0 + then OKTerms[3] := false else FF3 := abs(MSF3 / (MSF2F3 + MSF1F3 - MSF1F2F3)); FF1F2 := abs(MSF2F3 / MSErr); FF1F3 := abs(MSF1F2 / MSF1F2F3); @@ -1858,12 +1754,12 @@ begin ProbF1 := probf(FF3,DFF3,DFF1F2); ProbF2 := probf(FF2,DFF2,DFF1F2); if (DFF2F3 + DFF1F3 - DFF1F2F3) <= 0 - then OKTerms[10] := 0 - else ProbF3 := probf(FF1,DFF1,(DFF2F3 + DFF1F3 - DFF1F2F3)); - ProbF1F2 := probf(FF2F3,DFF2F3,DFErr); - ProbF1F3 := probf(FF1F2,DFF1F2,DFF1F2F3); - ProbF2F3 := probf(FF1F3,DFF1F3,DFF1F2F3); - ProbF1F2F3 := probf(FF1F2F3,DFF1F2F3,DFErr); + then OKTerms[10] := false + else ProbF3 := ProbF(FF1, DFF1, DFF2F3 + DFF1F3 - DFF1F2F3); + ProbF1F2 := ProbF(FF2F3, DFF2F3, DFErr); + ProbF1F3 := ProbF(FF1F2, DFF1F2, DFF1F2F3); + ProbF2F3 := ProbF(FF1F3, DFF1F3, DFF1F2F3); + ProbF1F2F3 := ProbF(FF1F2F3, DFF1F2F3, DFErr); end; if (ProbF1 > 1.0) then ProbF1 := 1.0; @@ -1887,8 +1783,10 @@ begin Result := true; end; -procedure TBlksAnovaForm.ThreeWayTable(AReport: TStrings); + +procedure TBlksAnovaForm.ThreeWayTable; var + lReport: TStrings; groupsize: integer; MinVar, MaxVar, sumvars, sumDFrecip: double; i, j, k: integer; @@ -1896,241 +1794,518 @@ var sumfreqlogvar, c, bartlett, cochran, hartley, chiprob: double; problem: boolean = false; begin - AReport.Add('Three Way Analysis of Variance'); - AReport.Add(''); - AReport.Add('Variable analyzed: %s', [DepVarEdit.Text]); - AReport.Add(''); + lReport := TStringList.Create; + try + lReport.Add('THREE-WAY ANALYSIS OF VARIANCE'); + lReport.Add(''); + lReport.Add('Variable analyzed: %s', [DepVarEdit.Text]); + lReport.Add('Factor A (rows) variable: %s (%s levels)', [ + Factor1Edit.Text, FIXED_RANDOM[Fact1Combo.ItemIndex] + ]); + lReport.Add('Factor B (columns) variable: %s (%s levels)', [ + Factor2Edit.Text, FIXED_RANDOM[Fact2Combo.ItemIndex] + ]); + lReport.Add('Factor C (slices) variable: %s (%s levels)', [ + Factor3Edit.Text, FIXED_RANDOM[Fact3Combo.ItemIndex] + ]); + lReport.Add(''); + lReport.Add( '--------------------------------------------------------------------------------'); + lReport.Add( 'SOURCE D.F. SS MS F PROB.> F Omega Squared'); + lReport.Add( '------------- ---- ---------- ---------- ---------- -------- -------------'); + if OKTerms[1]and OKTerms[8] then + lReport.Add('Among Rows %4.0f %10.3f %10.3f %10.3f %8.3f %10.3f', [DFF1, SSF1, MSF1, FF1, ProbF1, OmegaF1]) + else + lReport.Add('Among Rows %4.0f %10.3f %10.3f --- error ---', [DFF1, SSF1, MSF1 ]); - outline := format('Factor A (rows) variable: %s', [Factor1Edit.Text]); - if Fact1Combo.ItemIndex = 0 then - outline := outline + ' (Fixed Levels)' - else - outline := outline + ' (Random Levels)'; - AReport.Add(outline); + if OKTerms[2] and OKTerms[9] then + lReport.Add('Among Columns %4.0f %10.3f %10.3f %10.3f %8.3f %10.3f', [DFF2, SSF2, MSF2, FF2, ProbF2, OmegaF2]) + else + lReport.Add('Among Columns %4.0f %10.3f %10.3f --- error ---', [DFF2, SSF2, MSF2]); - outline := format('Factor B (columns) variable: %s', [Factor2Edit.Text]); - if Fact2Combo.ItemIndex = 0 then - outline := outline + ' (Fixed Levels)' - else - outline := outline + ' (Random Levels)'; - AReport.Add(outline); + if OKTerms[3] and OKTerms[10] then + lReport.Add('Among Slices %4.0f %10.3f %10.3f %10.3f %8.3f %10.3f', [DFF3, SSF3, MSF3, FF3, ProbF3, OmegaF3]) + else + lReport.Add('Among Slices %4.0f %10.3f %10.3f --- error ---', [DFF3, SSF3, MSF3]); - outline := format('Factor C (slices) variable: %s', [Factor3Edit.Text]); - if Fact3Combo.ItemIndex = 0 then - outline := outline + ' (Fixed Levels)' - else - outline := outline + ' (Random Levels)'; - AReport.Add(outline); - AReport.Add(''); - - AReport.Add('SOURCE D.F. SS MS F PROB.> F Omega Squared'); - AReport.Add(''); - if (OKTerms[1] = 1) and (OKTerms[8] = 1) then - AReport.Add('Among Rows %4.0f %10.3f %10.3f %10.3f %6.3f %6.3f', [DFF1, SSF1, MSF1, FF1, ProbF1, OmegaF1]) - else - AReport.Add('Among Rows %4.0f %10.3f %10.3f --- error ---', [DFF1, SSF1, MSF1 ]); - - if (OKTerms[2] = 1) and (OKTerms[9] = 1) then - AReport.Add('Among Columns %4.0f %10.3f %10.3f %10.3f %6.3f %6.3f', [DFF2, SSF2, MSF2, FF2, ProbF2, OmegaF2]) - else - AReport.Add('Among Columns %4.0f %10.3f %10.3f --- error ---', [DFF2, SSF2, MSF2]); - - if (OKTerms[3] = 1) and (OKTerms[10] = 1) then - AReport.Add('Among Slices %4.0f %10.3f %10.3f %10.3f %6.3f %6.3f', [DFF3, SSF3, MSF3, FF3, ProbF3, OmegaF3]) - else - AReport.Add('Among Slices %4.0f %10.3f %10.3f --- error ---', [DFF3, SSF3, MSF3]); - - AReport.Add('A x B Inter. %4.0f %10.3f %10.3f %10.3f %6.3f %6.3f', [DFF1F2, SSF1F2, MSF1F2, FF1F2, ProbF1F2, OmegaF1F2]); - AReport.Add('A x C Inter. %4.0f %10.3f %10.3f %10.3f %6.3f %6.3f', [DFF1F3, SSF1F3, MSF1F3, FF1F3, ProbF1F3, OmegaF1F3]); - AReport.Add('B x C Inter. %4.0f %10.3f %10.3f %10.3f %6.3f %6.3f', [DFF2F3, SSF2F3, MSF2F3, FF2F3, ProbF2F3, OmegaF2F3]); - AReport.Add('AxBxC Inter. %4.0f %10.3f %10.3f %10.3f %6.3f %6.3f', [DFF1F2F3, SSF1F2F3, MSF1F2F3, FF1F2F3, ProbF1F2F3, OmegaF1F2F3]); - AReport.Add('Within Groups %4.0f %10.3f %10.3f', [DFErr, SSErr, MSErr]); - AReport.Add('Total %4.0f %10.3f %10.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) and (Fact3Combo.ItemIndex = 0) then - AReport.Add('Note: MSErr denominator for all F ratios.'); - if (Fact1Combo.ItemIndex = 1) and (Fact2Combo.ItemIndex = 1) and (Fact3Combo.ItemIndex = 1) then - begin - AReport.Add('Note: Error term for A is MSAxB + MSAxC - MSAxBxC'); - AReport.Add('Error term for B is MSAxB + MSBxC - MSAxBxC'); - AReport.Add('Error term for C is MSAxC + MSBxC - MSAxBxC'); - AReport.Add('Error term for AxB, AxC and BxC is MSAxBxC'); - AReport.Add('Error term for AxBxC is MSErr.'); - end; - if (Fact1Combo.ItemIndex = 1) and (Fact2Combo.ItemIndex = 0) and (Fact3Combo.ItemIndex = 0) then - begin - AReport.Add('Note: Error term for A is MSErr'); - AReport.Add('Note: Error term for B is MSAxB'); - AReport.Add('Note: Error term for C is MSAxC'); - AReport.Add('Note: Error term for AxB is MSErr'); - AReport.Add('Note: Error term for AxC is MSErr'); - AReport.Add('Note: Error term for BxC is MSAxBxC'); - AReport.Add('Note: Error term for AxBxC is MSErr'); - end; - if (Fact1Combo.ItemIndex = 0) and (Fact2Combo.ItemIndex = 1) and (Fact3Combo.ItemIndex = 0) then - begin - AReport.Add('Note: Error term for A is MSAxB'); - AReport.Add('Note: Error term for B is MSErr'); - AReport.Add('Note: Error term for C is MSBxC'); - AReport.Add('Note: Error term for AxB is MSErr'); - AReport.Add('Note: Error term for AxC is MSAxBxC'); - AReport.Add('Note: Error term for BxC is MSErr'); - AReport.Add('Note: Error term for AxBxC is MSErr'); - end; - if (Fact1Combo.ItemIndex = 0) and (Fact2Combo.ItemIndex = 0) and (Fact3Combo.ItemIndex = 1) then - begin - AReport.Add('Note: Error term for A is MSAxC'); - AReport.Add('Note: Error term for B is MSBxC'); - AReport.Add('Note: Error term for C is MSErr'); - AReport.Add('Note: Error term for AxB is MSAxBxC'); - AReport.Add('Note: Error term for AxC is MSErr'); - AReport.Add('Note: Error term for BxC is MSErr'); - AReport.Add('Note: Error term for AxBxC is MSErr'); - end; - if (Fact1Combo.ItemIndex = 0) and (Fact2Combo.ItemIndex = 1) and (Fact3Combo.ItemIndex = 1) then - begin - AReport.Add('Note: Error term for A is MSAxC + MSAxB - MSAxBxC'); - AReport.Add('Note: Error term for B is MSBxC'); - AReport.Add('Note: Error term for C is MSBxC'); - AReport.Add('Note: Error term for AxB is MSAxBxC'); - AReport.Add('Note: Error term for AxC is MSAxBxC'); - AReport.Add('Note: Error term for BxC is MSErr'); - AReport.Add('Note: Error term for AxBxC is MSErr'); - end; - if (Fact1Combo.ItemIndex = 1) and (Fact2Combo.ItemIndex = 0) and (Fact3Combo.ItemIndex = 1) then - begin - AReport.Add('Note: Error term for A is MSAxC'); - AReport.Add('Note: Error term for B is MSBxC + MSAxB - MSAxBxC'); - AReport.Add('Note: Error term for C is MSAxC'); - AReport.Add('Note: Error term for AxB is MSAxBxC'); - AReport.Add('Note: Error term for AxC is MSErr'); - AReport.Add('Note: Error term for BxC is MSAxBxC'); - AReport.Add('Note: Error term for AxBxC is MSErr'); - end; - if (Fact1Combo.ItemIndex = 1) and (Fact2Combo.ItemIndex = 1) and (Fact3Combo.ItemIndex = 0) then - begin - AReport.Add('Note: Error term for A is MSAxB'); - AReport.Add('Note: Error term for B is MSAxB'); - AReport.Add('Note: Error term for C is MSBxC + MSAxC - MSAxBxC'); - AReport.Add('Note: Error term for AxB is MSErr'); - AReport.Add('Note: Error term for AxC is MSAxBxC'); - AReport.Add('Note: Error term for BxC is MSAxBxC'); - AReport.Add('Note: Error term for AxBxC is MSErr'); - end; - AReport.Add(''); - - for i := 1 to 10 do - if OKTerms[i] = 0 then - problem := true; - - if problem then - begin - AReport.Add('An error occurred due to either an estimate of MS being negative'); - AReport.Add('or the degrees of freedom being zero. This may occur in a design'); - AReport.Add('with random factors using the expected values for an exact F-test.'); - AReport.Add('Quasi-F statistics may be employed where this problem exists. See'); - AReport.Add('Winer, B.J., "Statistical Principles in Experimental Design, 1962'); - AReport.Add('Section 5.15, pages 199-202 and Glass, G.V. and Stanley, J.C.,'); - AReport.Add('1970, Section 18.10, pages 481-482.'); - end; - - AReport.Add(''); - AReport.Add('Descriptive Statistics'); - AReport.Add(''); - AReport.Add('GROUP N MEAN VARIANCE STD.DEV.'); - - groupsize := ncnt[1,1,1]; - equal_grp := true; - MaxVar := 0.0; - MinVar := 1e20; - sumvars := 0.0; - sumfreqlogvar := 0.0; - sumDFrecip := 0.0; - - // Display cell means, variances, standard deviations - for i := 0 to NoGrpsA-1 do - begin - for j := 0 to NoGrpsB-1 do + lReport.Add( 'A x B Inter. %4.0f %10.3f %10.3f %10.3f %8.3f %10.3f', [DFF1F2, SSF1F2, MSF1F2, FF1F2, ProbF1F2, OmegaF1F2]); + lReport.Add( 'A x C Inter. %4.0f %10.3f %10.3f %10.3f %8.3f %10.3f', [DFF1F3, SSF1F3, MSF1F3, FF1F3, ProbF1F3, OmegaF1F3]); + lReport.Add( 'B x C Inter. %4.0f %10.3f %10.3f %10.3f %8.3f %10.3f', [DFF2F3, SSF2F3, MSF2F3, FF2F3, ProbF2F3, OmegaF2F3]); + lReport.Add( 'AxBxC Inter. %4.0f %10.3f %10.3f %10.3f %8.3f %10.3f', [DFF1F2F3, SSF1F2F3, MSF1F2F3, FF1F2F3, ProbF1F2F3, OmegaF1F2F3]); + lReport.Add( 'Within Groups %4.0f %10.3f %10.3f', [DFErr, SSErr, MSErr]); + lReport.Add( 'Total %4.0f %10.3f %10.3f', [DFTot, SSDep, MSDep]); + lReport.Add( '--------------------------------------------------------------------------------'); + lReport.Add( ''); + lReport.Add( 'Omega squared for combined effects: %.3f', [Omega]); + lReport.Add( ''); + if (Fact1Combo.ItemIndex = 0) and (Fact2Combo.ItemIndex = 0) and (Fact3Combo.ItemIndex = 0) then + lReport.Add('Note: MSErr denominator for all F ratios.') + else + if (Fact1Combo.ItemIndex = 1) and (Fact2Combo.ItemIndex = 1) and (Fact3Combo.ItemIndex = 1) then begin - for k := 0 to NoGrpsC-1 do + lReport.Add('Note: Error term for A is MSAxB + MSAxC - MSAxBxC'); + lReport.Add('Error term for B is MSAxB + MSBxC - MSAxBxC'); + lReport.Add('Error term for C is MSAxC + MSBxC - MSAxBxC'); + lReport.Add('Error term for AxB, AxC and BxC is MSAxBxC'); + lReport.Add('Error term for AxBxC is MSErr.'); + end else + if (Fact1Combo.ItemIndex = 1) and (Fact2Combo.ItemIndex = 0) and (Fact3Combo.ItemIndex = 0) then + begin + lReport.Add('Note: Error term for A is MSErr'); + lReport.Add('Note: Error term for B is MSAxB'); + lReport.Add('Note: Error term for C is MSAxC'); + lReport.Add('Note: Error term for AxB is MSErr'); + lReport.Add('Note: Error term for AxC is MSErr'); + lReport.Add('Note: Error term for BxC is MSAxBxC'); + lReport.Add('Note: Error term for AxBxC is MSErr'); + end else + if (Fact1Combo.ItemIndex = 0) and (Fact2Combo.ItemIndex = 1) and (Fact3Combo.ItemIndex = 0) then + begin + lReport.Add('Note: Error term for A is MSAxB'); + lReport.Add('Note: Error term for B is MSErr'); + lReport.Add('Note: Error term for C is MSBxC'); + lReport.Add('Note: Error term for AxB is MSErr'); + lReport.Add('Note: Error term for AxC is MSAxBxC'); + lReport.Add('Note: Error term for BxC is MSErr'); + lReport.Add('Note: Error term for AxBxC is MSErr'); + end else + if (Fact1Combo.ItemIndex = 0) and (Fact2Combo.ItemIndex = 0) and (Fact3Combo.ItemIndex = 1) then + begin + lReport.Add('Note: Error term for A is MSAxC'); + lReport.Add('Note: Error term for B is MSBxC'); + lReport.Add('Note: Error term for C is MSErr'); + lReport.Add('Note: Error term for AxB is MSAxBxC'); + lReport.Add('Note: Error term for AxC is MSErr'); + lReport.Add('Note: Error term for BxC is MSErr'); + lReport.Add('Note: Error term for AxBxC is MSErr'); + end else + if (Fact1Combo.ItemIndex = 0) and (Fact2Combo.ItemIndex = 1) and (Fact3Combo.ItemIndex = 1) then + begin + lReport.Add('Note: Error term for A is MSAxC + MSAxB - MSAxBxC'); + lReport.Add('Note: Error term for B is MSBxC'); + lReport.Add('Note: Error term for C is MSBxC'); + lReport.Add('Note: Error term for AxB is MSAxBxC'); + lReport.Add('Note: Error term for AxC is MSAxBxC'); + lReport.Add('Note: Error term for BxC is MSErr'); + lReport.Add('Note: Error term for AxBxC is MSErr'); + end else + if (Fact1Combo.ItemIndex = 1) and (Fact2Combo.ItemIndex = 0) and (Fact3Combo.ItemIndex = 1) then + begin + lReport.Add('Note: Error term for A is MSAxC'); + lReport.Add('Note: Error term for B is MSBxC + MSAxB - MSAxBxC'); + lReport.Add('Note: Error term for C is MSAxC'); + lReport.Add('Note: Error term for AxB is MSAxBxC'); + lReport.Add('Note: Error term for AxC is MSErr'); + lReport.Add('Note: Error term for BxC is MSAxBxC'); + lReport.Add('Note: Error term for AxBxC is MSErr'); + end else + if (Fact1Combo.ItemIndex = 1) and (Fact2Combo.ItemIndex = 1) and (Fact3Combo.ItemIndex = 0) then + begin + lReport.Add('Note: Error term for A is MSAxB'); + lReport.Add('Note: Error term for B is MSAxB'); + lReport.Add('Note: Error term for C is MSBxC + MSAxC - MSAxBxC'); + lReport.Add('Note: Error term for AxB is MSErr'); + lReport.Add('Note: Error term for AxC is MSAxBxC'); + lReport.Add('Note: Error term for BxC is MSAxBxC'); + lReport.Add('Note: Error term for AxBxC is MSErr'); + end; + + for i := 1 to 10 do + if not OKTerms[i] then + problem := true; + + if problem then + begin + lReport.Add(''); + lReport.Add('An error occurred due to either an estimate of MS being negative'); + lReport.Add('or the degrees of freedom being zero. This may occur in a design'); + lReport.Add('with random factors using the expected values for an exact F-test.'); + lReport.Add('Quasi-F statistics may be employed where this problem exists. See'); + lReport.Add('Winer, B.J., "Statistical Principles in Experimental Design, 1962'); + lReport.Add('Section 5.15, pages 199-202 and Glass, G.V. and Stanley, J.C.,'); + lReport.Add('1970, Section 18.10, pages 481-482.'); + end; + + lReport.Add(''); + lReport.Add(DIVIDER_AUTO); + lReport.Add(''); + lReport.Add('DESCRIPTIVE STATISTICS'); + lReport.Add(''); + lReport.Add('-------------------------------------------------------------'); + lReport.Add('GROUP ROW COL SLICE N MEAN VARIANCE STD.DEV.'); + lReport.Add('----- --- --- ----- ----- -------- ---------- --------'); + + // Display cell means, variances, standard deviations + groupsize := NCnt[1, 1, 1]; + equal_grp := true; + MaxVar := -1E308; + MinVar := 1E308; + sumVars := 0.0; + sumFreqLogVar := 0.0; + sumDFRecip := 0.0; + for i := 0 to NoGrpsA-1 do + begin + for j := 0 to NoGrpsB-1 do begin - XBar := wsum[i,j,k] / ncnt[i,j,k]; - V := wx2[i,j,k] - ( (wsum[i,j,k] * wsum[i,j,k]) / ncnt[i,j,k]); - V := V / (ncnt[i,j,k] - 1.0); - S := sqrt(V); - sumvars := sumvars + V; - if V > MaxVar then MaxVar := V; - if V < MinVar then MinVar := V; - sumDFrecip := sumDFrecip + (1.0 / (ncnt[i,j,k] - 1.0)); - sumfreqlogvar := sumfreqlogvar + ((ncnt[i,j,k] - 1.0) * ln(V)); - if ncnt[i,j,k] <> groupsize then equal_grp := false; - AReport.Add('Cell %3d %3d %3d %3d %8.3f %8.3f %8.3f', [minf1+i, minf2+j, minf3+k, ncnt[i,j,k], XBar, V, S]); + for k := 0 to NoGrpsC-1 do + begin + XBar := WSum[i, j, k] / NCnt[i, j, k]; + V := (WX2[i, j, k] - sqr(WSum[i, j, k]) / NCnt[i, j, k]) / (NCnt[i, j, k] - 1); + S := sqrt(V); + sumVars := sumVars + V; + if V > MaxVar then MaxVar := V; + if V < MinVar then MinVar := V; + sumDFRecip := sumDFRecip + (1.0 / (NCnt[i, j, k] - 1)); + sumfreqLogVar := sumFreqLogVar + (NCnt[i, j, k] - 1) * ln(V); + if NCnt[i, j, k] <> groupsize then equal_grp := false; + lReport.Add('Cell %3d %3d %5d %5d %8.3f %10.3f %8.3f', [MinF1+i, MinF2+j, MinF3+k, NCnt[i, j, k], XBar, V, S]); + end; end; end; - end; - //Display Row means, variances, standard deviations - for i := 0 to NoGrpsA-1 do - begin - XBar := RowSums[i] / RowCount[i]; -// OrdMeansA[i] := XBar; - RowSS := 0.0; + //Display Row means, variances, standard deviations + for i := 0 to NoGrpsA-1 do + begin + XBar := RowSums[i] / RowCount[i]; + RowSS := 0.0; + for j := 0 to NoGrpsB-1 do + for k := 0 to NoGrpsC-1 do RowSS := RowSS + WX2[i, j, k]; + V := (RowSS - sqr(RowSums[i]) / RowCount[i]) / (RowCount[i] - 1); + S := sqrt(V); + lReport.Add('Row %3d %5d %8.3f %10.3f %8.3f', [MinF1+i, RowCount[i], xBar, V, s]); + end; + + //Display means, variances and standard deviations for columns for j := 0 to NoGrpsB-1 do - for k := 0 to NoGrpsC-1 do RowSS := RowSS + wx2[i,j,k]; - V := RowSS - (RowSums[i] * RowSums[i] / RowCount[i]); - V := V / (RowCount[i] - 1.0); - S := sqrt(V); - AReport.Add('Row %3d %3d %8.3f %8.3f %8.3f', [minf1+i, RowCount[i], XBar, V, S]); + begin + XBar := ColSums[j] / ColCount[j]; + ColSS := 0.0; + for i := 0 to NoGrpsA-1 do + for k := 0 to NoGrpsC-1 do ColSS := ColSS + WX2[i, j, k]; + V := (ColSS - sqr(ColSums[j]) / ColCount[j]) / (ColCount[j] - 1); + S := sqrt(V); + lReport.Add('Col %3d %5d %8.3f %10.3f %8.3f', [MinF2+j, ColCount[j], xBar, V, S]); + end; + + //Display means, variances and standard deviations for slices + for k := 0 to NoGrpsC-1 do + begin + XBar := SlcSums[k] / SlcCount[k]; + SlcSS := 0.0; + for i := 0 to NoGrpsA-1 do + for j := 0 to NoGrpsB-1 do SlcSS := SlcSS + WX2[i, j, k]; + V := (SlcSS - sqr(SlcSums[k]) / SlcCount[k]) / (SlcCount[k] - 1); + S := sqrt(V); + lReport.Add('Slice %5d %5d %8.3f %10.3f %8.3f', [MinF3+k, SlcCount[k], xBar, V,S]); + end; + + lReport.Add('-------------------------------------------------------------'); + lReport.Add('TOTAL %5d %8.3f %10.3f %8.3f', [N, MeanDep, MSDep, sqrt(MSDep)]); + lReport.Add('-------------------------------------------------------------'); + lReport.Add(''); + + c := 1.0 + (1.0 / (3.0 * NoGrpsA * NoGrpsB * NoGrpsC - 1)) * (sumDFrecip - (1.0 / DFErr)); + bartlett := (2.303 / c) * ((DFErr * ln(MSErr)) - SumFreqLogVar); + chiProb := ChiSquaredProb(bartlett, round(NoGrpsA * NoGrpsB * NoGrpsC - 1)); + cochran := MaxVar / SumVars; + hartley := MaxVar / MinVar; + + lReport.Add(DIVIDER); + lReport.Add(''); + lReport.Add('TESTS FOR HOMOGENEITY OF VARIANCE'); + lReport.Add(''); + lReport.Add('Hartley Fmax test statistic: %8.3f with %d and %d degrees of freedom.', [hartley, NoGrpsA*NoGrpsB, groupsize-1]); + lReport.Add('Cochran C statistic: %8.3f with %d and %d degrees of freedom.', [cochran, NoGrpsA*NoGrpsB, groupsize-1]); + lReport.Add('Bartlett Chi-square statistic: %8.3f with %d degrees of freedom; probability > value: %.3f', [bartlett, NoGrpsA*NoGrpsB-1, 1-chiProb]); + + FReportFrame.DisplayReport(lReport); + finally + lReport.Free; end; - - //Display means, variances and standard deviations for columns - for j := 0 to NoGrpsB-1 do - begin - XBar := ColSums[j] / ColCount[j]; -// OrdMeansB[j] := XBar; - ColSS := 0.0; - for i := 0 to NoGrpsA-1 do - for k := 0 to NoGrpsC-1 do ColSS := ColSS + wx2[i,j,k]; - V := ColSS - (ColSums[j] * ColSums[j] / ColCount[j]); - V := V / (ColCount[j] - 1.0); - S := sqrt(V); - AReport.Add('Col %3d %3d %8.3f %8.3f %8.3f', [minf2+j, ColCount[j], XBar, V, S]); - end; - - //Display means, variances and standard deviations for slices - for k := 0 to NoGrpsC-1 do - begin - XBar := SlcSums[k] / SlcCount[k]; -// OrdMeansC[k] := XBar; - SlcSS := 0.0; - for i := 0 to NoGrpsA-1 do - for j := 0 to NoGrpsB-1 do SlcSS := SlcSS + wx2[i,j,k]; - V := SlcSS - (SlcSums[k] * SlcSums[k] / SlcCount[k]); - V := V / (SlcCount[k] - 1.0); - S := sqrt(V); - AReport.Add('Slice %3d %3d %8.3f %8.3f %8.3f', [minf3+k, SlcCount[k], XBar, V, S]); - end; - - AReport.ADd('TOTAL %3d %8.3f %8.3f %8.3f', [N, MeanDep, MSDep, sqrt(MSDep)]); - AReport.Add(''); - AReport.Add(''); - - c := 1.0 + (1.0 / (3.0 * NoGrpsA * NoGrpsB * NoGrpsC - 1.0)) * (sumDFrecip - (1.0 / DFErr)); - bartlett := (2.303 / c) * ((DFErr * ln(MSErr)) - sumfreqlogvar); - chiprob := chisquaredprob(bartlett,round(NoGrpsA * NoGrpsB * NoGrpsC - 1)); - cochran := maxvar / sumvars; - hartley := maxvar / minvar; - AReport.Add(DIVIDER); - AReport.Add('TESTS FOR HOMOGENEITY OF VARIANCE'); - AReport.Add(DIVIDER_SMALL); - AReport.Add('Hartley Fmax test statistic: %8.2f with deg.s freedom: %d and %d.', [hartley, NoGrpsA*NoGrpsB, groupsize-1]); - AReport.Add('Cochran C statistic: %8.2f with deg.s freedom: %d and %d.', [cochran, NoGrpsA*NoGrpsB, groupsize - 1]); - AReport.Add('Bartlett Chi-square statistic: %8.2f with %d D.F. Prob. larger: %.3f', [bartlett, NoGrpsA*NoGrpsB - 1, 1.0 - chiprob]); - AReport.Add(DIVIDER); end; + +{ Determines from the ItemIndex of the FChartCombobox which factors will be + plotted along x and as y index, and for which C index the interactions will + be calculated. } +procedure TBlksAnovaForm.GetDataIndices(out ix, iy, iz: Integer); +var + index, i1, i2, i3: Integer; +begin + index := FChartComboBox.ItemIndex; + i1 := 3; + i2 := i1 + NF3Cells; + i3 := i2 + NF3Cells; + if (index >= i1) and (index < i3) then + begin + if index < i2 then + begin + ix := 1; + iy := 2; + iz := index - i1; + end else + begin + ix := 2; + iy := 1; + iz := index - i2; + end; + exit; + end; + + i1 := i3; + i2 := i1 + NF2Cells; + i3 := i2 + NF2Cells; + if (index >= i1) and (index < i3) then + begin + if index < i2 then + begin + ix := 1; + iy := 3; + iz := index - i1; + end else + begin + ix := 3; + iy := 1; + iz := index - i2; + end; + exit; + end; + + i1 := i3; + i2 := i1 + NF1Cells; + i3 := i2 + NF1Cells; + if (index >= i1) and (index < i3) then + begin + if index < i2 then + begin + ix := 2; + iy := 3; + iz := index - i1; + end else + begin + ix := 3; + iy := 2; + iz := index - i2; + end; + end; +end; + + +{ OnChange event handler for the ChartCombobox. Displays the chart associated + with the current ItemIndex. } +procedure TBlksAnovaForm.SelectThreeWayPlot(Sender: TObject); +var + i, j, k, idx, ix, iy, iz: 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 means vs factor C + FSeries.ListSource.YCount := 1; + for i := 0 to NF3Cells-1 do + FSeries.AddXY(minF3 + i, SlcSums[i] / SlcCount[i], IntToStr(MinF3 + i)); + FChartFrame.SetXTitle(Factor3Edit.Text + ' codes'); + FChartFrame.SetTitle(Factor3Edit.Text); + end; + else + GetDataIndices(ix, iy,iz); + if (ix = 1) and (iy = 2) then + begin + 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, wsum[i,j,iz] / ncnt[i,j,iz]); + end; + FChartFrame.SetTitle(Format('Factor "%s" x Factor "%s"' + LineEnding + '"%s" = %d', [ + Factor1Edit.Text, Factor2Edit.Text, Factor3Edit.Text, MinF3 + iz])); + 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 + else + if (ix = 2) and (iy = 1) then + begin + 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, wsum[i, j, iz] / ncnt[i, j, iz]); + end; + FChartFrame.SetTitle(Format('Factor "%s" x Factor "%s"' + LineEnding + '"%s" = %d', [ + Factor1Edit.Text, Factor2Edit.Text, Factor3Edit.Text, MinF3 + iz])); + 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 + else + if (ix = 1) and (iy = 3) then + begin + FSeries.ListSource.YCount := NF3Cells; + for i := 0 to NF1Cells-1 do + begin + idx := FSeries.AddXY(minF1 + i, NaN, IntToStr(minF1 + i)); + item := FSeries.Source.Item[idx]; + for k := 0 to NF3Cells-1 do + item^.SetY(k, wsum[i, iz, k] / ncnt[i, iz, k]); + end; + FChartFrame.SetTitle(Format('Factor "%s" x Factor "%s"' + LineEnding + '"%s" = %d', [ + Factor1Edit.Text, Factor3Edit.Text, Factor2Edit.Text, MinF2 + iz])); + FChartFrame.SetXTitle(Factor1Edit.Text + ' codes'); + for k := 0 to NF3Cells-1 do + with TChartStyle(FStyles.styles.Add) do + begin + Brush.Color := DATA_COLORS[k mod Length(DATA_COLORS)]; + UseBrush := True; + Text := Format('%s = %s', [Factor3Edit.Text, IntToStr(MinF3 + k)]); + end; + end + else + if (ix = 3) and (iy = 1) then + begin + FSeries.ListSource.YCount := NF1Cells; + for k := 0 to NF3Cells-1 do + begin + idx := FSeries.AddXY(minF3 + k, NaN, IntToStr(minF3 + k)); + item := FSeries.Source.Item[idx]; + for i := 0 to NF1Cells-1 do + item^.SetY(i, wsum[i, iz, k] / ncnt[i, iz, k]); + end; + FChartFrame.SetTitle(Format('Factor "%s" x Factor "%s"' + LineEnding + '"%s" = %d', [ + Factor1Edit.Text, Factor3Edit.Text, Factor2Edit.Text, MinF2 + iz])); + FChartFrame.SetXTitle(Factor3Edit.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 + else + if (ix = 2) and (iy = 3) then + begin + FSeries.ListSource.YCount := NF3Cells; + for j := 0 to NF2Cells-1 do + begin + idx := FSeries.AddXY(minF2 + j, NaN, IntToStr(minF2 + j)); + item := FSeries.Source.Item[idx]; + for k := 0 to NF3Cells-1 do + item^.SetY(k, wsum[iz, j, k] / ncnt[iz, j, k]); + end; + FChartFrame.SetTitle(Format('Factor "%s" x Factor "%s"' + LineEnding + '"%s" = %d', [ + Factor2Edit.Text, Factor3Edit.Text, Factor1Edit.Text, MinF1 + iz])); + FChartFrame.SetXTitle(Factor2Edit.Text + ' codes'); + for k := 0 to NF3Cells-1 do + with TChartStyle(FStyles.styles.Add) do + begin + Brush.Color := DATA_COLORS[k mod Length(DATA_COLORS)]; + UseBrush := True; + Text := Format('%s = %s', [Factor3Edit.Text, IntToStr(MinF3 + k)]); + end; + end + else + if (ix = 3) and (iy = 2) then + begin + FSeries.ListSource.YCount := NF2Cells; + for k := 0 to NF3Cells-1 do + begin + idx := FSeries.AddXY(minF3 + k, NaN, IntToStr(minF3 + k)); + item := FSeries.Source.Item[idx]; + for j := 0 to NF2Cells-1 do + item^.SetY(j, wsum[iz, j, k] / ncnt[iz, j, k]); + end; + FChartFrame.SetTitle(Format('Factor "%s" x Factor "%s"' + LineEnding + '"%s" = %d', [ + Factor2Edit.Text, Factor3Edit.Text, Factor1Edit.Text, MinF1 + iz])); + FChartFrame.SetXTitle(Factor3Edit.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 else + raise Exception.Create('Fatal error in SelectThreeWayPlot'); + end; + + 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.ThreeWayPlot; +begin + { + if not ShowPlotsChk.Checked then + begin + ChartPage.TabVisible := false; + exit; + end; + } + FChartFrame.Clear; // this destroys the series + FChartFrame.SetYTitle('Means'); + 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; + } + PopulateChartCombobox(true); + FChartCombobox.OnChange := @SelectThreeWayPlot; + SelectThreeWayPlot(nil); + + ChartPage.TabVisible := true; +end; + +(* procedure TBlksAnovaForm.ThreeWayPlot; var i, j, k : integer; @@ -2345,7 +2520,7 @@ begin GraphFrm.Xpoints := nil; GraphFrm.Ypoints := nil; end; - +*) procedure TBlksAnovaForm.TwoWayContrasts; var @@ -2377,8 +2552,7 @@ begin begin RowSS := 0.0; for j := 0 to NoGrpsB-1 do RowSS := RowSS + vars[i,j]; - variances[i] := RowSS - (RowSums[i] * RowSums[i] / RowCount[i]); - variances[i] := variances[i] / (RowCount[i] - 1.0); + variances[i] := (RowSS - sqr(RowSums[i]) / RowCount[i]) / (RowCount[i] - 1); end; lReport.Add('COMPARISONS AMONG ROWS'); @@ -2386,7 +2560,7 @@ begin // Get smallest group size value := 1e308; for i := 0 to NF1Cells-1 do - if RowCount[i] < value then value := RowCount[i]; + if RowCount[i] < value then value := RowCount[i]; if ScheffeChk.Checked then ScheffeTest(MSErr, RowSums, RowCount, minf1, maxf1, N, posthocAlpha, lReport); @@ -2418,8 +2592,7 @@ begin ColSS := 0.0; for i := 0 to NoGrpsA-1 do ColSS := ColSS + vars[i,j]; - variances[j] := ColSS - (ColSums[j] * ColSums[j] / ColCount[j]); - variances[j] := variances[j] / (ColCount[j] - 1.0); + variances[j] := (ColSS - sqr(ColSums[j]) / ColCount[j]) / (ColCount[j] - 1); end; if lReport.Count <> 0 then @@ -2472,7 +2645,7 @@ begin end; 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 ScheffeChk.Checked then @@ -2553,273 +2726,361 @@ begin end; -procedure TBlksAnovaForm.ThreeWayContrasts(AReport: TStrings); +procedure TBlksAnovaForm.ThreeWayContrasts; var + lReport: TStrings; i, j, k: integer; value: double; variances: DblDyneVec = nil; RowSS, ColSS, SlcSS: double; + totalCells: Integer; begin - if (ScheffeChk.Checked = false) and (TukeyHSDChk.Checked = false) and - (TukeyBChk.Checked = false) and (TukeyKramerChk.Checked = false) and - (NewmanKeulsChk.Checked = false) and (BonferroniChk.Checked = false) and - (OrthoContrastsChk.Checked = false) then exit; + 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; - SetLength(variances,totcells); + totalCells := NF1Cells + NF2Cells + NF3Cells; + SetLength(variances, totalCells); - // Do row comparisons - if (NF1cells > 2) and (ProbF1 < allAlpha) then - begin - for i := 0 to NoGrpsA-1 do - begin - RowSS := 0.0; - for j := 0 to NoGrpsB-1 do - for k := 0 to NoGrpsC-1 do RowSS := RowSS + wx2[i,j,k]; - variances[i] := RowSS - (RowSums[i] * RowSums[i] / RowCount[i]); - variances[i] := variances[i] / (RowCount[i] - 1.0); - end; - AReport.Add(''); - AReport.Add('COMPARISONS AMONG ROWS'); - // get smallest group size - value := 1e20; - for i := 0 to NF1cells-1 do if RowCount[i] < value then value := RowCount[i]; - if ScheffeChk.Checked then - ScheffeTest(MSErr, RowSums, RowCount, minf1, maxf1, N, posthocAlpha, AReport); - if TukeyHSDChk.Checked and equal_grp then - Tukey(MSErr, DFErr, value, RowSums, RowCount, minf1, maxf1, posthocAlpha, AReport); - if TukeyBChk.Checked and equal_grp then - TukeyBTest(MSErr, DFErr, RowSums, RowCount, minf1, maxf1, value, posthocAlpha, AReport); - if TukeyKramerChk.Checked and equal_grp then - Tukey_Kramer(MSErr, DFErr, value, RowSums, RowCount, minf1, maxf1, posthocAlpha, AReport); - if NewmanKeulsChk.Checked and equal_grp then - Newman_Keuls(MSErr, DFErr, value, RowSums, RowCount, minf1, maxf1, posthocAlpha, AReport); - if BonferroniChk.Checked then - Bonferroni(RowSums, RowCount, variances, minf1, maxf1, posthocAlpha, AReport); - if OrthoContrastsChk.Checked then - Contrasts(MSErr, DFErr, RowSums, RowCount, minf1, maxf1, allAlpha, postHocAlpha, AReport); - end; + lReport := TStringList.Create; + try + // Do row comparisons + if (NF1Cells > 2) and (ProbF1 < allAlpha) then + begin + for i := 0 to NoGrpsA-1 do + begin + RowSS := 0.0; + for j := 0 to NoGrpsB-1 do + for k := 0 to NoGrpsC-1 do RowSS := RowSS + wx2[i,j,k]; + variances[i] := (RowSS - sqr(RowSums[i]) / RowCount[i]) / (RowCount[i] - 1); + end; + lReport.Add('COMPARISONS AMONG ROWS'); - // Do column comparisons - if (NF2cells > 2) and (ProbF2 < allAlpha) then - begin - for j := 0 to NoGrpsB-1 do - begin - ColSS := 0.0; - for i := 0 to NoGrpsA-1 do - for k := 0 to NoGrpsC-1 do ColSS := ColSS + wx2[i,j,k]; - variances[j] := ColSS - (ColSums[j] * ColSums[j] / ColCount[j]); - variances[j] := variances[j] / (ColCount[j] - 1.0); - end; - AReport.Add(''); - AReport.Add('COMPARISONS AMONG COLUMNS'); - value := 1e308; - for i := 0 to NF2cells-1 do - if ColCount[i] < value then value := ColCount[i]; - if ScheffeChk.Checked then - ScheffeTest(MSErr, ColSums, ColCount, minf2, maxf2, N, posthocAlpha, AReport); - if TukeyHSDChk.Checked and equal_grp then - Tukey(MSErr, DFErr, value, ColSums, ColCount, minf2, maxf2, posthocAlpha, AReport); - if TukeyBChk.Checked and equal_grp then - TukeyBTest(MSErr, DFErr, ColSums, ColCount, minf2, maxf2, value, posthocAlpha, AReport); - if TukeyKramerChk.Checked and equal_grp then - Tukey_Kramer(MSErr, DFErr, value, ColSums, ColCount, minf2, maxf2, posthocAlpha, AReport); - if NewmanKeulsChk.Checked and equal_grp then - Newman_Keuls(MSErr, DFErr, value, ColSums, ColCount, minf2, maxf2, posthocAlpha, AReport); - if BonferroniChk.Checked then - Bonferroni(ColSums, ColCount, variances, minf2, maxf2, posthocAlpha, AReport); - if OrthoContrastsChk.Checked then - Contrasts(MSErr, DFErr, ColSums, ColCount, minf2, maxf2, allAlpha, posthocAlpha, AReport); - end; + // get smallest group size + value := 1e20; + for i := 0 to NF1Cells-1 do + if RowCount[i] < value then value := RowCount[i]; - // Do slice comparisons - if (NF3cells > 2) and (ProbF3 < allAlpha) then - begin + if ScheffeChk.Checked then + ScheffeTest(MSErr, RowSums, RowCount, MinF1, MaxF1, N, posthocAlpha, lReport); + + if TukeyHSDChk.Checked and equal_grp then + Tukey(MSErr, DFErr, value, RowSums, RowCount, MinF1, MaxF1, posthocAlpha, lReport); + + if TukeyBChk.Checked and equal_grp then + TukeyBTest(MSErr, DFErr, RowSums, RowCount, MinF1, MaxF1, value, posthocAlpha, lReport); + + if TukeyKramerChk.Checked and equal_grp then + Tukey_Kramer(MSErr, DFErr, value, RowSums, RowCount, MinF1, MaxF1, posthocAlpha, lReport); + + if NewmanKeulsChk.Checked and equal_grp then + Newman_Keuls(MSErr, DFErr, value, RowSums, RowCount, MinF1, MaxF1, posthocAlpha, lReport); + + if BonferroniChk.Checked then + Bonferroni(RowSums, RowCount, variances, MinF1, MaxF1, posthocAlpha, lReport); + + if OrthoContrastsChk.Checked then + Contrasts(MSErr, DFErr, RowSums, RowCount, MinF1, MaxF1, allAlpha, postHocAlpha, lReport); + end; + + // Do column comparisons + if (NF2Cells > 2) and (ProbF2 < allAlpha) then + begin + for j := 0 to NoGrpsB-1 do + begin + ColSS := 0.0; + for i := 0 to NoGrpsA-1 do for k := 0 to NoGrpsC-1 do - begin - SlcSS := 0.0; - for i := 0 to NoGrpsA-1 do - for j := 0 to NoGrpsB-1 do SlcSS := SlcSS + wx2[i,j,k]; - variances[k] := SlcSS - (SlcSums[k] * SlcSums[k] / SlcCount[k]); - variances[k] := variances[k] / (SlcCount[k] - 1.0); - end; - AReport.Add(''); - AReport.Add('COMPARISONS AMONG SLICES'); - value := 1e308; - for i := 0 to NF3cells-1 do - if SlcCount[i] < value then value := SlcCount[i]; - if ScheffeChk.Checked then - ScheffeTest(MSErr, SlcSums, SlcCount, minf3, maxf3, N, posthocAlpha, AReport); - if TukeyHSDChk.Checked and equal_grp then - Tukey(MSErr, DFErr, value, SlcSums, SlcCount, minf3, maxf3, posthocAlpha, AReport); - if TukeyBChk.Checked and equal_grp then - TukeyBTest(MSErr, DFErr, SlcSums, SlcCount, minf3, maxf3, value, posthocAlpha, AReport); - if TukeyKramerChk.Checked and equal_grp then - Tukey_Kramer(MSErr, DFErr, value, SlcSums, SlcCount, minf3, maxf3, posthocAlpha, AReport); - if NewmanKeulsChk.Checked and equal_grp then - Newman_Keuls(MSErr, DFErr, value, SlcSums, SlcCount, minf3, maxf3, posthocAlpha, AReport); - if BonferroniChk.Checked then - Bonferroni(SlcSums, SlcCount, variances, minf3, maxf3, posthocAlpha, AReport); - if OrthoContrastsChk.Checked then - Contrasts(MSErr, DFErr, SlcSums, SlcCount, minf3, maxf3, allAlpha, posthocAlpha, AReport); - end; + ColSS := ColSS + WX2[i,j,k]; + variances[j] := (ColSS - sqr(ColSums[j]) / ColCount[j]) / (ColCount[j] - 1); + end; - // do simple effects for columns within each row - if (ProbF1f2 < allAlpha) then - begin - AReport.Add(''); - AReport.Add('COMPARISONS AMONG COLUMNS WITHIN EACH ROW'); - for i := 0 to NF1cells-1 do - begin - AReport.Add(''); - AReport.Add('ROW %d COMPARISONS',[i+1]); - // move cell sums and counts to cellsums and cellcnts - for j := 0 to NF2cells-1 do - begin - for k := 0 to NF3cells-1 do - begin - cellsums[j] := wsum[i,j,k]; - cellcnts[j] := ncnt[i,j,k]; - cellvars[j] := wx2[i,j,k]; - end; - end; - value := 1e308; - for j := 0 to NF2cells-1 do - if cellcnts[j] < value then value := cellcnts[j]; - if ScheffeChk.Checked then - ScheffeTest(MSErr, cellsums, cellcnts, minf2, maxf2, N, posthocAlpha, AReport); - if TukeyHSDChk.Checked and equal_grp then - Tukey(MSErr, DFErr, value, cellsums, cellcnts, minf2, maxf2, posthocAlpha, AReport); - if TukeyBChk.Checked and equal_grp then - TukeyBTest(MSErr, DFErr, cellsums, cellcnts, minf2, maxf2, value, posthocAlpha, AReport); - if TukeyKramerChk.Checked and equal_grp then - Tukey_Kramer(MSErr, DFErr, value, cellsums, cellcnts, minf2, maxf2, posthocAlpha, AReport); - if NewmanKeulsChk.Checked and equal_grp then - Newman_Keuls(MSErr, DFErr, value, cellsums, cellcnts, minf2, maxf2, posthocAlpha, AReport); - if BonferroniChk.Checked then - Bonferroni(cellsums, cellcnts, cellvars, minf2, maxf2, posthocAlpha, AReport); - if OrthoContrastsChk.Checked then - Contrasts(MSErr, DFErr, cellsums, cellcnts, minf2, maxf2, allAlpha, posthocAlpha, AReport); - end; - end; + if lReport.Count > 0 then + lReport.Add(''); + lReport.Add('COMPARISONS AMONG COLUMNS'); + value := 1e308; + for i := 0 to NF2Cells-1 do + if ColCount[i] < value then value := ColCount[i]; - // do simple effects for rows within each column - if (ProbF1f2 < allAlpha) then - begin - AReport.Add(''); - AReport.Add('COMPARISONS AMONG ROWS WITHIN EACH COLUMN'); - for j := 0 to NF2cells-1 do - begin - AReport.Add(''); - AReport.Add('COLUMN %d COMPARISONS', [j+1]); - // move cell sums and counts to cellsums and cellcnts - for i := 0 to NF1cells-1 do - begin - for k := 0 to NF3cells-1 do - begin - cellsums[i] := wsum[i,j,k]; - cellcnts[i] := ncnt[i,j,k]; - cellvars[i] := wx2[i,j,k]; - end; - end; - value := 1e308; - for i := 0 to NF1cells-1 do - if cellcnts[j] < value then value := cellcnts[j]; - if ScheffeChk.Checked then - ScheffeTest(MSErr, cellsums, cellcnts, minf1, maxf1, N, posthocAlpha, AReport); - if TukeyHSDChk.Checked and equal_grp then - Tukey(MSErr, DFErr, value, cellsums, cellcnts, minf1, maxf1, posthocAlpha, AReport); - if TukeyBChk.Checked and equal_grp then - TukeyBTest(MSErr, DFErr, cellsums, cellcnts, minf1, maxf1, value, posthocAlpha, AReport); - if TukeyKramerChk.Checked and equal_grp then - Tukey_Kramer(MSErr, DFErr, value, cellsums, cellcnts, minf1, maxf1, posthocAlpha, AReport); - if NewmanKeulsChk.Checked and equal_grp then - Newman_Keuls(MSErr, DFErr, value, cellsums, cellcnts, minf1, maxf1, posthocAlpha, AReport); - if BonferroniChk.Checked then - Bonferroni(cellsums, cellcnts, cellvars, minf1, maxf1, posthocAlpha, AReport); - if OrthoContrastsChk.Checked then - Contrasts(MSErr, DFErr, cellsums, cellcnts, minf1, maxf1, allAlpha, posthocAlpha, AReport); - end; - end; + if ScheffeChk.Checked then + ScheffeTest(MSErr, ColSums, ColCount, MinF2, MaxF2, N, posthocAlpha, lReport); - // do simple effects for columns within each slice - if (ProbF2F3 < allAlpha) then - begin - AReport.Add(''); - AReport.Add('COMPARISONS AMONG COLUMNS WITHIN EACH SLICE'); - for k := 0 to NF3cells-1 do - begin - AReport.Add(''); - AReport.Add('SLICE %d COMPARISONS',[k+1]); - // move cell sums and counts to cellsums and cellcnts - for j := 0 to NF2cells-1 do - begin - for i := 0 to NF1cells-1 do - begin - cellsums[j] := wsum[i,j,k]; - cellcnts[j] := ncnt[i,j,k]; - cellvars[j] := wx2[i,j,k]; - end; - end; - value := 1e20; - for j := 1 to NF2cells do if cellcnts[j] < value then value := cellcnts[j]; - if ScheffeChk.Checked then - ScheffeTest(MSErr, cellsums, cellcnts, minf2, maxf2, N, posthocAlpha, AReport); - if TukeyHSDChk.Checked and equal_grp then - Tukey(MSErr, DFErr, value, cellsums, cellcnts, minf2, maxf2, posthocAlpha, AReport); - if TukeyBChk.Checked and equal_grp then - TukeyBTest(MSErr, DFErr, cellsums, cellcnts, minf2, maxf2, value, posthocAlpha, AReport); - if TukeyKramerChk.Checked and equal_grp then - Tukey_Kramer(MSErr, DFErr, value, cellsums, cellcnts, minf2, maxf2, posthocAlpha, AReport); - if NewmanKeulsChk.Checked and equal_grp then - Newman_Keuls(MSErr, DFErr, value, cellsums, cellcnts, minf2, maxf2, posthocAlpha, AReport); - if BonferroniChk.Checked then - Bonferroni(cellsums, cellcnts, cellvars, minf2, maxf2, posthocAlpha, AReport); - if OrthoContrastsChk.Checked then - Contrasts(MSErr, DFErr, cellsums, cellcnts, minf2, maxf2, allAlpha, posthocAlpha, AReport); - end; - end; + if TukeyHSDChk.Checked and equal_grp then + Tukey(MSErr, DFErr, value, ColSums, ColCount, MinF2, MaxF2, posthocAlpha, lReport); - // do simple effects for rows within each slice - if (ProbF1F3 < allAlpha) then - begin - AReport.Add(''); - AReport.Add('COMPARISONS AMONG ROWS WITHIN EACH SLICE'); - for k := 0 to NF3cells-1 do + if TukeyBChk.Checked and equal_grp then + TukeyBTest(MSErr, DFErr, ColSums, ColCount, MinF2, MaxF2, value, posthocAlpha, lReport); + + if TukeyKramerChk.Checked and equal_grp then + Tukey_Kramer(MSErr, DFErr, value, ColSums, ColCount, MinF2, MaxF2, posthocAlpha, lReport); + + if NewmanKeulsChk.Checked and equal_grp then + Newman_Keuls(MSErr, DFErr, value, ColSums, ColCount, MinF2, MaxF2, posthocAlpha, lReport); + + if BonferroniChk.Checked then + Bonferroni(ColSums, ColCount, variances, MinF2, MaxF2, posthocAlpha, lReport); + + if OrthoContrastsChk.Checked then + Contrasts(MSErr, DFErr, ColSums, ColCount, MinF2, MaxF2, allAlpha, posthocAlpha, lReport); + end; + + // Do slice comparisons + if (NF3Cells > 2) and (ProbF3 < allAlpha) then + begin + for k := 0 to NoGrpsC-1 do + begin + SlcSS := 0.0; + for i := 0 to NoGrpsA-1 do + for j := 0 to NoGrpsB-1 do + SlcSS := SlcSS + WX2[i,j,k]; + variances[k] := (SlcSS - sqr(SlcSums[k]) / SlcCount[k]) / (SlcCount[k] - 1); + end; + + if lReport.Count > 0 then + lReport.Add(''); + lReport.Add('COMPARISONS AMONG SLICES'); + + value := 1e308; + for i := 0 to NF3Cells-1 do + if SlcCount[i] < value then value := SlcCount[i]; + + if ScheffeChk.Checked then + ScheffeTest(MSErr, SlcSums, SlcCount, MinF3, MaxF3, N, posthocAlpha, lReport); + + if TukeyHSDChk.Checked and equal_grp then + Tukey(MSErr, DFErr, value, SlcSums, SlcCount, MinF3, MaxF3, posthocAlpha, lReport); + + if TukeyBChk.Checked and equal_grp then + TukeyBTest(MSErr, DFErr, SlcSums, SlcCount, MinF3, MaxF3, value, posthocAlpha, lReport); + + if TukeyKramerChk.Checked and equal_grp then + Tukey_Kramer(MSErr, DFErr, value, SlcSums, SlcCount, MinF3, MaxF3, posthocAlpha, lReport); + + if NewmanKeulsChk.Checked and equal_grp then + Newman_Keuls(MSErr, DFErr, value, SlcSums, SlcCount, MinF3, MaxF3, posthocAlpha, lReport); + + if BonferroniChk.Checked then + Bonferroni(SlcSums, SlcCount, variances, MinF3, MaxF3, posthocAlpha, lReport); + + if OrthoContrastsChk.Checked then + Contrasts(MSErr, DFErr, SlcSums, SlcCount, MinF3, MaxF3, allAlpha, posthocAlpha, lReport); + end; + + // Do simple effects for columns within each row + if (ProbF1f2 < allAlpha) then + begin + if lReport.Count > 0 then + lReport.Add(''); + lReport.Add('COMPARISONS AMONG COLUMNS WITHIN EACH ROW'); + for i := 0 to NF1cells-1 do + begin + lReport.Add(''); + lReport.Add('ROW %d COMPARISONS',[i+1]); + + // move cell sums and counts to cellsums and cellcnts + for j := 0 to NF2Cells-1 do + begin + for k := 0 to NF3Cells-1 do begin - AReport.Add(''); - AReport.Add('SLICE %d COMPARISONS',[k+1]); - // move cell sums and counts to cellsums and cellcnts - for i := 0 to NF1cells-1 do - begin - for j := 0 to NF2cells-1 do - begin - cellsums[j] := wsum[i,j,k]; - cellcnts[j] := ncnt[i,j,k]; - cellvars[j] := wx2[i,j,k]; - end; - end; - value := 1e20; - for i := 0 to NF1cells-1 do if cellcnts[i] < value then value := cellcnts[i]; - if ScheffeChk.Checked then - ScheffeTest(MSErr, cellsums, cellcnts, minf1, maxf1, N, posthocAlpha, AReport); - if TukeyHSDChk.Checked and equal_grp then - Tukey(MSErr, DFErr, value, cellsums, cellcnts, minf1, maxf1, posthocAlpha, AReport); - if TukeyBChk.Checked and equal_grp then - TukeyBTest(MSErr, DFErr, cellsums, cellcnts, minf1, maxf1, value, posthocAlpha, AReport); - if TukeyKramerChk.Checked and equal_grp then - Tukey_Kramer(MSErr, DFErr, value, cellsums, cellcnts, minf1, maxf1, posthocAlpha, AReport); - if NewmanKeulsChk.Checked and equal_grp then - Newman_Keuls(MSErr, DFErr, value, cellsums, cellcnts, minf1, maxf1, posthocAlpha, AReport); - if BonferroniChk.Checked then - Bonferroni(cellsums, cellcnts, cellvars, minf1, maxf1, posthocAlpha, AReport); - if OrthoContrastsChk.Checked then - Contrasts(MSErr, DFErr, cellsums, cellcnts, minf1, maxf1, allAlpha, posthocAlpha, AReport); + cellSums[j] := WSum[i,j,k]; + cellCnts[j] := NCnt[i,j,k]; + cellVars[j] := WX2[i,j,k]; end; - end; - variances := nil + end; + + value := 1e308; + for j := 0 to NF2Cells-1 do + if cellCnts[j] < value then + value := cellCnts[j]; + + if ScheffeChk.Checked then + ScheffeTest(MSErr, cellsums, cellcnts, MinF2, MaxF2, N, posthocAlpha, lReport); + + if TukeyHSDChk.Checked and equal_grp then + Tukey(MSErr, DFErr, value, cellsums, cellcnts, MinF2, MaxF2, posthocAlpha, lReport); + + if TukeyBChk.Checked and equal_grp then + TukeyBTest(MSErr, DFErr, cellsums, cellcnts, MinF2, MaxF2, value, posthocAlpha, lReport); + + if TukeyKramerChk.Checked and equal_grp then + Tukey_Kramer(MSErr, DFErr, value, cellsums, cellcnts, MinF2, MaxF2, posthocAlpha, lReport); + + if NewmanKeulsChk.Checked and equal_grp then + Newman_Keuls(MSErr, DFErr, value, cellsums, cellcnts, MinF2, MaxF2, posthocAlpha, lReport); + + if BonferroniChk.Checked then + Bonferroni(cellsums, cellcnts, cellvars, MinF2, MaxF2, posthocAlpha, lReport); + + if OrthoContrastsChk.Checked then + Contrasts(MSErr, DFErr, cellsums, cellcnts, MinF2, MaxF2, allAlpha, posthocAlpha, lReport); + end; + end; + + // Do simple effects for rows within each column + if (ProbF1f2 < allAlpha) then + begin + if lReport.Count > 0 then + lReport.Add(''); + lReport.Add('COMPARISONS AMONG ROWS WITHIN EACH COLUMN'); + for j := 0 to NF2Cells-1 do + begin + lReport.Add(''); + lReport.Add('COLUMN %d COMPARISONS', [j+1]); + + // move cell sums and counts to cellsums and cellcnts + for i := 0 to NF1Cells-1 do + begin + for k := 0 to NF3Cells-1 do + begin + cellSums[i] := WSum[i,j,k]; + cellCnts[i] := NCnt[i,j,k]; + cellVars[i] := WX2[i,j,k]; + end; + end; + + value := 1e308; + for i := 0 to NF1Cells-1 do + if cellCnts[j] < value then value := cellCnts[j]; + + if ScheffeChk.Checked then + ScheffeTest(MSErr, cellsums, cellcnts, MinF1, MaxF1, N, posthocAlpha, lReport); + + if TukeyHSDChk.Checked and equal_grp then + Tukey(MSErr, DFErr, value, cellsums, cellcnts, MinF1, MaxF1, posthocAlpha, lReport); + + if TukeyBChk.Checked and equal_grp then + TukeyBTest(MSErr, DFErr, cellsums, cellcnts, MinF1, MaxF1, value, posthocAlpha, lReport); + + if TukeyKramerChk.Checked and equal_grp then + Tukey_Kramer(MSErr, DFErr, value, cellsums, cellcnts, MinF1, MaxF1, posthocAlpha, lReport); + + if NewmanKeulsChk.Checked and equal_grp then + Newman_Keuls(MSErr, DFErr, value, cellsums, cellcnts, MinF1, MaxF1, posthocAlpha, lReport); + + if BonferroniChk.Checked then + Bonferroni(cellsums, cellcnts, cellvars, MinF1, MaxF1, posthocAlpha, lReport); + + if OrthoContrastsChk.Checked then + Contrasts(MSErr, DFErr, cellsums, cellcnts, MinF1, MaxF1, allAlpha, posthocAlpha, lReport); + end; + end; + + // Do simple effects for columns within each slice + if (ProbF2F3 < allAlpha) then + begin + if lReport.Count > 0 then + lReport.Add(''); + lReport.Add('COMPARISONS AMONG COLUMNS WITHIN EACH SLICE'); + + for k := 0 to NF3Cells-1 do + begin + lReport.Add(''); + lReport.Add('SLICE %d COMPARISONS', [k+1]); + + // move cell sums and counts to cellsums and cellcnts + for j := 0 to NF2Cells-1 do + begin + for i := 0 to NF1Cells-1 do + begin + cellSums[j] := WSum[i,j,k]; + cellCnts[j] := NCnt[i,j,k]; + cellVars[j] := WX2[i,j,k]; + end; + end; + + value := 1e20; + for j := 1 to NF2cells do + if cellCnts[j] < value then + value := cellCnts[j]; + + if ScheffeChk.Checked then + ScheffeTest(MSErr, cellsums, cellcnts, MinF2, MaxF2, N, posthocAlpha, lReport); + + if TukeyHSDChk.Checked and equal_grp then + Tukey(MSErr, DFErr, value, cellsums, cellcnts, MinF2, MaxF2, posthocAlpha, lReport); + + if TukeyBChk.Checked and equal_grp then + TukeyBTest(MSErr, DFErr, cellsums, cellcnts, MinF2, MaxF2, value, posthocAlpha, lReport); + + if TukeyKramerChk.Checked and equal_grp then + Tukey_Kramer(MSErr, DFErr, value, cellsums, cellcnts, MinF2, MaxF2, posthocAlpha, lReport); + + if NewmanKeulsChk.Checked and equal_grp then + Newman_Keuls(MSErr, DFErr, value, cellsums, cellcnts, MinF2, MaxF2, posthocAlpha, lReport); + + if BonferroniChk.Checked then + Bonferroni(cellsums, cellcnts, cellvars, MinF2, MaxF2, posthocAlpha, lReport); + + if OrthoContrastsChk.Checked then + Contrasts(MSErr, DFErr, cellsums, cellcnts, MinF2, MaxF2, allAlpha, posthocAlpha, lReport); + end; + end; + + // Do simple effects for rows within each slice + if (ProbF1F3 < allAlpha) then + begin + if lReport.Count > 0 then + lReport.Add(''); + lReport.Add('COMPARISONS AMONG ROWS WITHIN EACH SLICE'); + + for k := 0 to NF3Cells-1 do + begin + lReport.Add(''); + lReport.Add('SLICE %d COMPARISONS', [k+1]); + + // move cell sums and counts to cellsums and cellcnts + for i := 0 to NF1Cells-1 do + begin + for j := 0 to NF2Cells-1 do + begin + cellSums[j] := WSum[i,j,k]; + cellCnts[j] := NCnt[i,j,k]; + cellVars[j] := WX2[i,j,k]; + end; + end; + + value := 1e20; + for i := 0 to NF1Cells-1 do + if cellCnts[i] < value then + value := cellCnts[i]; + + if ScheffeChk.Checked then + ScheffeTest(MSErr, cellsums, cellcnts, MinF1, MaxF1, N, posthocAlpha, lReport); + + if TukeyHSDChk.Checked and equal_grp then + Tukey(MSErr, DFErr, value, cellsums, cellcnts, MinF1, MaxF1, posthocAlpha, lReport); + + if TukeyBChk.Checked and equal_grp then + TukeyBTest(MSErr, DFErr, cellsums, cellcnts, MinF1, MaxF1, value, posthocAlpha, lReport); + + if TukeyKramerChk.Checked and equal_grp then + Tukey_Kramer(MSErr, DFErr, value, cellsums, cellcnts, MinF1, MaxF1, posthocAlpha, lReport); + + if NewmanKeulsChk.Checked and equal_grp then + Newman_Keuls(MSErr, DFErr, value, cellsums, cellcnts, MinF1, MaxF1, posthocAlpha, lReport); + + if BonferroniChk.Checked then + Bonferroni(cellsums, cellcnts, cellvars, MinF1, MaxF1, posthocAlpha, lReport); + + if OrthoContrastsChk.Checked then + Contrasts(MSErr, DFErr, cellsums, cellcnts, MinF1, MaxF1, allAlpha, posthocAlpha, lReport); + end; + end; + + FPosthocReportFrame.DisplayReport(lReport); + + finally + lReport.Free; + end; + + PostHocPage.TabVisible := true; end; -//------------------------------------------------------------------- + procedure TBlksAnovaForm.BrownForsytheOneWay(AReport: TStrings); var i, intValue: integer; @@ -2839,9 +3100,7 @@ begin for i := 1 to NoCases do begin if not GoodRecord(OS3MainFrm.DataGrid, i, ColNoSelected) then continue; - intvalue := round(StrToFloat(Trim(OS3MainFrm.DataGrid.Cells[ColNoSelected[1], i]))); -// X := StrToFloat(Trim(OS3MainFrm.DataGrid.Cells[DepVarCol,i])); - intvalue := intvalue - minf1; + intvalue := round(StrToFloat(Trim(OS3MainFrm.DataGrid.Cells[ColNoSelected[1], i]))) - MinF1; cellcnts[intvalue] := 0; cellsums[intvalue] := 0.0; cellvars[intvalue] := 0.0; @@ -2856,10 +3115,9 @@ begin for i := 1 to NoCases do begin if not GoodRecord(OS3MainFrm.DataGrid, i, ColNoSelected) then continue; - intvalue := round(StrToFloat(Trim(OS3MainFrm.DataGrid.Cells[ColNoSelected[1], i]))); + intvalue := round(StrToFloat(Trim(OS3MainFrm.DataGrid.Cells[ColNoSelected[1], i]))) - MinF1; X := StrToFloat(Trim(OS3MainFrm.DataGrid.Cells[ColNoSelected[0], i])); Xsq := X*X; - intvalue := intvalue - minf1; cellcnts[intvalue] := cellcnts[intvalue] + 1; cellsums[intvalue] := cellsums[intvalue] + X; cellvars[intvalue] := cellvars[intvalue] + Xsq; @@ -2873,8 +3131,7 @@ begin begin if cellcnts[i] > 0 then begin - cellvars[i] := cellvars[i] - (cellsums[i] * cellsums[i] /cellcnts[i]); - cellvars[i] := cellvars[i] / (cellcnts[i] - 1.0); + cellvars[i] := (cellvars[i] - sqr(cellsums[i]) /cellcnts[i]) / (cellcnts[i] - 1); SSF1 := SSF1 + (sqr(cellsums[i]) / cellcnts[i]); DFF1 := DFF1 + 1; end; @@ -2914,11 +3171,9 @@ begin MSErr := 0.0; for i := 0 to Nf1cells-1 do begin -// MSErr := MSErr + (((1.0 - cellcnts[i] / N) * cellvars[i])); c1[i+1] := (1.0 - (cellcnts[i] / N)) * cellvars[i]; sumc1 := sumc1 + c1[i+1]; end; -// MSErr := MSErr / DFF1; for i := 1 to Nf1cells do c1[i] := c1[i] / sumc1; @@ -2932,10 +3187,10 @@ begin for i := 1 to Nf1cells do begin cellmeans[i] := cellsums[i-1] / cellcnts[i-1]; - Fnumerator := Fnumerator + (cellcnts[i-1] * (sqr(cellmeans[i] - MeanDep))); - Fdenominator := Fdenominator + ((1.0 - (cellcnts[i-1] / N)) * cellvars[i-1]); + FNumerator := FNumerator + (cellcnts[i-1] * (sqr(cellmeans[i] - MeanDep))); + FDenominator := FDenominator + ((1.0 - (cellcnts[i-1] / N)) * cellvars[i-1]); end; - NewF := Fnumerator / Fdenominator; + NewF := FNumerator / FDenominator; ProbF1 := probf(NewF,DFF1, fdegfree); AReport.Add(''); @@ -2945,18 +3200,10 @@ begin AReport.Add('Brown-Forsythe F probability: %8.3f', [probf1]); AReport.Add(DIVIDER); - { - if Outputfrm = nil then - OutputFrm := TOutputFrm.Create(Application) - else - OutputFrm.Clear; - OutputFrm.AddLines(AReport); - OutputFrm.ShowModal; - } - WelchtTests(AReport); end; + procedure TBlksAnovaForm.WelchOneWay(AReport: TStrings); var i, intValue: integer; diff --git a/applications/lazstats/source/forms/analysis/comparisons/onecaseanovaunit.pas b/applications/lazstats/source/forms/analysis/comparisons/onecaseanovaunit.pas index 51e677dfd..f460948fc 100644 --- a/applications/lazstats/source/forms/analysis/comparisons/onecaseanovaunit.pas +++ b/applications/lazstats/source/forms/analysis/comparisons/onecaseanovaunit.pas @@ -886,27 +886,27 @@ begin Constant := sqr(MeanDep) / N; GrandMean := MeanDep / N; - // Get ss for rows + // Get SS for rows SSF1 := 0; RowsTotCnt := 0; for i := 0 to NoGrpsA - 1 do begin - SSF1 := SSF1 + RowSums[i] * RowSums[i] / RowCount[i]; + SSF1 := SSF1 + sqr(RowSums[i]) / RowCount[i]; RowsTotCnt := RowsTotCnt + RowCount[i]; end; SSF1 := SSF1 - Constant; - // Get ss for columns + // Get SS for columns SSF2 := 0; ColsTotCnt := 0; for j := 0 to NoGrpsB - 1 do begin - SSF2 := SSF2 + ColSums[j] * ColSums[j] / ColCount[j]; + SSF2 := SSF2 + sqr(ColSums[j]) / ColCount[j]; ColsTotCnt := ColsTotCnt + ColCount[j]; end; SSF2 := SSF2 - Constant; - // Get ss for slices + // Get SS for slices SSF3 := 0; SlcsTotCnt := 0; for k := 0 to NoGrpsC - 1 do @@ -1016,6 +1016,7 @@ begin else DFErr := DFTot - DFF1 - DFF2 - DFF3; DFBalance := DFErr - 1; + MSF1 := SSF1 / DFF1; MSF2 := SSF2 / DFF2; MSF3 := SSF3 / DFF3; @@ -1025,6 +1026,7 @@ begin MSErr := SSErr / DFErr; MSDep := SSDep / DFTot; MSBalance := SSBalance / DFBalance; + OmegaF1 := (SSF1 - DFF1 * MSErr) / (SSDep + MSErr); OmegaF2 := (SSF2 - DFF2 * MSErr) / (SSDep + MSErr); OmegaF3 := (SSF3 - DFF3 * MSErr) / (SSDep + MSErr);