Files
lazarus-ccr/applications/lazstats/source/forms/analysis/nonparametric/riditunit.pas
wp_xxyyzz 29721742a0 LazStats: Less hints and warnings.
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@7897 8e941d3f-bd1b-0410-a28a-d453659cc2b4
2020-11-22 18:49:28 +00:00

914 lines
26 KiB
ObjectPascal

unit RIDITUnit;
{$mode objfpc}{$H+}
{$WARN 6058 off : Call to subroutine "$1" marked as inline is not inlined}
interface
uses
Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs,
StdCtrls, Buttons, ExtCtrls, ComCtrls,
MainUnit, Globals, FunctionsLib, MatrixLib, ReportFrameUnit, BasicStatsReportFormUnit;
type
{ TRIDITForm }
TRIDITForm = class(TBasicStatsReportForm)
Bevel2: TBevel;
BonChk: TCheckBox;
AlphaEdit: TEdit;
PageControl: TPageControl;
Panel1: TPanel;
AlphaLabel: TLabel;
ObsChk: TCheckBox;
ExpChk: TCheckBox;
PropChk: TCheckBox;
ChiChk: TCheckBox;
RefGrp: TRadioGroup;
ResultsPage: TTabSheet;
FrequenciesPage: TTabSheet;
RowColPropsPage: TTabSheet;
CellChiSqrPage: TTabSheet;
YatesChk: TCheckBox;
DetailsChk: TCheckBox;
ColList: TListBox;
OptionsGroup: TGroupBox;
RefEdit: TEdit;
Label4: TLabel;
RowEdit: TEdit;
Label2: TLabel;
Label3: TLabel;
RowIn: TBitBtn;
RowOut: TBitBtn;
ColIn: TBitBtn;
ColOut: TBitBtn;
Label1: TLabel;
VarList: TListBox;
procedure ColInClick(Sender: TObject);
procedure ColListClick(Sender: TObject);
procedure ColListDblClick(Sender: TObject);
procedure ColOutClick(Sender: TObject);
procedure RefGrpClick(Sender: TObject);
procedure RowInClick(Sender: TObject);
procedure RowOutClick(Sender: TObject);
procedure VarListDblClick(Sender: TObject);
procedure VarListSelectionChange(Sender: TObject; {%H-}User: boolean);
private
FFrequenciesReportFrame: TReportFrame;
FRowColPropsReportFrame: TReportFrame;
FCellChiSqrReportFrame: TReportFrame;
procedure Analyze(RefCol: integer; RowLabels, ColLabels: StrDyneVec;
NoToAnalyze: integer; Freq: IntDyneMat; Props: DblDyneMat;
NoRows: integer; AReport: TStrings);
function CalcColProportions(const AFrequencies: IntDyneMat): DblDyneMat;
function CalcRowProportions(const AFrequencies: IntDyneMat): DblDyneMat;
procedure GetExpectedAndCellChiSqr(const AFrequencies: IntDyneMat;
out AExpected, ACellChiSqr: DblDyneMat; out AChiSqr, AdjChiSqr: Double;
out ADegreesOfFreedom: Integer; out AYates: Boolean);
procedure GetFrequencies(const AColNoSelected: IntDyneVec;
ANumRows, ANumCols: Integer;
out ANumCases: Integer; out AFrequencies: IntDyneMat);
protected
procedure AdjustConstraints; override;
procedure Compute; override;
procedure UpdateBtnStates; override;
function Validate(out AMsg: String; out AControl: TWinControl): Boolean; override;
public
constructor Create(AOwner: TComponent); override;
procedure Reset; override;
end;
var
RIDITForm: TRIDITForm;
implementation
{$R *.lfm}
uses
Math,
Utils, GridProcs, MatrixUnit;
{ TRIDITForm }
constructor TRIDITForm.Create(AOwner: TComponent);
begin
inherited;
FReportFrame.Parent := ResultsPage;
FFrequenciesReportFrame := TReportFrame.Create(self);
FFrequenciesReportFrame.Name := '';
FFrequenciesReportFrame.Parent := FrequenciesPage;
FFrequenciesReportFrame.Align := alClient;
FFrequenciesReportFrame.BorderSpacing.Left := 0;
FFrequenciesReportFrame.BorderSpacing.Top := 0;
FFrequenciesReportFrame.BorderSpacing.Bottom := 0;
FFrequenciesReportFrame.BorderSpacing.Right := 0;
InitToolbar(FFrequenciesReportFrame.ReportToolbar, tpRight);
FRowColPropsReportFrame := TReportFrame.Create(self);
FRowColPropsReportFrame.Name := '';
FRowColPropsReportFrame.Parent := RowColPropsPage;
FRowColPropsReportFrame.Align := alClient;
FRowColPropsReportFrame.BorderSpacing.Left := 0;
FRowColPropsReportFrame.BorderSpacing.Top := 0;
FRowColPropsReportFrame.BorderSpacing.Bottom := 0;
FRowColPropsReportFrame.BorderSpacing.Right := 0;
InitToolbar(FRowColPropsReportFrame.ReportToolbar, tpRight);
FCellChiSqrReportFrame := TReportFrame.Create(self);
FCellChiSqrReportFrame.Name := '';
FCellChiSqrReportFrame.Parent := CellChiSqrPage;
FCellChiSqrReportFrame.Align := alClient;
FCellChiSqrReportFrame.BorderSpacing.Left := 0;
FCellChiSqrReportFrame.BorderSpacing.Top := 0;
FCellChiSqrReportFrame.BorderSpacing.Bottom := 0;
FCellChiSqrReportFrame.BorderSpacing.Right := 0;
InitToolbar(FCellChiSqrReportFrame.ReportToolbar, tpRight);
PageControl.ActivePageIndex := 0;
end;
procedure TRIDITForm.AdjustConstraints;
begin
inherited;
ParamsPanel.Constraints.MinWidth := MaxValue([
CloseBtn.Width * 4 + CloseBtn.BorderSpacing.Left * 3,
OptionsGroup.Width,
AlphaEdit.Left + AlphaEdit.Width
]);
ParamsPanel.Constraints.MinHeight := ColOut.Top + ColOut.Height +
Label4.BorderSpacing.Top + Label4.Height + Label4.BorderSpacing.Bottom + RefEdit.Height +
Panel1.BorderSpacing.Bottom + OptionsGroup.Height + RefGrp.Height +
ButtonBevel.Height + CloseBtn.BorderSpacing.Top + CloseBtn.Height;
end;
procedure TRIDITForm.Analyze(RefCol: integer; RowLabels, ColLabels: StrDyneVec;
NoToAnalyze: integer; Freq: IntDyneMat; Props: DblDyneMat; NoRows: integer;
AReport: TStrings);
var
probdists : DblDyneMat = nil;
refprob : DblDyneMat = nil;
sizes : DblDyneVec = nil;
meanridits : DblDyneVec = nil;
StdErr : DblDyneVec = nil;
CRatios : DblDyneVec = nil;
OverMeanRidit : double;
chisquare : double;
probchi : double;
alpha : double;
Bonferroni : double;
i, j : integer;
outline : string;
details : boolean;
term1,term2,term3,term4 : double;
begin
SetLength(probdists,NoRows,NoToAnalyze);
SetLength(refprob,NoRows,4);
SetLength(sizes,NoToAnalyze);
SetLength(meanridits,NoToAnalyze);
SetLength(CRatios,NoToAnalyze);
SetLength(StdErr,NoToAnalyze);
alpha := StrToFloat(AlphaEdit.Text);
details := DetailsChk.Checked;
AReport.Add('ANALYSIS FOR STANDARD %s', [ColLabels[RefCol]]);
AReport.Add('');
{ --- wp: these data are displayed in separate tabs, no need to repeat them.
// print frequencies
outline := 'Frequencies Observed';
IntArrayPrint(Freq, NoRows, NoToAnalyze, 'Frequencies', RowLabels, ColLabels, outline, AReport);
// print column proportions
outline := 'Column Proportions Observed';
MatPrint(Props, NoRows, NoToAnalyze, outline, RowLabels, ColLabels, NoCases, AReport);
}
// Get sizes in each column
for i := 0 to NoToAnalyze - 1 do
sizes[i] := Freq[NoRows,i];
// Get the reference variable probabilities for all variables
for j := 0 to NoToAnalyze - 1 do
begin
for i := 0 to NoRows - 1 do
begin
refprob[i,0] := Props[i,j];
refprob[i,1] := Props[i,j] / 2.0;
end;
refprob[0,2] := 0.0;
// for i := 1 to NoRows - 1 do refprob[i,2] := refprob[i-1,2] + refprob[i-1,0];
for i := 0 to NoRows - 2 do
refprob[i+1, 2] := refprob[i, 2] + refprob[i, 0];
for i := 0 to NoRows - 1 do
refprob[i, 3] := refprob[i, 1] + refprob[i, 2];
// Print calculations table
if details then
begin
outline := 'Ridit calculations for ' + ColLabels[j];
MatPrint(refprob, NoRows, 4, outline, RowLabels, ColLabels, NoCases, AReport);
AReport.Add(DIVIDER_SMALL_AUTO);
end;
// store results in probdists
for i := 0 to NoRows - 1 do probdists[i,j] := refprob[i,3];
end;
outline := 'Ridits for all variables';
MatPrint(probdists, NoRows, NoToAnalyze, outline, RowLabels, ColLabels, NoCases, AReport);
AReport.Add(DIVIDER_SMALL_AUTO);
// obtain mean ridits for the all variables using the reference variable
for i := 0 to NoToAnalyze - 1 do
begin
meanridits[i] := 0.0;
for j := 0 to NoRows - 1 do
meanridits[i] := meanridits[i] + (probdists[j,RefCol] * Freq[j,i]);
meanridits[i] := meanridits[i] / sizes[i];
end;
// print the means using the reference variable
outline := 'Mean RIDITS Using the Reference Values';
DynVectorPrint(meanridits, NoToAnalyze, outline, ColLabels, NoCases, AReport);
AReport.Add(DIVIDER_SMALL_AUTO);
// obtain the weighted grand mean ridit
OverMeanRidit := 0.0;
for i := 0 to NoToAnalyze - 1 do
if (i <> RefCol) then OverMeanRidit := OverMeanRidit + sizes[i] * meanridits[i];
OverMeanRidit := OverMeanRidit / (Freq[NoRows,NoToAnalyze] - sizes[RefCol]);
AReport.Add('Overall mean for RIDITS in non-reference groups: %8.4f', [OverMeanRidit]);
// obtain chisquare
chisquare := 0.0;
term4 := sqr(OverMeanRidit - 0.5);
term3 := 0.0;
for i := 0 to NoToAnalyze - 1 do
if (i <> RefCol) then term3 := term3 + sizes[i] * sizes[i];
term3 := 12.0 * term3;
term2 := Freq[NoRows,NoToAnalyze];
term1 := 0.0;
for i := 0 to NoToAnalyze - 1 do
if (i <> RefCol) then
term1 := term1 + sizes[i] * sqr(meanridits[i] - 0.5);
term1 := term1 * 12.0;
chisquare := term1 - (term3 / term2) * term4;
probchi := 1.0 - ChiSquaredProb(chisquare, NoToAnalyze-1);
AReport.Add('Chisquared: %8.4f', [chisquare]);
AReport.Add(' with probability < %8.4f', [probchi]);
// do pairwise comparisons
CRatios[RefCol] := 0.0;
for i := 0 to NoToAnalyze - 1 do
if (i <> RefCol) then
begin
StdErr[i] := sqrt(sizes[RefCol] + sizes[i]) / (2.0 * sqrt(3.0 * sizes[RefCol] * sizes[i]));
CRatios[i] := (meanridits[i] - 0.5) / StdErr[i];
end;
outline := 'z critical ratios';
DynVectorPrint(CRatios, NoToAnalyze, outline, ColLabels, NoCases, AReport);
alpha := alpha / 2.0;
if BonChk.Checked then
begin
alpha := alpha / (NoToAnalyze - 1);
Bonferroni := InverseZ(1.0 - alpha);
AReport.Add('Significance level used for comparisons: %8.3f', [Bonferroni]);
AReport.Add('');
end;
for i := 0 to NoToAnalyze - 1 do
if (i <> RefCol) then
begin
if (abs(CRatios[i]) > Bonferroni) then
AReport.Add('%s vs %s: significant', [ColLabels[i], ColLabels[RefCol]])
else
AReport.Add('%s vs %s: not significant', [ColLabels[i], ColLabels[RefCol]]);
end;
end;
function TRIDITForm.CalcColProportions(const AFrequencies: IntDyneMat): DblDyneMat;
var
i, j, n, m, numRows, numCols: Integer;
begin
MatSize(AFrequencies, n,m);
numRows := n-1;
numCols := m-1;
Result := nil;
SetLength(Result, n,m);
for j := 0 to numCols do
begin
for i := 0 to numRows-1 do
begin
if (AFrequencies[numRows, j] > 0.0) then
Result[i, j] := AFrequencies[i, j] / AFrequencies[numRows, j]
else
Result[i, j] := 0.0;
end;
if (AFrequencies[numRows, j] > 0.0) then
Result[numRows, j] := 1.0
else
Result[numRows, j] := 0.0;
end;
end;
function TRIDITForm.CalcRowProportions(const AFrequencies: IntDyneMat): DblDyneMat;
var
i, j, n, m, numRows, numCols: Integer;
begin
MatSize(AFrequencies, n,m);
numRows := n-1;
numCols := m-1;
Result := nil;
SetLength(Result, n,m);
for i := 0 to numRows do
begin
for j := 0 to numCols-1 do
begin
if (AFrequencies[i, numCols] > 0.0) then
Result[i, j] := AFrequencies[i, j] / AFrequencies[i, numCols]
else
Result[i, j] := 0.0;
end;
if (AFrequencies[i, numCols] > 0.0) then
Result[i, numCols] := 1.0
else
Result[i, numCols] := 0.0;
end;
end;
procedure TRIDITForm.ColInClick(Sender: TObject);
var
i: integer;
begin
i := 0;
while (i < VarList.Items.Count) do
begin
if VarList.Selected[i] then
begin
ColList.Items.Add(VarList.Items[i]);
VarList.Items.Delete(i);
i := 0;
end else
i := i + 1;
end;
UpdateBtnStates;
end;
procedure TRIDITForm.ColListClick(Sender: TObject);
var
index: integer;
begin
index := ColList.ItemIndex;
if index > -1 then
RefEdit.Text := ColList.Items[index];
UpdateBtnStates;
end;
procedure TRIDITForm.ColListDblClick(Sender: TObject);
var
index: Integer;
begin
index := ColList.ItemIndex;
if index > -1 then
begin
VarList.Items.Add(ColList.Items[index]);
ColList.Items.Delete(index);
UpdateBtnStates;
end;
end;
procedure TRIDITForm.ColOutClick(Sender: TObject);
var
index: integer;
begin
index := ColList.ItemIndex;
if index > -1 then
begin
VarList.Items.Add(ColList.Items[index]);
ColList.Items.Delete(index);
end;
UpdateBtnStates;
end;
procedure TRIDITForm.Compute;
var
RowProp: DblDyneMat = nil;
ColProp: DblDyneMat = nil;
Expected: DblDyneMat = nil;
CellChi: DblDyneMat = nil;
ColNoSelected: IntDyneVec = nil;
Freq : IntDyneMat = nil;
RowLabels: StrDyneVec = nil;
ColLabels: StrDyneVec = nil;
AllRefs : boolean;
i, j, RowNo, RefColNo, NoToAnalyze : integer;
Ncases, Nrows, Ncols, df : integer;
ChiSquare, ProbChi : double;
yates : boolean;
Adjchisqr, Adjprobchi: double;
likelihood, problikelihood, phi: double;
pearsonr, VarX, VarY, SumX, SumY, MantelHaenszel, MHProb, CoefCont: double;
CramerV: double;
lReport: TStrings;
begin
AllRefs := RefGrp.ItemIndex = 0;
SetLength(ColNoSelected, NoVariables+1); // +1 due to RowNo in first element
RowNo := GetVariableIndex(OS3MainFrm.DataGrid, RowEdit.Text);
if (RowNo = -1) then
begin
RowEdit.Setfocus;
ErrorMsg('A variable for the row labels was not entered.');
ColNoSelected := nil;
exit;
end;
ColNoSelected[0] := RowNo;
// Get row labels
NRows := NoCases;
SetLength(RowLabels, NRows+1); // wp: why +1?
for i := 1 to NRows do
RowLabels[i-1] := OS3MainFrm.DataGrid.Cells[RowNo,i];
// Get Column labels
NCols := ColList.Items.Count;
SetLength(ColLabels, NCols+1); // wp: why +1?
for i := 0 to ColList.Items.Count-1 do
begin
ColLabels[i] := ColList.Items[i];
ColNoSelected[i+1] := GetVariableIndex(OS3MainFrm.DataGrid, ColLabels[i]);
end;
RowLabels[NRows] := 'Total';
ColLabels[NCols] := 'Total';
// Get frequencies
GetFrequencies(ColNoSelected, NRows, NCols, NCases, Freq);
// Calculate expected values and cell chi-squares
GetExpectedAndCellChiSqr(Freq, Expected, cellChi, chiSquare, AdjChiSqr, df, yates);
probChi := 1.0 - ChiSquaredProb(ChiSquare, df); // prob. larger chi
if yates then
AdjProbChi := 1.0 - ChiSquaredProb(AdjChiSqr, df);
// Calculate column proportions (needed by Analyze() routine)
ColProp := CalcColProportions(Freq);
// Print results to output form
lReport := TStringList.Create;
try
// Print frequencies tables if requested by user
if ObsChk.Checked or ExpChk.Checked then
begin
FrequenciesPage.TabVisible := true;
if ObsChk.Checked then
begin
IntArrayPrint(Freq, NRows+1, NCols+1, 'Frequencies', RowLabels, ColLabels, 'OBSERVED FREQUENCIES', lReport);
if ExpChk.Checked then
begin
lReport.Add(DIVIDER_SMALL_AUTO);
lReport.Add('');
end;
end;
if ExpChk.Checked then
MatPrint(Expected, Nrows, Ncols, 'EXPECTED FREQUENCIES', RowLabels, ColLabels, NoCases, lReport);
FFrequenciesReportFrame.DisplayReport(lReport);
lReport.Clear;
end else
FrequenciesPage.TabVisible := false;
// Print row/col proportions
if PropChk.Checked then
begin
RowColPropsPage.TabVisible := true;
RowProp := CalcRowProportions(Freq);
MatPrint(RowProp, NRows+1, NCols+1, 'ROW PROPORTIONS', RowLabels, ColLabels, NoCases, lReport);
RowProp := nil; // not needed any more
lReport.Add(DIVIDER_SMALL_AUTO);
lReport.Add('');
MatPrint(ColProp, NRows+1, NCols+1, 'COLUMN PROPORTIONS', RowLabels, ColLabels, NoCases, lReport);
FRowColPropsReportFrame.DisplayReport(lReport);
lReport.Clear;
end else
RowColPropsPage.TabVisible := false;
// Print cell chi-sqr values if requested by user
if ChiChk.Checked then
begin
CellChiSqrPage.TabVisible := true;
MatPrint(CellChi, Nrows, Ncols, 'CHI-SQUARED VALUE FOR CELLS', RowLabels, ColLabels, NoCases, lReport);
FCellChiSqrReportFrame.DisplayReport(lReport);
lReport.Clear;
end else
CellChiSqrPage.TabVisible := false;
lReport.Add('CHI-SQUARE ANALYSIS RESULTS');
lReport.Add('No. of Cases: %d', [Ncases]);
lReport.Add('');
lReport.Add('');
lReport.Add( 'Chi-square: %8.3f', [ChiSquare]);
lReport.Add( ' with D.F. %8d', [df]);
lReport.Add( ' and probability > value: %8.3f', [ProbChi]);
lReport.Add('');
if yates then
begin
lReport.Add('Chi-square using Yates correction: %8.3f', [AdjChiSqr]);
lReport.Add(' and probability > value: %8.3f', [AdjProbChi]);
end;
likelihood := 0.0;
for i := 0 to Nrows - 1 do
for j := 0 to Ncols - 1 do
if (Freq[i,j] > 0.0) then
likelihood := likelihood + Freq[i,j] * (ln(Expected[i,j] / Freq[i,j]));
likelihood := -2.0 * likelihood;
problikelihood := 1.0 - ChiSquaredProb(likelihood, df);
lReport.Add( 'Likelihood Ratio: %8.3f', [likelihood]);
lReport.Add( ' with probability > value: %8.3f', [probLikelihood]);
lReport.Add('');
if ((Nrows > 1) and (Ncols > 1)) then
begin
phi := sqrt(ChiSquare / Ncases);
lReport.Add('phi Correlation: %8.3f', [phi]);
pearsonr := 0.0;
SumX := 0.0;
SumY := 0.0;
VarX := 0.0;
VarY := 0.0;
for i := 0 to Nrows - 1 do SumX := SumX + ( (i+1) * Freq[i,Ncols] );
for j := 0 to Ncols - 1 do SumY := SumY + ( (j+1) * Freq[Nrows,j] );
for i := 0 to Nrows - 1 do VarX := VarX + ( ((i+1)*(i+1)) * Freq[i,Ncols] );
for j := 0 to Ncols - 1 do VarY := VarY + ( ((j+1)*(j+1)) * Freq[Nrows,j] );
VarX := VarX - ((SumX * SumX) / Ncases);
VarY := VarY - ((SumY * SumY) / Ncases);
for i := 0 to Nrows - 1 do
for j := 0 to Ncols - 1 do
pearsonr := pearsonr + ((i+1)*(j+1) * Freq[i,j]);
pearsonr := pearsonr - (SumX * SumY / Ncases);
pearsonr := pearsonr / sqrt(VarX * VarY);
lReport.Add('Pearson Correlation r: %8.3f', [pearsonr]);
MantelHaenszel := (Ncases-1) * (pearsonr * pearsonr);
MHprob := 1.0 - chisquaredprob(MantelHaenszel,1);
lReport.Add('Mantel-Haenszel Test of Linear Association: %8.3f', [MantelHaenszel]);
lReport.Add(' with probability > value %8.3f', [MHprob]);
CoefCont := sqrt(ChiSquare / (ChiSquare + Ncases));
lReport.Add('The coefficient of contingency: %8.3f', [CoefCont]);
if (Nrows < Ncols) then
CramerV := sqrt(ChiSquare / (Ncases * ((Nrows-1))))
else
CramerV := sqrt(ChiSquare / (Ncases * ((Ncols-1))));
lReport.Add('Cramers V: %8.3f', [CramerV]);
end;
lReport.Add('');
lReport.Add(DIVIDER_AUTO);
lReport.Add('');
// Now do RIDIT analysis
NoToAnalyze := ColList.Items.Count;
// do an analysis for each variable as a reference variable
if AllRefs then
begin
NoToAnalyze := ColList.Items.Count;
for i := 0 to NoToAnalyze - 1 do
begin
RefColNo := ColNoSelected[i+1] - 2;
Analyze(RefColNo, RowLabels,ColLabels, NoToAnalyze, Freq, ColProp, Nrows, lReport);
if i < NoToAnalyze-1 then
begin
lReport.Add('');
lReport.Add(DIVIDER_AUTO);
lReport.Add('');
end;
end;
end
else
// only one selected reference variable
begin
NoToAnalyze := ColList.Items.Count;
// get column of reference variable
for i := 1 to NoVariables do
if (RefEdit.Text = OS3MainFrm.DataGrid.Cells[i,0]) then RefColNo := i;
for j := 0 to NoToAnalyze - 1 do
if (ColNoSelected[j+1] = RefColNo) then RefColNo := j;
Analyze(RefColNo, RowLabels,ColLabels, NoToAnalyze, Freq, ColProp, Nrows, lReport);
end;
FReportFrame.DisplayReport(lReport);
finally
lReport.Free;
end;
end;
procedure TRIDITForm.GetExpectedAndCellChiSqr(const AFrequencies: IntDyneMat;
out AExpected, ACellChiSqr: DblDyneMat; out AChiSqr, AdjChiSqr: Double;
out ADegreesOfFreedom: Integer; out AYates: Boolean);
var
i, j, n, m: Integer;
numRows, numCols, numCases: Integer;
begin
MatSize(AFrequencies, n,m); // n,m contain totals row and column
numRows := n-1;
numCols := m-1;
numCases := AFrequencies[numRows, numCols];
AExpected := nil;
ACellChiSqr := nil;
SetLength(AExpected, numRows, numCols);
SetLength(ACellChiSqr, numRows, numCols);
AChiSqr := 0;
AdjChiSqr := -1; // -1 indicates non-existing value in case of AYates=false
AYates := YatesChk.Checked and (numRows = 2) and (numCols = 2);
if (numRows > 1) and (numCols > 1) then
begin
for i := 0 to numRows-1 do
begin
for j := 0 to numCols-1 do
begin
AExpected[i, j] := AFrequencies[numRows, j] * AFrequencies[i, numCols] / numCases;
if (AExpected[i, j] > 0) then
ACellChiSqr[i, j] := sqr(AFrequencies[i, j] - AExpected[i, j]) / AExpected[i, j]
else
begin
ErrorMsg('Zero expected value found.');
ACellChiSqr[i, j] := 0;
end;
AChiSqr := AChiSqr + ACellChiSqr[i, j];
end;
end;
ADegreesOfFreedom := (numRows - 1) * (numCols - 1);
// 2x2 corrected chi-square
if AYates then
begin
AdjChiSqr := abs((AFrequencies[0, 0] * AFrequencies[1, 1]) - (AFrequencies[0, 1] * AFrequencies[1, 0]));
AdjChiSqr := sqr(AdjChiSqr - numCases / 2.0) * numCases; // numerator
AdjChiSqr := AdjChiSqr / (AFrequencies[0, 2] * AFrequencies[1,2] * AFrequencies[2,0] * AFrequencies[2,1]);
end;
end;
// Equal probability
if (numRows = 1) then
begin
for j := 0 to numCols - 1 do
begin
AExpected[0, j] := numCases / numCols;
if (AExpected[0, j] > 0) then
ACellChiSqr[0, j] := sqr(AFrequencies[0, j] - AExpected[0, j]) / AExpected[0, j];
AChiSqr := AChiSqr + ACellChiSqr[0, j];
end;
ADegreesOfFreedom := numCols - 1;
end;
// Equal probability
if (numCols = 1) then
begin
for i := 0 to numRows - 1 do
begin
AExpected[i, 0] := numCases / numRows;
if (AExpected[i, 0] > 0) then
ACellChiSqr[i, 0] := sqr(AFrequencies[i, 0] - AExpected[i, 0]) / AExpected[i, 0];
AChiSqr := AChiSqr + ACellChiSqr[i, 0];
end;
ADegreesOfFreedom := numRows - 1;
end;
end;
procedure TRIDITForm.GetFrequencies(const AColNoSelected: IntDyneVec;
ANumRows, ANumCols: Integer; out ANumCases: Integer; out AFrequencies: IntDyneMat);
var
i, j, row, col: Integer;
begin
// over-dimension the matrix because row and column totals will be in
// last column and row.
AFrequencies := nil;
SetLength(AFrequencies, ANumRows+1, ANumCols+1);
for i := 0 to ANumRows do
for j := 0 to ANumCols do
AFrequencies[i, j] := 0;
// Get cell data
ANumCases := 0;
for i := 0 to NoCases-1 do
begin
row := i+1;
for j := 0 to ANumCols-1 do
begin
col := AColNoSelected[j+1]; // +1 because row index is at index 0
AFrequencies[i, j] := StrToInt(OS3MainFrm.DataGrid.Cells[col, row]);
ANumCases := ANumCases + AFrequencies[i, j];
end;
end;
AFrequencies[ANumRows, ANumCols] := ANumCases;
// Calculate row totals
for i := 0 to ANumRows-1 do
for j := 0 to ANumCols-1 do
AFrequencies[i, ANumCols] := AFrequencies[i, ANumCols] + AFrequencies[i, j];
// Calculate col totals
for j := 0 to ANumCols-1 do
for i := 0 to ANumRows-1 do
AFrequencies[ANumRows, j] := AFrequencies[ANumRows, j] + AFrequencies[i, j];
end;
procedure TRIDITForm.RefGrpClick(Sender: TObject);
begin
RefEdit.Visible := RefGrp.ItemIndex > 0;
Label4.Visible := RefEdit.Visible;
end;
procedure TRIDITForm.Reset;
var
i: integer;
begin
inherited;
FrequenciesPage.TabVisible := false;
RowColPropsPage.TabVisible := false;
CellChiSqrPage.TabVisible := false;
if FFrequenciesReportFrame <> nil then
FFrequenciesReportFrame.Clear;
if FRowColPropsReportFrame <> nil then
FRowColPropsReportframe.Clear;
if FCellChiSqrReportFrame <> nil then
FCellChiSqrReportFrame.Clear;
VarList.Clear;
for i := 1 to NoVariables do
VarList.Items.Add(OS3MainFrm.DataGrid.Cells[i, 0]);
ColList.Clear;
RowEdit.Clear;
RefEdit.Clear;
AlphaEdit.Text := FormatFloat('0.00', DEFAULT_ALPHA_LEVEL);
BonChk.Checked := false;
Label4.Visible := false;
RefEdit.Visible := false;
RefGrp.ItemIndex := 0;
UpdateBtnStates;
end;
procedure TRIDITForm.RowInClick(Sender: TObject);
var
index: integer;
begin
index := VarList.ItemIndex;
if (index > -1) and (RowEdit.Text = '') then
begin
RowEdit.Text := VarList.Items[index];
VarList.Items.Delete(index);
end;
UpdateBtnStates;
end;
procedure TRIDITForm.RowOutClick(Sender: TObject);
begin
if RowEdit.Text <> '' then
begin
VarList.Items.Add(RowEdit.Text);
RowEdit.Text := '';
end;
UpdateBtnStates;
end;
procedure TRIDITForm.UpdateBtnStates;
begin
inherited;
if FFrequenciesReportFrame <> nil then
FFrequenciesReportFrame.UpdateBtnStates;
if FRowColPropsReportFrame <> nil then
FRowColPropsReportframe.UpdateBtnStates;
if FCellChiSqrReportFrame <> nil then
FCellChiSqrReportFrame.UpdateBtnStates;
RowIn.Enabled := (VarList.ItemIndex > -1) and (RowEdit.Text = '');
RowOut.Enabled := (RowEdit.Text <> '');
ColIn.Enabled := AnySelected(VarList);
ColOut.Enabled := (ColList.ItemIndex > -1);
end;
function TRIDITForm.Validate(out AMsg: String; out AControl: TWinControl): Boolean;
var
tmp: Double;
begin
Result := false;
if ColList.Count = 0 then
begin
AControl := ColList;
AMsg := 'No column variable(s) selected.';
exit;
end;
if AlphaEdit.Text = '' then
begin
AControl := AlphaEdit;
AMsg := 'Alpha level not specified.';
exit;
end;
if not TryStrToFloat(AlphaEdit.Text, tmp) then
begin
AControl := AlphaEdit;
AMsg := 'Numeric input required for alpha level.';
exit;
end;
if (tmp <= 0) or (tmp >= 1) then
begin
AControl := AlphaEdit;
AMsg := 'Alpha level must be > 0 and < 1';
exit;
end;
Result := true;
end;
procedure TRIDITForm.VarListDblClick(Sender: TObject);
var
index: Integer;
s: String;
begin
index := VarList.ItemIndex;
if index > -1 then
begin
s := VarList.Items[index];
if RowEdit.Text = '' then
RowEdit.Text := s
else
ColList.Items.Add(s);
VarList.Items.Delete(index);
UpdateBtnStates;
end;
end;
procedure TRIDITForm.VarListSelectionChange(Sender: TObject; User: boolean);
begin
UpdateBtnStates;
end;
end.