2020-03-30 18:01:44 +00:00
|
|
|
unit RIDITUnit;
|
|
|
|
|
|
|
|
{$mode objfpc}{$H+}
|
|
|
|
|
|
|
|
interface
|
|
|
|
|
|
|
|
uses
|
2020-10-29 22:17:02 +00:00
|
|
|
Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs,
|
2020-03-30 18:01:44 +00:00
|
|
|
StdCtrls, Buttons, ExtCtrls,
|
2020-10-29 22:17:02 +00:00
|
|
|
MainUnit, Globals, FunctionsLib, MatrixLib, BasicStatsReportFormUnit;
|
2020-03-30 18:01:44 +00:00
|
|
|
|
|
|
|
type
|
|
|
|
|
2020-10-29 22:17:02 +00:00
|
|
|
{ TRIDITForm }
|
2020-03-30 18:01:44 +00:00
|
|
|
|
2020-10-29 22:17:02 +00:00
|
|
|
TRIDITForm = class(TBasicStatsReportForm)
|
2020-03-30 18:01:44 +00:00
|
|
|
Bevel2: TBevel;
|
|
|
|
BonChk: TCheckBox;
|
|
|
|
AlphaEdit: TEdit;
|
|
|
|
Panel1: TPanel;
|
2020-10-29 22:17:02 +00:00
|
|
|
AlphaLabel: TLabel;
|
2020-03-30 18:01:44 +00:00
|
|
|
ObsChk: TCheckBox;
|
|
|
|
ExpChk: TCheckBox;
|
|
|
|
PropChk: TCheckBox;
|
|
|
|
ChiChk: TCheckBox;
|
|
|
|
RefGrp: TRadioGroup;
|
|
|
|
YatesChk: TCheckBox;
|
|
|
|
DetailsChk: TCheckBox;
|
|
|
|
ColList: TListBox;
|
|
|
|
GroupBox1: 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);
|
2020-10-29 22:17:02 +00:00
|
|
|
procedure ColListDblClick(Sender: TObject);
|
2020-03-30 18:01:44 +00:00
|
|
|
procedure ColOutClick(Sender: TObject);
|
|
|
|
procedure RefGrpClick(Sender: TObject);
|
|
|
|
procedure RowInClick(Sender: TObject);
|
|
|
|
procedure RowOutClick(Sender: TObject);
|
2020-04-05 17:25:38 +00:00
|
|
|
procedure Analyze(RefCol: integer; ColNoSelected: IntDyneVec;
|
|
|
|
RowLabels: StrDyneVec; ColLabels: StrDyneVec;
|
|
|
|
NoToAnalyze: integer; Freq: IntDyneMat;
|
|
|
|
Props: DblDyneMat; NoRows: integer; AReport: TStrings);
|
2020-10-29 22:17:02 +00:00
|
|
|
procedure VarListDblClick(Sender: TObject);
|
2020-10-29 22:48:02 +00:00
|
|
|
procedure VarListSelectionChange(Sender: TObject; {%H-}User: boolean);
|
2020-10-29 22:17:02 +00:00
|
|
|
|
2020-03-30 18:01:44 +00:00
|
|
|
private
|
2020-10-29 22:17:02 +00:00
|
|
|
|
|
|
|
protected
|
|
|
|
procedure AdjustConstraints; override;
|
|
|
|
procedure Compute; override;
|
|
|
|
procedure UpdateBtnStates; override;
|
|
|
|
function Validate(out AMsg: String; out AControl: TWinControl): Boolean; override;
|
|
|
|
|
2020-03-30 18:01:44 +00:00
|
|
|
public
|
2020-10-29 22:17:02 +00:00
|
|
|
procedure Reset; override;
|
2020-03-30 18:01:44 +00:00
|
|
|
end;
|
|
|
|
|
|
|
|
var
|
2020-10-29 22:17:02 +00:00
|
|
|
RIDITForm: TRIDITForm;
|
|
|
|
|
2020-03-30 18:01:44 +00:00
|
|
|
|
|
|
|
implementation
|
|
|
|
|
2020-10-29 22:17:02 +00:00
|
|
|
{$R *.lfm}
|
|
|
|
|
2020-03-30 18:01:44 +00:00
|
|
|
uses
|
2020-04-05 17:25:38 +00:00
|
|
|
Math,
|
2020-10-29 22:17:02 +00:00
|
|
|
Utils, GridProcs;
|
2020-03-30 18:01:44 +00:00
|
|
|
|
2020-10-29 22:17:02 +00:00
|
|
|
{ TRIDITForm }
|
2020-03-30 18:01:44 +00:00
|
|
|
|
2020-10-29 22:17:02 +00:00
|
|
|
procedure TRIDITForm.AdjustConstraints;
|
2020-03-30 18:01:44 +00:00
|
|
|
begin
|
2020-10-29 22:17:02 +00:00
|
|
|
inherited;
|
|
|
|
|
|
|
|
ParamsPanel.Constraints.MinWidth := MaxValue([
|
|
|
|
CloseBtn.Width * 4 + CloseBtn.BorderSpacing.Left * 3,
|
|
|
|
GroupBox1.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 + GroupBox1.Height + RefGrp.Height +
|
|
|
|
ButtonBevel.Height + CloseBtn.BorderSpacing.Top + CloseBtn.Height;
|
2020-03-30 18:01:44 +00:00
|
|
|
end;
|
|
|
|
|
2020-10-29 22:17:02 +00:00
|
|
|
|
|
|
|
procedure TRIDITForm.Analyze(RefCol : integer; ColNoSelected : IntDyneVec;
|
|
|
|
RowLabels : StrDyneVec; ColLabels : StrDyneVec;
|
|
|
|
NoToAnalyze : integer; Freq : IntDyneMat;
|
|
|
|
Props : DblDyneMat; NoRows : integer;
|
|
|
|
AReport: TStrings);
|
2020-04-05 17:25:38 +00:00
|
|
|
var
|
2020-10-29 22:48:02 +00:00
|
|
|
probdists : DblDyneMat = nil;
|
|
|
|
refprob : DblDyneMat = nil;
|
|
|
|
sizes : DblDyneVec = nil;
|
|
|
|
meanridits : DblDyneVec = nil;
|
|
|
|
StdErr : DblDyneVec = nil;
|
|
|
|
Cratios : DblDyneVec = nil;
|
2020-10-29 22:17:02 +00:00
|
|
|
OverMeanRidit : double;
|
|
|
|
chisquare : double;
|
|
|
|
probchi : double;
|
|
|
|
alpha : double;
|
|
|
|
Bonferroni : double;
|
|
|
|
i, j : integer;
|
|
|
|
outline : string;
|
|
|
|
details : boolean;
|
|
|
|
term1,term2,term3,term4 : double;
|
|
|
|
|
2020-03-30 18:01:44 +00:00
|
|
|
begin
|
2020-10-29 22:17:02 +00:00
|
|
|
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('');
|
|
|
|
|
|
|
|
// 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
|
2020-04-05 17:25:38 +00:00
|
|
|
begin
|
2020-10-29 22:17:02 +00:00
|
|
|
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 - 1 do refprob[i,3] := refprob[i,1] + refprob[i,2];
|
|
|
|
if (details) then // print calculations table
|
|
|
|
begin
|
|
|
|
outline := 'Ridit calculations for ' + ColLabels[j];
|
|
|
|
MatPrint(refprob, NoRows, 4, outline, RowLabels, ColLabels, NoCases, AReport);
|
|
|
|
end;
|
|
|
|
|
|
|
|
// store results in probdists
|
|
|
|
for i := 0 to NoRows - 1 do probdists[i,j] := refprob[i,3];
|
2020-04-05 17:25:38 +00:00
|
|
|
end;
|
2020-10-29 22:17:02 +00:00
|
|
|
outline := 'Ridits for all variables';
|
|
|
|
MatPrint(probdists, NoRows, NoToAnalyze, outline, RowLabels, ColLabels, NoCases, AReport);
|
2020-03-30 18:01:44 +00:00
|
|
|
|
2020-10-29 22:17:02 +00:00
|
|
|
// obtain mean ridits for the all variables using the reference variable
|
|
|
|
for i := 0 to NoToAnalyze - 1 do
|
2020-04-05 17:25:38 +00:00
|
|
|
begin
|
2020-10-29 22:17:02 +00:00
|
|
|
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];
|
2020-04-05 17:25:38 +00:00
|
|
|
end;
|
2020-03-30 18:01:44 +00:00
|
|
|
|
2020-10-29 22:17:02 +00:00
|
|
|
// print the means using the reference variable
|
|
|
|
outline := 'Mean RIDITS Using the Reference Values';
|
|
|
|
DynVectorPrint(meanridits, NoToAnalyze, outline, ColLabels, NoCases, AReport);
|
2020-03-30 18:01:44 +00:00
|
|
|
|
2020-10-29 22:17:02 +00:00
|
|
|
// 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]);
|
2020-03-30 18:01:44 +00:00
|
|
|
|
2020-10-29 22:17:02 +00:00
|
|
|
AReport.Add('Overall mean for RIDITS in non-reference groups: %8.4f', [OverMeanRidit]);
|
2020-03-30 18:01:44 +00:00
|
|
|
|
2020-10-29 22:17:02 +00:00
|
|
|
// 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]);
|
2020-03-30 18:01:44 +00:00
|
|
|
|
2020-10-29 22:17:02 +00:00
|
|
|
// 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;
|
2020-03-30 18:01:44 +00:00
|
|
|
|
2020-10-29 22:17:02 +00:00
|
|
|
outline := 'z critical ratios';
|
|
|
|
DynVectorPrint(Cratios, NoToAnalyze, outline, ColLabels, NoCases, AReport);
|
2020-03-30 18:01:44 +00:00
|
|
|
|
2020-10-29 22:17:02 +00:00
|
|
|
alpha := alpha / 2.0;
|
|
|
|
if (BonChk.Checked) then alpha := alpha / (NoToAnalyze - 1);
|
|
|
|
Bonferroni := InverseZ(1.0 - alpha);
|
|
|
|
AReport.Add('Significance level used for comparisons: %8.3f', [Bonferroni]);
|
|
|
|
AReport.Add('');
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
// cleanup
|
|
|
|
StdErr := nil;
|
|
|
|
Cratios := nil;
|
|
|
|
meanridits := nil;
|
|
|
|
sizes := nil;
|
|
|
|
refprob := nil;
|
|
|
|
probdists := nil;
|
2020-03-30 18:01:44 +00:00
|
|
|
end;
|
|
|
|
|
2020-10-29 22:17:02 +00:00
|
|
|
|
|
|
|
procedure TRIDITForm.ColInClick(Sender: TObject);
|
2020-04-05 17:25:38 +00:00
|
|
|
var
|
|
|
|
i: integer;
|
2020-03-30 18:01:44 +00:00
|
|
|
begin
|
2020-04-05 17:25:38 +00:00
|
|
|
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;
|
2020-03-30 18:01:44 +00:00
|
|
|
end;
|
|
|
|
|
2020-10-29 22:17:02 +00:00
|
|
|
|
|
|
|
procedure TRIDITForm.ColListClick(Sender: TObject);
|
2020-04-05 17:25:38 +00:00
|
|
|
var
|
|
|
|
index: integer;
|
2020-03-30 18:01:44 +00:00
|
|
|
begin
|
2020-04-05 17:25:38 +00:00
|
|
|
index := ColList.ItemIndex;
|
|
|
|
if index > -1 then
|
|
|
|
RefEdit.Text := ColList.Items[index];
|
|
|
|
UpdateBtnStates;
|
2020-03-30 18:01:44 +00:00
|
|
|
end;
|
|
|
|
|
2020-10-29 22:17:02 +00:00
|
|
|
|
|
|
|
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);
|
2020-04-05 17:25:38 +00:00
|
|
|
var
|
|
|
|
index: integer;
|
2020-03-30 18:01:44 +00:00
|
|
|
begin
|
2020-04-05 17:25:38 +00:00
|
|
|
index := ColList.ItemIndex;
|
|
|
|
if index > -1 then
|
|
|
|
begin
|
|
|
|
VarList.Items.Add(ColList.Items[index]);
|
|
|
|
ColList.Items.Delete(index);
|
|
|
|
end;
|
|
|
|
UpdateBtnStates;
|
2020-03-30 18:01:44 +00:00
|
|
|
end;
|
|
|
|
|
2020-10-29 22:17:02 +00:00
|
|
|
|
|
|
|
procedure TRIDITForm.Compute;
|
2020-04-05 17:25:38 +00:00
|
|
|
var
|
2020-10-29 22:48:02 +00:00
|
|
|
Prop: DblDyneMat = nil;
|
|
|
|
Expected: DblDyneMat = nil;
|
|
|
|
CellChi: DblDyneMat = nil;
|
|
|
|
ColNoSelected: IntDyneVec = nil;
|
|
|
|
Freq : IntDyneMat = nil;
|
|
|
|
RowLabels: StrDyneVec = nil;
|
|
|
|
ColLabels: StrDyneVec = nil;
|
2020-04-05 17:25:38 +00:00
|
|
|
AllRefs : boolean;
|
|
|
|
i, j, RowNo, RefColNo, NoToAnalyze : integer;
|
|
|
|
Row, Col, Ncases, Nrows, Ncols, df : integer;
|
|
|
|
outline : string;
|
|
|
|
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;
|
2020-03-30 18:01:44 +00:00
|
|
|
begin
|
2020-04-05 17:25:38 +00:00
|
|
|
AllRefs := RefGrp.ItemIndex = 0;
|
|
|
|
|
2020-10-29 22:17:02 +00:00
|
|
|
SetLength(ColNoSelected, NoVariables+1); // +1 due to RowNo in first element
|
|
|
|
RowNo := GetVariableIndex(OS3MainFrm.DataGrid, RowEdit.Text);
|
|
|
|
if (RowNo = -1) then
|
2020-04-05 17:25:38 +00:00
|
|
|
begin
|
2020-10-29 22:17:02 +00:00
|
|
|
RowEdit.Setfocus;
|
|
|
|
ErrorMsg('A variable for the row labels was not entered.');
|
|
|
|
ColNoSelected := nil;
|
|
|
|
exit;
|
2020-04-05 17:25:38 +00:00
|
|
|
end;
|
|
|
|
ColNoSelected[0] := RowNo;
|
|
|
|
|
2020-10-29 22:17:02 +00:00
|
|
|
// 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];
|
|
|
|
|
2020-04-05 17:25:38 +00:00
|
|
|
// Get Column labels
|
2020-10-29 22:17:02 +00:00
|
|
|
NCols := ColList.Items.Count;
|
|
|
|
SetLength(ColLabels, NCols+1); // wp: why +1?
|
|
|
|
for i := 0 to ColList.Items.Count-1 do
|
2020-04-05 17:25:38 +00:00
|
|
|
begin
|
2020-10-29 22:17:02 +00:00
|
|
|
ColLabels[i] := ColList.Items[i];
|
|
|
|
ColNoSelected[i+1] := GetVariableIndex(OS3MainFrm.DataGrid, ColLabels[i]);
|
2020-04-05 17:25:38 +00:00
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
// allocate and initialize
|
2020-10-29 22:17:02 +00:00
|
|
|
SetLength(Freq, NRows+1, NCols+1);
|
|
|
|
SetLength(Prop, NRows+1, NCols+1);
|
|
|
|
SetLength(Expected, NRows, NCols);
|
|
|
|
SetLength(CellChi, NRows, NCols);
|
|
|
|
for i := 1 to NRows + 1 do
|
|
|
|
for j := 1 to NCols + 1 do
|
2020-04-05 17:25:38 +00:00
|
|
|
Freq[i-1,j-1] := 0;
|
2020-10-29 22:17:02 +00:00
|
|
|
RowLabels[NRows] := 'Total';
|
|
|
|
ColLabels[NCols] := 'Total';
|
2020-04-05 17:25:38 +00:00
|
|
|
|
|
|
|
// get cell data
|
2020-10-29 22:17:02 +00:00
|
|
|
NCases := 0;
|
2020-04-05 17:25:38 +00:00
|
|
|
for i := 1 to NoCases do
|
|
|
|
begin
|
|
|
|
Row := i;
|
|
|
|
for j := 1 to Ncols do
|
|
|
|
begin
|
|
|
|
Col := ColNoSelected[j];
|
|
|
|
Freq[i-1,j-1] := StrToInt(OS3MainFrm.DataGrid.Cells[Col,Row]);
|
|
|
|
// result := GetValue(Row,Col,intvalue,dblvalue,strvalue);
|
|
|
|
// if (result = 1) Freq[i-1][j-1] := 0;
|
|
|
|
// else Freq[i-1][j-1] := intvalue;
|
|
|
|
Ncases := Ncases + Freq[i-1,j-1];
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
Freq[Nrows][Ncols] := Ncases;
|
|
|
|
|
|
|
|
// Now, calculate expected values
|
|
|
|
|
|
|
|
// Get row totals first
|
|
|
|
for i := 1 to Nrows do
|
|
|
|
for j := 1 to Ncols do
|
|
|
|
Freq[i-1,Ncols] := Freq[i-1,Ncols] + Freq[i-1,j-1];
|
|
|
|
|
|
|
|
// Get col totals next
|
|
|
|
for j := 1 to Ncols do
|
|
|
|
for i := 1 to Nrows do
|
|
|
|
Freq[Nrows,j-1] := Freq[Nrows,j-1] + Freq[i-1,j-1];
|
|
|
|
|
|
|
|
// Then get expected values and cell chi-squares
|
|
|
|
ChiSquare := 0.0;
|
|
|
|
Adjchisqr := 0.0;
|
|
|
|
yates := YatesChk.Checked and (Nrows = 2) and (Ncols = 2);
|
|
|
|
if (Nrows > 1) and (Ncols > 1) then
|
|
|
|
begin
|
|
|
|
for i := 1 to Nrows do
|
|
|
|
begin
|
|
|
|
for j := 1 to Ncols do
|
|
|
|
begin
|
|
|
|
Expected[i-1,j-1] := Freq[Nrows,j-1] * Freq[i-1,Ncols] / Ncases;
|
|
|
|
if (Expected[i-1,j-1] > 0.0) then
|
|
|
|
CellChi[i-1,j-1] := sqr(Freq[i-1,j-1] - Expected[i-1,j-1])/ Expected[i-1,j-1]
|
|
|
|
else
|
2020-03-30 18:01:44 +00:00
|
|
|
begin
|
2020-10-29 22:17:02 +00:00
|
|
|
ErrorMsg('Zero expected value found.');
|
2020-04-05 17:25:38 +00:00
|
|
|
CellChi[i-1,j-1] := 0.0;
|
2020-03-30 18:01:44 +00:00
|
|
|
end;
|
2020-04-05 17:25:38 +00:00
|
|
|
ChiSquare := ChiSquare + CellChi[i-1,j-1];
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
df := (Nrows - 1) * (Ncols - 1);
|
2020-03-30 18:01:44 +00:00
|
|
|
|
2020-04-05 17:25:38 +00:00
|
|
|
if yates then // 2 x 2 corrected chi-square
|
|
|
|
begin
|
2020-10-29 22:17:02 +00:00
|
|
|
AdjChiSqr := abs((Freq[0,0] * Freq[1,1]) - (Freq[0,1] * Freq[1,0]));
|
|
|
|
AdjChiSqr := sqr(AdjChiSqr - Ncases / 2.0) * Ncases; // numerator
|
|
|
|
AdjChiSqr := AdjChiSqr / (Freq[0,2] * Freq[1,2] * Freq[2,0] * Freq[2,1]);
|
|
|
|
AdjProbChi := 1.0 - chisquaredprob(AdjChiSqr,df);
|
2020-04-05 17:25:38 +00:00
|
|
|
end;
|
|
|
|
end;
|
2020-03-30 18:01:44 +00:00
|
|
|
|
2020-04-05 17:25:38 +00:00
|
|
|
if (Nrows = 1) then // equal probability
|
|
|
|
begin
|
|
|
|
for j := 0 to Ncols - 1 do
|
|
|
|
begin
|
|
|
|
Expected[0,j] := Ncases / Ncols;
|
|
|
|
if (Expected[0][j] > 0) then
|
|
|
|
CellChi[0,j] := sqr(Freq[0,j] - Expected[0,j]) / Expected[0,j];
|
|
|
|
ChiSquare := ChiSquare + CellChi[0,j];
|
|
|
|
end;
|
|
|
|
df := Ncols - 1;
|
|
|
|
end;
|
2020-03-30 18:01:44 +00:00
|
|
|
|
2020-04-05 17:25:38 +00:00
|
|
|
if (Ncols = 1) then // equal probability
|
|
|
|
begin
|
|
|
|
for i := 0 to Nrows - 1 do
|
|
|
|
begin
|
|
|
|
Expected[i,0] := Ncases / Nrows;
|
|
|
|
if (Expected[i,0] > 0) then
|
|
|
|
CellChi[i,0] := sqr(Freq[i,0] - Expected[i,0]) / Expected[i,0];
|
|
|
|
ChiSquare := ChiSquare + CellChi[i,0];
|
|
|
|
end;
|
|
|
|
df := Nrows - 1;
|
|
|
|
end;
|
|
|
|
|
2020-10-29 22:17:02 +00:00
|
|
|
ProbChi := 1.0 - ChiSquaredProb(ChiSquare, df); // prob. larger chi
|
2020-04-05 17:25:38 +00:00
|
|
|
|
|
|
|
//Print results to output form
|
|
|
|
lReport := TStringList.Create;
|
|
|
|
try
|
|
|
|
lReport.Add('CHI-SQUARE ANALYSIS RESULTS');
|
|
|
|
lReport.Add('No. of Cases: %d', [Ncases]);
|
|
|
|
lReport.Add('');
|
2020-03-30 18:01:44 +00:00
|
|
|
|
|
|
|
// print tables requested by use
|
2020-04-05 17:25:38 +00:00
|
|
|
if ObsChk.Checked then
|
|
|
|
IntArrayPrint(Freq, Nrows+1, Ncols+1, 'Frequencies', RowLabels, ColLabels, 'OBSERVED FREQUENCIES', lReport);
|
|
|
|
|
|
|
|
if ExpChk.Checked then
|
2020-03-30 18:01:44 +00:00
|
|
|
begin
|
2020-04-05 17:25:38 +00:00
|
|
|
outline := 'EXPECTED FREQUENCIES';
|
|
|
|
MatPrint(Expected, Nrows, Ncols, outline, RowLabels, ColLabels, NoCases, lReport);
|
2020-03-30 18:01:44 +00:00
|
|
|
end;
|
|
|
|
|
2020-04-05 17:25:38 +00:00
|
|
|
for i := 1 to Nrows + 1 do
|
2020-03-30 18:01:44 +00:00
|
|
|
begin
|
2020-04-05 17:25:38 +00:00
|
|
|
for j := 1 to Ncols do
|
|
|
|
begin
|
|
|
|
if (Freq[i-1,Ncols] > 0.0) then
|
|
|
|
Prop[i-1,j-1] := Freq[i-1,j-1] / Freq[i-1,Ncols]
|
|
|
|
else
|
|
|
|
Prop[i-1,j-1] := 0.0;
|
|
|
|
end;
|
|
|
|
if (Freq[i-1,Ncols] > 0.0) then
|
|
|
|
Prop[i-1,Ncols] := 1.0
|
|
|
|
else
|
|
|
|
Prop[i-1,Ncols] := 0.0;
|
2020-03-30 18:01:44 +00:00
|
|
|
end;
|
|
|
|
|
2020-04-05 17:25:38 +00:00
|
|
|
if PropChk.Checked then
|
2020-03-30 18:01:44 +00:00
|
|
|
begin
|
2020-04-05 17:25:38 +00:00
|
|
|
outline := 'ROW PROPORTIONS';
|
|
|
|
MatPrint(Prop, Nrows+1, Ncols+1, outline, RowLabels, ColLabels, NoCases, lReport);
|
2020-03-30 18:01:44 +00:00
|
|
|
end;
|
2020-04-05 17:25:38 +00:00
|
|
|
|
2020-03-30 18:01:44 +00:00
|
|
|
for j := 1 to Ncols + 1 do
|
|
|
|
begin
|
2020-04-05 17:25:38 +00:00
|
|
|
for i := 1 to Nrows do
|
|
|
|
begin
|
|
|
|
if (Freq[Nrows,j-1] > 0.0) then
|
|
|
|
Prop[i-1,j-1] := Freq[i-1,j-1] / Freq[Nrows,j-1]
|
|
|
|
else
|
|
|
|
Prop[i-1,j-1] := 0.0;
|
|
|
|
end;
|
|
|
|
if (Freq[Nrows,j-1] > 0.0) then
|
|
|
|
Prop[Nrows,j-1] := 1.0
|
|
|
|
else
|
|
|
|
Prop[Nrows,j-1] := 0.0;
|
2020-03-30 18:01:44 +00:00
|
|
|
end;
|
|
|
|
if (PropChk.Checked) then
|
2020-04-05 17:25:38 +00:00
|
|
|
begin
|
|
|
|
outline := 'COLUMN PROPORTIONS';
|
|
|
|
MatPrint(Prop, Nrows+1, Ncols+1, outline, RowLabels, ColLabels, NoCases, lReport);
|
|
|
|
end;
|
2020-03-30 18:01:44 +00:00
|
|
|
|
2020-04-05 17:25:38 +00:00
|
|
|
if ChiChk.Checked then
|
2020-03-30 18:01:44 +00:00
|
|
|
begin
|
2020-04-05 17:25:38 +00:00
|
|
|
outline := 'CHI-SQUARED VALUE FOR CELLS';
|
|
|
|
MatPrint(CellChi, Nrows, Ncols, outline, RowLabels, ColLabels, NoCases, lReport);
|
2020-03-30 18:01:44 +00:00
|
|
|
end;
|
|
|
|
|
2020-04-05 17:25:38 +00:00
|
|
|
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
|
2020-03-30 18:01:44 +00:00
|
|
|
begin
|
2020-04-05 17:25:38 +00:00
|
|
|
lReport.Add('Chi-square using Yates correction: %8.3f', [AdjChiSqr]);
|
|
|
|
lReport.Add(' and Probability > value: %8.3f', [Adjprobchi]);
|
2020-03-30 18:01:44 +00:00
|
|
|
end;
|
|
|
|
|
2020-04-05 17:25:38 +00:00
|
|
|
likelihood := 0.0;
|
2020-03-30 18:01:44 +00:00
|
|
|
for i := 0 to Nrows - 1 do
|
|
|
|
for j := 0 to Ncols - 1 do
|
|
|
|
if (Freq[i,j] > 0.0) then
|
2020-04-05 17:25:38 +00:00
|
|
|
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.4f', [problikelihood]);
|
|
|
|
lReport.Add('');
|
2020-03-30 18:01:44 +00:00
|
|
|
|
|
|
|
if ((Nrows > 1) and (Ncols > 1)) then
|
|
|
|
begin
|
2020-04-05 17:25:38 +00:00
|
|
|
phi := sqrt(ChiSquare / Ncases);
|
|
|
|
lReport.Add('phi correlation: %8.4f', [phi]);
|
|
|
|
lReport.Add('');
|
|
|
|
|
|
|
|
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.4f', [pearsonr]);
|
|
|
|
lReport.Add('');
|
|
|
|
|
|
|
|
MantelHaenszel := (Ncases-1) * (pearsonr * pearsonr);
|
|
|
|
MHprob := 1.0 - chisquaredprob(MantelHaenszel,1);
|
|
|
|
lReport.Add('Mantel-Haenszel Test of Linear Association: %.3f with probability > value %.4f', [MantelHaenszel, MHprob]);
|
|
|
|
lReport.Add('');
|
|
|
|
|
|
|
|
CoefCont := sqrt(ChiSquare / (ChiSquare + Ncases));
|
|
|
|
lReport.Add('The coefficient of contingency: %8.3f', [CoefCont]);
|
|
|
|
lReport.Add('');
|
|
|
|
|
|
|
|
if (Nrows < Ncols) then
|
|
|
|
CramerV := sqrt(ChiSquare / (Ncases * ((Nrows-1))))
|
|
|
|
else
|
|
|
|
CramerV := sqrt(ChiSquare / (Ncases * ((Ncols-1))));
|
|
|
|
lReport.Add('Cramers V: %8.3f', [CramerV]);
|
2020-03-30 18:01:44 +00:00
|
|
|
end;
|
2020-04-05 17:25:38 +00:00
|
|
|
|
|
|
|
lReport.Add('');
|
|
|
|
lReport.Add('=============================================================================');
|
|
|
|
lReport.Add('');
|
2020-03-30 18:01:44 +00:00
|
|
|
|
|
|
|
// Now do RIDIT analysis
|
|
|
|
NoToAnalyze := ColList.Items.Count;
|
|
|
|
|
2020-04-05 17:25:38 +00:00
|
|
|
// do an analysis for each variable as a reference variable
|
|
|
|
if AllRefs then
|
2020-03-30 18:01:44 +00:00
|
|
|
begin
|
2020-04-05 17:25:38 +00:00
|
|
|
NoToAnalyze := ColList.Items.Count;
|
|
|
|
for i := 0 to NoToAnalyze - 1 do
|
|
|
|
begin
|
|
|
|
RefColNo := ColNoSelected[i+1] - 2;
|
|
|
|
Analyze(RefColNo, ColNoSelected, RowLabels,ColLabels, NoToAnalyze, Freq, Prop, Nrows, lReport);
|
|
|
|
end;
|
|
|
|
end else
|
|
|
|
// only one selected reference variable
|
2020-03-30 18:01:44 +00:00
|
|
|
begin
|
2020-04-05 17:25:38 +00:00
|
|
|
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;
|
2020-03-30 18:01:44 +00:00
|
|
|
|
2020-04-05 17:25:38 +00:00
|
|
|
for j := 0 to NoToAnalyze - 1 do
|
|
|
|
if (ColNoSelected[j+1] = RefColNo) then RefColNo := j;
|
|
|
|
|
|
|
|
Analyze(RefColNo, ColNoSelected, RowLabels,ColLabels, NoToAnalyze, Freq, Prop, Nrows, lReport);
|
2020-03-30 18:01:44 +00:00
|
|
|
end;
|
|
|
|
|
2020-10-29 22:17:02 +00:00
|
|
|
FReportFrame.DisplayReport(lReport);
|
2020-04-05 17:25:38 +00:00
|
|
|
|
|
|
|
finally
|
|
|
|
lReport.Free;
|
|
|
|
end;
|
2020-03-30 18:01:44 +00:00
|
|
|
end;
|
|
|
|
|
|
|
|
|
2020-10-29 22:17:02 +00:00
|
|
|
procedure TRIDITForm.RefGrpClick(Sender: TObject);
|
2020-03-30 18:01:44 +00:00
|
|
|
begin
|
2020-10-29 22:17:02 +00:00
|
|
|
RefEdit.Visible := RefGrp.ItemIndex > 0;
|
|
|
|
Label4.Visible := RefEdit.Visible;
|
|
|
|
end;
|
2020-04-05 17:25:38 +00:00
|
|
|
|
|
|
|
|
2020-10-29 22:17:02 +00:00
|
|
|
procedure TRIDITForm.Reset;
|
|
|
|
var
|
|
|
|
i: integer;
|
|
|
|
begin
|
|
|
|
inherited;
|
2020-04-05 17:25:38 +00:00
|
|
|
|
2020-10-29 22:17:02 +00:00
|
|
|
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 := true;
|
|
|
|
Label4.Visible := false;
|
|
|
|
RefEdit.Visible := false;
|
|
|
|
RefGrp.ItemIndex := 0;
|
2020-04-05 17:25:38 +00:00
|
|
|
|
2020-10-29 22:17:02 +00:00
|
|
|
UpdateBtnStates;
|
|
|
|
end;
|
2020-04-05 17:25:38 +00:00
|
|
|
|
|
|
|
|
2020-10-29 22:17:02 +00:00
|
|
|
procedure TRIDITForm.RowInClick(Sender: TObject);
|
|
|
|
var
|
|
|
|
index: integer;
|
|
|
|
begin
|
|
|
|
index := VarList.ItemIndex;
|
|
|
|
if (index > -1) and (RowEdit.Text = '') then
|
2020-04-05 17:25:38 +00:00
|
|
|
begin
|
2020-10-29 22:17:02 +00:00
|
|
|
RowEdit.Text := VarList.Items[index];
|
|
|
|
VarList.Items.Delete(index);
|
2020-04-05 17:25:38 +00:00
|
|
|
end;
|
2020-10-29 22:17:02 +00:00
|
|
|
UpdateBtnStates;
|
|
|
|
end;
|
2020-04-05 17:25:38 +00:00
|
|
|
|
2020-10-29 22:17:02 +00:00
|
|
|
|
|
|
|
procedure TRIDITForm.RowOutClick(Sender: TObject);
|
|
|
|
begin
|
|
|
|
if RowEdit.Text <> '' then
|
2020-04-05 17:25:38 +00:00
|
|
|
begin
|
2020-10-29 22:17:02 +00:00
|
|
|
VarList.Items.Add(RowEdit.Text);
|
|
|
|
RowEdit.Text := '';
|
2020-04-05 17:25:38 +00:00
|
|
|
end;
|
2020-10-29 22:17:02 +00:00
|
|
|
UpdateBtnStates;
|
|
|
|
end;
|
2020-04-05 17:25:38 +00:00
|
|
|
|
|
|
|
|
2020-10-29 22:17:02 +00:00
|
|
|
procedure TRIDITForm.UpdateBtnStates;
|
|
|
|
begin
|
|
|
|
inherited;
|
|
|
|
|
|
|
|
RowIn.Enabled := (VarList.ItemIndex > -1) and (RowEdit.Text = '');
|
|
|
|
RowOut.Enabled := (RowEdit.Text <> '');
|
2020-04-05 17:25:38 +00:00
|
|
|
|
2020-10-29 22:17:02 +00:00
|
|
|
ColIn.Enabled := AnySelected(VarList);
|
|
|
|
ColOut.Enabled := (ColList.ItemIndex > -1);
|
|
|
|
end;
|
2020-04-05 17:25:38 +00:00
|
|
|
|
|
|
|
|
2020-10-29 22:17:02 +00:00
|
|
|
function TRIDITForm.Validate(out AMsg: String; out AControl: TWinControl): Boolean;
|
|
|
|
var
|
|
|
|
tmp: Double;
|
|
|
|
begin
|
|
|
|
Result := false;
|
2020-04-05 17:25:38 +00:00
|
|
|
|
2020-10-29 22:17:02 +00:00
|
|
|
if AlphaEdit.Text = '' then
|
|
|
|
begin
|
|
|
|
AControl := AlphaEdit;
|
|
|
|
AMsg := 'Alpha level not specified.';
|
|
|
|
exit;
|
|
|
|
end;
|
2020-04-05 17:25:38 +00:00
|
|
|
|
2020-10-29 22:17:02 +00:00
|
|
|
if not TryStrToFloat(AlphaEdit.Text, tmp) then
|
|
|
|
begin
|
|
|
|
AControl := AlphaEdit;
|
|
|
|
AMsg := 'Numeric input required for alpha level.';
|
|
|
|
exit;
|
|
|
|
end;
|
2020-10-29 22:18:58 +00:00
|
|
|
|
2020-10-29 22:17:02 +00:00
|
|
|
if (tmp <= 0) or (tmp >= 1) then
|
|
|
|
begin
|
|
|
|
AControl := AlphaEdit;
|
|
|
|
AMsg := 'Alpha level must be > 0 and < 1';
|
|
|
|
exit;
|
|
|
|
end;
|
2020-04-05 17:25:38 +00:00
|
|
|
|
2020-10-29 22:17:02 +00:00
|
|
|
Result := true;
|
2020-04-05 17:25:38 +00:00
|
|
|
end;
|
|
|
|
|
2020-10-29 22:17:02 +00:00
|
|
|
|
|
|
|
procedure TRIDITForm.VarListDblClick(Sender: TObject);
|
|
|
|
var
|
|
|
|
index: Integer;
|
|
|
|
s: String;
|
2020-04-05 17:25:38 +00:00
|
|
|
begin
|
2020-10-29 22:17:02 +00:00
|
|
|
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;
|
2020-04-05 17:25:38 +00:00
|
|
|
end;
|
|
|
|
|
|
|
|
|
2020-10-29 22:17:02 +00:00
|
|
|
procedure TRIDITForm.VarListSelectionChange(Sender: TObject; User: boolean);
|
|
|
|
begin
|
|
|
|
UpdateBtnStates;
|
2020-03-30 18:01:44 +00:00
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
end.
|
|
|
|
|