2020-03-30 18:01:44 +00:00
|
|
|
unit ChiSqrUnit;
|
|
|
|
|
|
|
|
{$mode objfpc}{$H+}
|
2020-11-06 00:04:57 +00:00
|
|
|
{$WARN 6058 off : Call to subroutine "$1" marked as inline is not inlined}
|
2020-03-30 18:01:44 +00:00
|
|
|
interface
|
|
|
|
|
|
|
|
uses
|
2020-10-25 18:33:42 +00:00
|
|
|
Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs,
|
2020-10-25 21:41:09 +00:00
|
|
|
ExtCtrls, StdCtrls, Buttons, ComCtrls,
|
2020-10-26 10:56:48 +00:00
|
|
|
MainUnit, FunctionsLib, GraphLib, Globals, MatrixLib,
|
2020-10-25 21:41:09 +00:00
|
|
|
DictionaryUnit, ReportFrameUnit, BasicStatsReportFormUnit;
|
2020-03-30 18:01:44 +00:00
|
|
|
|
|
|
|
type
|
|
|
|
|
2020-10-26 14:02:37 +00:00
|
|
|
{ TChiSqrForm }
|
2020-03-30 18:01:44 +00:00
|
|
|
|
2020-10-26 14:02:37 +00:00
|
|
|
TChiSqrForm = class(TBasicStatsReportForm)
|
2020-03-30 18:01:44 +00:00
|
|
|
ObsChk: TCheckBox;
|
|
|
|
ExpChk: TCheckBox;
|
2020-10-25 21:41:09 +00:00
|
|
|
PageControl: TPageControl;
|
2020-03-30 18:01:44 +00:00
|
|
|
PropsChk: TCheckBox;
|
|
|
|
CellChiChk: TCheckBox;
|
|
|
|
SaveFChk: TCheckBox;
|
|
|
|
OptionsGroup: TGroupBox;
|
2020-10-25 21:41:09 +00:00
|
|
|
ResultsPage: TTabSheet;
|
|
|
|
FrequenciesPage: TTabSheet;
|
|
|
|
RowColPage: TTabSheet;
|
|
|
|
CellChiSqrPage: TTabSheet;
|
2020-03-30 18:01:44 +00:00
|
|
|
YatesChk: TCheckBox;
|
|
|
|
RowIn: TBitBtn;
|
|
|
|
RowOut: TBitBtn;
|
|
|
|
ColIn: TBitBtn;
|
|
|
|
ColOut: TBitBtn;
|
|
|
|
DepIn: TBitBtn;
|
|
|
|
DepOut: TBitBtn;
|
|
|
|
NCasesEdit: TEdit;
|
|
|
|
NCasesLabel: TLabel;
|
|
|
|
RowEdit: TEdit;
|
|
|
|
ColEdit: TEdit;
|
|
|
|
DepEdit: TEdit;
|
|
|
|
InputGrp: TRadioGroup;
|
|
|
|
Label1: TLabel;
|
2020-10-26 10:56:48 +00:00
|
|
|
RowLabel: TLabel;
|
|
|
|
ColLabel: TLabel;
|
|
|
|
DepLabel: TLabel;
|
2020-03-30 18:01:44 +00:00
|
|
|
VarList: TListBox;
|
|
|
|
procedure ColInClick(Sender: TObject);
|
|
|
|
procedure ColOutClick(Sender: TObject);
|
|
|
|
procedure DepInClick(Sender: TObject);
|
|
|
|
procedure DepOutClick(Sender: TObject);
|
|
|
|
procedure InputGrpClick(Sender: TObject);
|
|
|
|
procedure RowInClick(Sender: TObject);
|
|
|
|
procedure RowOutClick(Sender: TObject);
|
2020-10-25 18:33:42 +00:00
|
|
|
procedure VarListDblClick(Sender: TObject);
|
2020-10-26 10:56:48 +00:00
|
|
|
procedure VarListSelectionChange(Sender: TObject; {%H-}User: boolean);
|
2020-10-25 21:41:09 +00:00
|
|
|
|
2020-03-30 18:01:44 +00:00
|
|
|
private
|
2020-10-25 21:41:09 +00:00
|
|
|
FFrequenciesReportFrame: TReportFrame;
|
|
|
|
FRowColPropsReportFrame: TReportFrame;
|
|
|
|
FCellChiSqrReportFrame: TReportFrame;
|
|
|
|
|
2020-10-26 00:18:22 +00:00
|
|
|
function CalcGStatistic(const AFrequencies: IntDyneMat;
|
|
|
|
const AExpected: DblDyneMat): Double;
|
|
|
|
|
|
|
|
function CalcLikelihoodRatio(const AFrequencies: IntDyneMat;
|
|
|
|
const AExpected: DblDyneMat): Double;
|
|
|
|
|
|
|
|
function CalcPearsonR(const AFrequencies: IntDyneMat): Double;
|
|
|
|
|
2020-10-26 10:56:48 +00:00
|
|
|
procedure FrequenciesToGrid(const AFrequencies: IntDyneMat);
|
|
|
|
|
2020-10-26 00:18:22 +00:00
|
|
|
procedure GetExpectedAndCellChiSqr(const AFrequencies: IntDyneMat;
|
|
|
|
out AExpected, ACellChiSqr: DblDyneMat;
|
|
|
|
out AChiSqr: Double);
|
|
|
|
|
|
|
|
procedure GetFrequencies(const AColNoSelected: IntDyneVec;
|
|
|
|
ARowIndex, AColIndex, ADepIndex: Integer;
|
|
|
|
out ANumRows, ANumCols, ANumCases: Integer;
|
|
|
|
out AFrequencies: IntDyneMat);
|
|
|
|
|
|
|
|
procedure GetColProportions(const AFrequencies: IntDyneMat;
|
|
|
|
out AProportions: DblDyneMat);
|
|
|
|
|
|
|
|
procedure GetRowProportions(const AFrequencies: IntDyneMat;
|
|
|
|
out AProportions: DblDyneMat);
|
|
|
|
|
|
|
|
procedure GetTotalProportions(const AFrequencies: IntDyneMat;
|
|
|
|
out AProportions: DblDyneMat);
|
|
|
|
|
2020-10-31 23:13:18 +00:00
|
|
|
procedure GetYatesCorrection(const AFrequencies: IntDyneMat;
|
|
|
|
out AdjChiSqr: Double);
|
|
|
|
|
2020-10-26 10:56:48 +00:00
|
|
|
procedure ProcessAndReportCellChiSqr(const ACellChiSqr: DblDyneMat;
|
|
|
|
const ARowLabels, AColLabels: StrDyneVec; ANumCases: Integer);
|
|
|
|
|
|
|
|
procedure ProcessAndReportFrequencies(const AFrequencies: IntDyneMat;
|
|
|
|
const AExpected: DblDyneMat; const ARowLabels, AColLabels: StrDyneVec);
|
|
|
|
|
|
|
|
procedure ProcessAndReportProportions(const AFrequencies: IntDyneMat;
|
|
|
|
const ARowLabels, AColLabels: StrDyneVec);
|
|
|
|
|
2020-10-25 18:33:42 +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-25 18:33:42 +00:00
|
|
|
constructor Create(AOwner: TComponent); override;
|
|
|
|
procedure Reset; override;
|
2020-03-30 18:01:44 +00:00
|
|
|
end;
|
|
|
|
|
|
|
|
var
|
2020-10-26 14:02:37 +00:00
|
|
|
ChiSqrForm: TChiSqrForm;
|
2020-03-30 18:01:44 +00:00
|
|
|
|
|
|
|
implementation
|
|
|
|
|
2020-10-25 18:33:42 +00:00
|
|
|
{$R *.lfm}
|
|
|
|
|
2020-03-30 18:01:44 +00:00
|
|
|
uses
|
2020-10-25 21:41:09 +00:00
|
|
|
Math,
|
2020-10-26 00:18:22 +00:00
|
|
|
Utils, GridProcs, MatrixUnit;
|
2020-03-30 18:01:44 +00:00
|
|
|
|
2020-10-26 14:02:37 +00:00
|
|
|
{ TChiSqrForm }
|
2020-03-30 18:01:44 +00:00
|
|
|
|
2020-10-26 14:02:37 +00:00
|
|
|
constructor TChiSqrForm.Create(AOwner: TComponent);
|
2020-03-30 18:01:44 +00:00
|
|
|
begin
|
2020-10-25 18:33:42 +00:00
|
|
|
inherited;
|
|
|
|
if DictionaryFrm = nil then
|
|
|
|
Application.CreateForm(TDictionaryFrm, DictionaryFrm);
|
2020-10-25 21:41:09 +00:00
|
|
|
|
|
|
|
FReportFrame.Parent := ResultsPage;
|
|
|
|
FReportFrame.BorderSpacing.Left := 0;
|
|
|
|
FReportFrame.BorderSpacing.Top := 0;
|
|
|
|
FReportFrame.BorderSpacing.Bottom := 0;
|
|
|
|
FReportFrame.BorderSpacing.Right := 0;
|
|
|
|
InitToolbar(FReportFrame.ReportToolbar, tpRight);
|
|
|
|
|
|
|
|
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 := RowColPage;
|
|
|
|
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;
|
2020-03-30 18:01:44 +00:00
|
|
|
end;
|
|
|
|
|
2020-10-25 21:41:09 +00:00
|
|
|
|
2020-10-26 14:02:37 +00:00
|
|
|
procedure TChiSqrForm.AdjustConstraints;
|
2020-03-30 18:01:44 +00:00
|
|
|
begin
|
2020-10-25 18:33:42 +00:00
|
|
|
inherited;
|
|
|
|
|
|
|
|
ParamsPanel.Constraints.MinWidth := MaxValue([
|
|
|
|
4*CloseBtn.Width + 3*CloseBtn.BorderSpacing.Left,
|
|
|
|
OptionsGroup.Width,
|
|
|
|
InputGrp.Width
|
|
|
|
]);
|
|
|
|
ParamsPanel.Constraints.MinHeight := NCasesEdit.Top + NCasesEdit.Height +
|
|
|
|
OptionsGroup.BorderSpacing.Top + OptionsGroup.Height +
|
|
|
|
ButtonBevel.Height + CloseBtn.BorderSpacing.Top + CloseBtn.Height;
|
2020-03-30 18:01:44 +00:00
|
|
|
end;
|
|
|
|
|
|
|
|
|
2020-10-26 14:02:37 +00:00
|
|
|
function TChiSqrForm.CalcGStatistic(const AFrequencies: IntDyneMat;
|
2020-10-26 00:18:22 +00:00
|
|
|
const AExpected: DblDyneMat): Double;
|
|
|
|
var
|
|
|
|
numRows, numCols: Integer;
|
|
|
|
i, j: Integer;
|
|
|
|
begin
|
|
|
|
MatSize(AExpected, numRows, numCols);
|
|
|
|
Result := 0.0;
|
|
|
|
for i := 0 to numRows-1 do
|
|
|
|
for j := 0 to numCols-1 do
|
|
|
|
if (AExpected[i, j] > 0) then
|
|
|
|
Result := Result + AFrequencies[i, j] * ln(AFrequencies[i, j] / AExpected[i, j]);
|
|
|
|
Result := 2.0 * Result;
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
2020-10-26 14:02:37 +00:00
|
|
|
function TChiSqrForm.CalcLikelihoodRatio(const AFrequencies: IntDyneMat;
|
2020-10-26 00:18:22 +00:00
|
|
|
const AExpected: DblDyneMat): Double;
|
|
|
|
var
|
|
|
|
numRows, numCols: Integer;
|
|
|
|
i, j: Integer;
|
|
|
|
begin
|
|
|
|
MatSize(AExpected, numRows, numCols);
|
|
|
|
Result := 0.0;
|
|
|
|
for i := 0 to numRows-1 do
|
|
|
|
for j := 0 to numCols-1 do
|
|
|
|
if (AFrequencies[i, j] > 0.0) then
|
|
|
|
Result := Result + AFrequencies[i, j] * ln(AExpected[i, j] / AFrequencies[i, j]);
|
|
|
|
Result := -2.0 * Result;
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
2020-10-26 14:02:37 +00:00
|
|
|
function TChiSqrForm.CalcPearsonR(const AFrequencies: IntDyneMat): Double;
|
2020-10-26 00:18:22 +00:00
|
|
|
var
|
|
|
|
numRows, numCols, numCases: Integer;
|
|
|
|
sumX, sumY: Double;
|
|
|
|
varX, varY: Double;
|
|
|
|
i, j: Integer;
|
|
|
|
begin
|
|
|
|
MatSize(AFrequencies, numRows, numCols);
|
|
|
|
dec(numRows); // Do not iterate into the totals row and column
|
|
|
|
dec(numCols);
|
|
|
|
numCases := AFrequencies[numRows, numCols];
|
|
|
|
|
|
|
|
SumX := 0;
|
|
|
|
SumY := 0;
|
|
|
|
VarX := 0;
|
|
|
|
VarY := 0;
|
|
|
|
|
|
|
|
for i := 0 to numRows-1 do
|
|
|
|
sumX := sumX + ( (i+1) * AFrequencies[i, numCols] );
|
|
|
|
for j := 0 to numCols-1 do
|
|
|
|
sumY := sumY + ( (j+1) * AFrequencies[numRows, j] );
|
|
|
|
for i := 0 to numRows-1 do
|
|
|
|
varX := varX + ( sqr(i+1) * AFrequencies[i, numCols] );
|
|
|
|
for j := 0 to numCols-1 do
|
|
|
|
varY := varY + ( sqr(j+1) * AFrequencies[numRows, j] );
|
|
|
|
varX := varX - sqr(sumX) / numCases;
|
|
|
|
varY := varY - sqr(sumY) / numCases;
|
|
|
|
|
|
|
|
Result := 0;
|
|
|
|
for i := 0 to numRows-1 do
|
|
|
|
for j := 0 to numCols-1 do
|
|
|
|
Result := Result + ((i+1)*(j+1) * AFrequencies[i, j]);
|
|
|
|
|
|
|
|
Result := Result - (sumX * sumY / numCases);
|
|
|
|
Result := Result / sqrt(varX * varY);
|
|
|
|
end;
|
|
|
|
|
2020-10-26 14:02:37 +00:00
|
|
|
procedure TChiSqrForm.ColInClick(Sender: TObject);
|
2020-03-30 18:01:44 +00:00
|
|
|
var
|
|
|
|
index: integer;
|
|
|
|
begin
|
|
|
|
index := VarList.ItemIndex;
|
|
|
|
if (index > -1) and (ColEdit.Text = '') then
|
|
|
|
begin
|
|
|
|
ColEdit.Text := VarList.Items[index];
|
|
|
|
VarList.Items.Delete(index);
|
|
|
|
end;
|
|
|
|
UpdateBtnStates;
|
|
|
|
end;
|
|
|
|
|
2020-10-25 18:33:42 +00:00
|
|
|
|
2020-10-26 14:02:37 +00:00
|
|
|
procedure TChiSqrForm.ColOutClick(Sender: TObject);
|
2020-03-30 18:01:44 +00:00
|
|
|
begin
|
|
|
|
if ColEdit.Text <> '' then
|
|
|
|
begin
|
|
|
|
VarList.Items.Add(ColEdit.Text);
|
|
|
|
ColEdit.Text := '';
|
|
|
|
end;
|
|
|
|
UpdateBtnStates;
|
|
|
|
end;
|
|
|
|
|
2020-10-25 18:33:42 +00:00
|
|
|
|
2020-10-26 14:02:37 +00:00
|
|
|
procedure TChiSqrForm.Compute;
|
2020-03-30 18:01:44 +00:00
|
|
|
var
|
2020-10-25 18:33:42 +00:00
|
|
|
ColNoSelected: IntDyneVec = nil;
|
|
|
|
Freq: IntDyneMat = nil;
|
|
|
|
Expected: DblDyneMat = nil;
|
|
|
|
CellChi: DblDyneMat = nil;
|
2020-10-25 21:41:09 +00:00
|
|
|
RowLabels: StrDyneVec = nil;
|
|
|
|
ColLabels: StrDyneVec = nil;
|
2020-10-26 00:18:22 +00:00
|
|
|
yates : boolean;
|
2020-10-25 21:41:09 +00:00
|
|
|
NoSelected, NCases, NRows, NCols: Integer;
|
2020-10-26 00:18:22 +00:00
|
|
|
i, j, rowNo, colNo, depNo: integer;
|
2020-10-26 18:00:52 +00:00
|
|
|
df: integer;
|
2020-10-26 00:18:22 +00:00
|
|
|
ChiSquare, probChi, phi: double;
|
|
|
|
AdjChiSqr, AdjProbChi, pearsonr, G, likelihood, MantelHaenszel, prob: double;
|
2020-10-25 21:41:09 +00:00
|
|
|
CoefCont, CramerV: double;
|
2020-10-25 18:33:42 +00:00
|
|
|
lReport: TStrings;
|
2020-03-30 18:01:44 +00:00
|
|
|
begin
|
2020-10-26 00:18:22 +00:00
|
|
|
rowNo := GetVariableIndex(OS3MainFrm.DataGrid, RowEdit.Text);
|
|
|
|
colNo := GetVariableIndex(OS3MainFrm.DataGrid, ColEdit.Text);
|
|
|
|
depNo := GetVariableIndex(OS3MainFrm.DataGrid, DepEdit.Text);
|
2020-10-25 21:41:09 +00:00
|
|
|
|
|
|
|
SetLength(ColNoSelected, NoVariables);
|
|
|
|
ColNoSelected[0] := RowNo;
|
|
|
|
ColNoSelected[1] := ColNo;
|
|
|
|
NoSelected := 2;
|
|
|
|
if InputGrp.ItemIndex > 0 then // for reading proportions or frequencies
|
|
|
|
begin
|
|
|
|
NoSelected := 3;
|
|
|
|
ColNoSelected[2] := DepNo;
|
|
|
|
end;
|
2020-10-26 00:18:22 +00:00
|
|
|
SetLength(ColNoSelected, NoSelected); // trim length
|
2020-10-25 21:41:09 +00:00
|
|
|
|
2020-10-26 00:18:22 +00:00
|
|
|
// Get frequencies from the grid
|
|
|
|
GetFrequencies(ColNoselected, rowNo, colNo, depNo, nRows, nCols, nCases, Freq);
|
|
|
|
df := (nRows - 1) * (nCols - 1);
|
2020-10-25 21:41:09 +00:00
|
|
|
|
2020-10-26 00:18:22 +00:00
|
|
|
// Calculate expected values and cell chi-squares
|
|
|
|
GetExpectedAndCellChiSqr(Freq, Expected, CellChi, ChiSquare);
|
2020-10-26 10:56:48 +00:00
|
|
|
ProbChi := 1.0 - ChiSquaredProb(ChiSquare, df); // prob. > chi
|
2020-10-25 21:41:09 +00:00
|
|
|
|
2020-10-26 10:56:48 +00:00
|
|
|
// Yates correction
|
2020-10-26 00:18:22 +00:00
|
|
|
yates := YatesChk.Checked and (nRows = 2) and (nCols = 2);
|
|
|
|
if yates then begin
|
|
|
|
GetYatesCorrection(Freq, AdjChiSqr);
|
2020-10-25 21:41:09 +00:00
|
|
|
AdjProbChi := 1.0 - ChiSquaredProb(AdjChiSqr, df);
|
2020-10-26 00:18:22 +00:00
|
|
|
end else
|
|
|
|
AdjChiSqr := 0;
|
2020-10-25 21:41:09 +00:00
|
|
|
|
2020-10-26 00:18:22 +00:00
|
|
|
// Get row and column labels for reports
|
|
|
|
SetLength(RowLabels, NRows+1);
|
2020-10-25 21:41:09 +00:00
|
|
|
for i := 1 to NRows do RowLabels[i-1] := Format('Row %d', [i]);
|
|
|
|
RowLabels[NRows] := 'Total';
|
|
|
|
|
2020-10-26 00:18:22 +00:00
|
|
|
SetLength(ColLabels, NCols+1);
|
2020-10-25 21:41:09 +00:00
|
|
|
for j := 1 to NCols do ColLabels[j-1] := Format('Col.%d', [j]);
|
|
|
|
ColLabels[NCols] := 'Total';
|
|
|
|
|
2020-10-26 10:56:48 +00:00
|
|
|
// Print main results to report frame
|
2020-10-25 21:41:09 +00:00
|
|
|
lReport := TStringList.Create;
|
|
|
|
try
|
|
|
|
lReport.Add('CHI-SQUARE ANALYSIS RESULTS');
|
|
|
|
lReport.Add('');
|
|
|
|
lReport.Add('Chi-square: %.3f', [ChiSquare]);
|
|
|
|
lReport.Add(' with %d degrees of freedom', [DF]);
|
|
|
|
lReport.Add(' Probability > value is %.4f', [ProbChi]);
|
|
|
|
lReport.Add('');
|
|
|
|
if yates then
|
|
|
|
begin
|
|
|
|
lReport.Add('Chi-square using Yates correction: %.3f', [AdjChiSqr]);
|
|
|
|
lReport.Add(' Probability > value is %.4f', [AdjProbChi]);
|
|
|
|
lReport.Add('');
|
2020-03-30 18:01:44 +00:00
|
|
|
end;
|
|
|
|
|
2020-10-26 00:18:22 +00:00
|
|
|
likelihood := CalcLikelihoodRatio(Freq, Expected);
|
|
|
|
prob := 1.0 - ChiSquaredProb(likelihood, df);
|
2020-10-25 21:41:09 +00:00
|
|
|
lReport.Add('Likelihood Ratio: %.3f', [likelihood]);
|
2020-10-26 00:18:22 +00:00
|
|
|
lReport.Add(' Probability > value is %.4f', [prob]);
|
2020-10-25 21:41:09 +00:00
|
|
|
lReport.Add('');
|
|
|
|
|
2020-10-26 00:18:22 +00:00
|
|
|
G := CalcGStatistic(Freq, Expected);
|
|
|
|
prob := 1.0 - ChiSquaredProb(G, df);
|
2020-10-25 21:41:09 +00:00
|
|
|
lReport.Add('G statistic: %.3f ', [G]);
|
2020-10-26 00:18:22 +00:00
|
|
|
lReport.Add(' Probability > value is %.4f', [prob]);
|
2020-10-25 21:41:09 +00:00
|
|
|
lReport.Add('');
|
|
|
|
|
|
|
|
if ((NRows > 1) and (NCols > 1)) then
|
2020-03-30 18:01:44 +00:00
|
|
|
begin
|
2020-10-25 21:41:09 +00:00
|
|
|
phi := sqrt(ChiSquare / NCases);
|
|
|
|
lReport.Add('phi correlation: %.4f', [phi]);
|
|
|
|
lReport.Add('');
|
|
|
|
|
2020-10-26 00:18:22 +00:00
|
|
|
pearsonR := CalcPearsonR(Freq);
|
2020-10-25 21:41:09 +00:00
|
|
|
lReport.Add('Pearson Correlation r: %.4f', [pearsonR]);
|
|
|
|
lReport.Add('');
|
|
|
|
|
|
|
|
MantelHaenszel := (NCases-1) * sqr(pearsonR);
|
2020-10-26 00:18:22 +00:00
|
|
|
prob := 1.0 - ChiSquaredProb(MantelHaenszel, 1);
|
2020-10-25 21:41:09 +00:00
|
|
|
lReport.Add('Mantel-Haenszel Test of Linear Association: %.3f', [MantelHaenszel]);
|
2020-10-26 00:18:22 +00:00
|
|
|
lReport.Add(' Probability > value is %.4f', [prob]);
|
2020-10-25 21:41:09 +00:00
|
|
|
lReport.Add('');
|
|
|
|
|
|
|
|
CoefCont := sqrt(ChiSquare / (ChiSquare + NCases));
|
|
|
|
lReport.Add('The coefficient of contingency is %.3f', [CoefCont]);
|
|
|
|
lReport.Add('');
|
|
|
|
|
|
|
|
if (Nrows < Ncols) then
|
2020-10-26 00:18:22 +00:00
|
|
|
CramerV := sqrt(ChiSquare / (NCases * ((NRows-1))))
|
2020-10-25 21:41:09 +00:00
|
|
|
else
|
2020-10-26 00:18:22 +00:00
|
|
|
CramerV := sqrt(ChiSquare / (NCases * ((NCols-1))));
|
2020-10-25 21:41:09 +00:00
|
|
|
lReport.Add('Cramers V is %.3f', [CramerV]);
|
|
|
|
lReport.Add('');
|
2020-03-30 18:01:44 +00:00
|
|
|
end;
|
|
|
|
|
2020-10-25 21:41:09 +00:00
|
|
|
FReportFrame.DisplayReport(lReport);
|
|
|
|
finally
|
|
|
|
lReport.Free;
|
|
|
|
end;
|
|
|
|
|
2020-10-26 10:56:48 +00:00
|
|
|
// Print frequencies tables if requested by user
|
|
|
|
if ObsChk.Checked or ExpChk.Checked then
|
2020-10-25 21:41:09 +00:00
|
|
|
begin
|
2020-10-26 10:56:48 +00:00
|
|
|
FrequenciesPage.TabVisible := true;
|
|
|
|
ProcessAndReportFrequencies(Freq, Expected, RowLabels, ColLabels);
|
|
|
|
end else
|
|
|
|
FrequenciesPage.TabVisible := false;
|
2020-10-25 21:41:09 +00:00
|
|
|
|
2020-10-26 10:56:48 +00:00
|
|
|
// Print proportions if requested by user
|
|
|
|
if PropsChk.Checked then
|
|
|
|
begin
|
|
|
|
RowColPage.TabVisible := true;
|
|
|
|
ProcessAndReportProportions(Freq, RowLabels, ColLabels);
|
|
|
|
end else
|
|
|
|
RowColPage.TabVisible := false;
|
|
|
|
|
|
|
|
// Print cell chisqr values if requested by user
|
|
|
|
if CellChiChk.Checked then
|
|
|
|
begin
|
|
|
|
CellChiSqrPage.TabVisible := true;
|
|
|
|
ProcessAndReportCellChiSqr(CellChi, RowLabels, ColLabels, NCases);
|
|
|
|
end else
|
|
|
|
CellChiSqrPage.TabVisible := false;
|
|
|
|
|
|
|
|
// Save frequency data in grid if elected.
|
|
|
|
// NOTE: THIS WILL CLOSE CURRENT FILE!
|
|
|
|
if SaveFChk.Checked and
|
|
|
|
(MessageDlg('This operation will close the current data file. Continue?',
|
|
|
|
mtConfirmation, [mbYes, mbNo], 0) = mrYes)
|
|
|
|
then begin
|
|
|
|
FrequenciesToGrid(Freq);
|
|
|
|
Reset; // the grids contains new variables which must be read.
|
|
|
|
SaveFChk.Checked := false;
|
2020-10-26 00:18:22 +00:00
|
|
|
end;
|
2020-03-30 18:01:44 +00:00
|
|
|
end;
|
|
|
|
|
2020-10-25 18:33:42 +00:00
|
|
|
|
2020-10-26 14:02:37 +00:00
|
|
|
procedure TChiSqrForm.DepInClick(Sender: TObject);
|
2020-03-30 18:01:44 +00:00
|
|
|
var
|
|
|
|
index: integer;
|
|
|
|
begin
|
|
|
|
index := VarList.ItemIndex;
|
|
|
|
if (index > -1) and (DepEdit.Text = '') then
|
|
|
|
begin
|
|
|
|
DepEdit.Text := VarList.Items[index];
|
|
|
|
VarList.Items.Delete(index);
|
|
|
|
end;
|
|
|
|
UpdateBtnStates;
|
|
|
|
end;
|
|
|
|
|
2020-10-25 18:33:42 +00:00
|
|
|
|
2020-10-26 14:02:37 +00:00
|
|
|
procedure TChiSqrForm.DepOutClick(Sender: TObject);
|
2020-03-30 18:01:44 +00:00
|
|
|
begin
|
|
|
|
if DepEdit.Text <> '' then
|
|
|
|
begin
|
|
|
|
VarList.Items.Add(DepEdit.Text);
|
|
|
|
DepEdit.Text := '';
|
|
|
|
end;
|
|
|
|
UpdateBtnStates;
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
2020-10-26 14:02:37 +00:00
|
|
|
procedure TChiSqrForm.FrequenciesToGrid(const AFrequencies: IntDyneMat);
|
2020-10-26 10:56:48 +00:00
|
|
|
var
|
|
|
|
numRows, numCols: Integer;
|
|
|
|
row, col: Integer;
|
|
|
|
i, j: Integer;
|
|
|
|
colLabels: StrDyneVec = nil;
|
|
|
|
begin
|
|
|
|
MatSize(AFrequencies, numRows, numCols); // contains totals in last row/col
|
|
|
|
dec(numRows); // we don't need the totals
|
|
|
|
dec(numCols);
|
|
|
|
|
|
|
|
OS3MainFrm.mnuFileCloseClick(self);
|
|
|
|
OS3MainFrm.FileNameEdit.Text := '';
|
|
|
|
for i := 1 to DictionaryFrm.DictGrid.RowCount - 1 do
|
|
|
|
for j := 0 to 7 do DictionaryFrm.DictGrid.Cells[j,i] := '';
|
|
|
|
DictionaryFrm.DictGrid.RowCount := 1;
|
|
|
|
|
|
|
|
// get labels for new file
|
|
|
|
SetLength(colLabels, 3);
|
|
|
|
colLabels[0] := 'ROW';
|
|
|
|
colLabels[1] := 'COL';
|
|
|
|
colLabels[2] := 'FREQ';
|
|
|
|
|
|
|
|
// create new variables
|
|
|
|
OS3MainFrm.DataGrid.ColCount := 4;
|
|
|
|
DictionaryFrm.DictGrid.ColCount := 8;
|
|
|
|
NoVariables := 0;
|
|
|
|
for i := 0 to High(colLabels) do
|
|
|
|
begin
|
|
|
|
col := NoVariables + 1;
|
|
|
|
DictionaryFrm.NewVar(col); // increments NoVariables!
|
|
|
|
DictionaryFrm.DictGrid.Cells[1, col] := ColLabels[i];
|
|
|
|
OS3MainFrm.DataGrid.Cells[col, 0] := ColLabels[i];
|
|
|
|
end;
|
|
|
|
OS3MainFrm.DataGrid.RowCount := (numRows * numCols) + 1;
|
|
|
|
|
|
|
|
row := 0;
|
|
|
|
for i := 0 to numRows-1 do
|
|
|
|
begin
|
|
|
|
for j := 0 to numCols-1 do
|
|
|
|
begin
|
|
|
|
row := row + 1;
|
|
|
|
OS3MainFrm.DataGrid.Cells[0, Row] := Format('Case %d', [row]);
|
|
|
|
OS3MainFrm.DataGrid.Cells[1, Row] := IntToStr(i+1);
|
|
|
|
OS3MainFrm.DataGrid.Cells[2, Row] := IntToStr(j+1);
|
|
|
|
OS3MainFrm.DataGrid.Cells[3, Row] := IntToStr(AFrequencies[i, j]);
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
NoCases := row;
|
|
|
|
OS3MainFrm.FileNameEdit.Text := 'ChiSqrFreq.laz';
|
|
|
|
OS3MainFrm.NoCasesEdit.Text := IntToStr(NoCases);
|
|
|
|
OS3MainFrm.NoVarsEdit.Text := IntToStr(NoVariables);
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
2020-10-26 14:02:37 +00:00
|
|
|
procedure TChiSqrForm.GetExpectedAndCellChiSqr(const AFrequencies: IntDyneMat;
|
2020-10-26 00:18:22 +00:00
|
|
|
out AExpected, ACellChiSqr: DblDyneMat;
|
|
|
|
out AChiSqr: Double);
|
|
|
|
var
|
2020-10-26 10:56:48 +00:00
|
|
|
n, m, numCases: Integer;
|
2020-10-26 00:18:22 +00:00
|
|
|
i, j: Integer;
|
|
|
|
begin
|
2020-10-26 10:56:48 +00:00
|
|
|
MatSize(AFrequencies, n, m); // contains the totals row/col
|
|
|
|
numCases := AFrequencies[n-1, m-1];
|
2020-10-26 00:18:22 +00:00
|
|
|
|
2020-10-26 10:56:48 +00:00
|
|
|
AExpected := nil;
|
|
|
|
ACellChiSqr := nil;
|
|
|
|
SetLength(AExpected, n-1, m-1); // -1: we don't need the totals here
|
|
|
|
SetLength(ACellChiSqr, n-1, m-1);
|
2020-10-26 00:18:22 +00:00
|
|
|
|
|
|
|
AChiSqr := 0;
|
2020-10-26 10:56:48 +00:00
|
|
|
for i := 0 to n-2 do // -2 instead of -1 to skip the totals row
|
2020-10-26 00:18:22 +00:00
|
|
|
begin
|
2020-10-26 10:56:48 +00:00
|
|
|
for j := 0 to m-2 do // -2 instead of -1 to skip the totals column
|
2020-10-26 00:18:22 +00:00
|
|
|
begin
|
2020-10-26 10:56:48 +00:00
|
|
|
AExpected[i, j] := AFrequencies[n-1, j] * AFrequencies[i, m-1] / numCases;
|
2020-10-26 00:18:22 +00:00
|
|
|
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;
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
2020-10-26 14:02:37 +00:00
|
|
|
procedure TChiSqrForm.GetFrequencies(const AColNoSelected: IntDyneVec;
|
2020-10-26 00:18:22 +00:00
|
|
|
ARowIndex, AColIndex, ADepIndex: Integer; out ANumRows, ANumCols, ANumCases: Integer;
|
|
|
|
out AFrequencies: IntDyneMat);
|
|
|
|
var
|
|
|
|
i, j: Integer;
|
|
|
|
row, col: Integer;
|
|
|
|
minRow, maxRow, minCol, maxCol: Integer;
|
|
|
|
FObs: Integer;
|
|
|
|
PObs: Double;
|
|
|
|
begin
|
|
|
|
// Get min and max of row and col numbers
|
|
|
|
minRow := MaxInt;
|
|
|
|
maxRow := -MinRow;
|
|
|
|
minCol := MaxInt;
|
|
|
|
maxCol := -MinCol;
|
|
|
|
for i := 1 to NoCases do
|
|
|
|
begin
|
|
|
|
if not GoodRecord(OS3MainFrm.DataGrid, i, AColNoSelected) then continue;
|
|
|
|
row := round(StrToFloat(Trim(OS3MainFrm.DataGrid.Cells[ARowIndex, i])));
|
|
|
|
col := round(StrToFloat(Trim(OS3MainFrm.DataGrid.Cells[AColIndex, i])));
|
|
|
|
if row > maxRow then maxRow := row;
|
|
|
|
if row < minRow then minRow := row;
|
|
|
|
if col > maxCol then maxCol := col;
|
|
|
|
if col < minCol then minCol := col;
|
|
|
|
end;
|
|
|
|
ANumRows := maxRow - minRow + 1;
|
|
|
|
ANumCols := maxCol - minCol + 1;
|
|
|
|
|
|
|
|
AFrequencies := nil;
|
|
|
|
SetLength(AFrequencies, ANumRows+1, ANumCols+1); // +1 for row and column totals
|
|
|
|
|
|
|
|
ANumCases := 0;
|
|
|
|
case InputGrp.ItemIndex of
|
|
|
|
0 : begin // count number of cases in each row and column combination
|
|
|
|
for i := 1 to NoCases do
|
|
|
|
begin
|
|
|
|
if not GoodRecord(OS3MainFrm.DataGrid, i, AColNoSelected) then continue;
|
|
|
|
row := round(StrToFloat(Trim(OS3MainFrm.DataGrid.Cells[ARowIndex, i])));
|
|
|
|
col := round(StrToFloat(Trim(OS3MainFrm.DataGrid.Cells[AColIndex, i])));
|
|
|
|
row := row - minRow;
|
|
|
|
col := col - minCol;
|
|
|
|
AFrequencies[row, col] := AFrequencies[row, col] + 1;
|
|
|
|
ANumCases := ANumCases + 1;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
1 : begin // read frequencies data from grid
|
|
|
|
for i := 1 to NoCases do
|
|
|
|
begin
|
|
|
|
if not GoodRecord(OS3MainFrm.DataGrid, i, AColNoSelected) then continue;
|
|
|
|
row := round(StrToFloat(Trim(OS3MainFrm.DataGrid.Cells[ARowIndex, i])));
|
2020-10-26 10:56:48 +00:00
|
|
|
col := round(StrToFloat(Trim(OS3MainFrm.DataGrid.Cells[AColIndex, i])));
|
2020-10-26 00:18:22 +00:00
|
|
|
row := row - minRow;
|
|
|
|
col := col - minCol;
|
|
|
|
FObs := round(StrToFloat(Trim(OS3MainFrm.DataGrid.Cells[ADepIndex, i])));
|
|
|
|
AFrequencies[row, col] := AFrequencies[row, col] + FObs;
|
|
|
|
ANumCases := ANumCases + FObs;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
2 : begin // get no. of cases and proportions for each cell
|
|
|
|
ANumCases := StrToInt(NCasesEdit.Text);
|
|
|
|
for i := 1 to NoCases do
|
|
|
|
begin
|
|
|
|
if not GoodRecord(OS3MainFrm.Datagrid, i, AColNoSelected) then continue;
|
|
|
|
row := round(StrToFloat(Trim(OS3MainFrm.DataGrid.Cells[ARowIndex, i])));
|
|
|
|
col := round(StrToFloat(Trim(OS3MainFrm.DataGrid.Cells[AColIndex, i])));
|
|
|
|
row := row - minRow + 1;
|
|
|
|
col := col - minCol + 1;
|
|
|
|
PObs := StrToFloat(Trim(OS3MainFrm.DataGrid.Cells[ADepIndex, i]));
|
|
|
|
AFrequencies[row, col] := AFrequencies[row, col] + round(PObs * ANumCases);
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
// Get 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];
|
|
|
|
|
|
|
|
// Get 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];
|
|
|
|
|
|
|
|
// Grand total
|
|
|
|
AFrequencies[ANumRows, ANumCols] := ANumCases;
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
// 2 x 2 corrected chi-square
|
2020-10-26 14:02:37 +00:00
|
|
|
procedure TChiSqrForm.GetYatesCorrection(const AFrequencies: IntDyneMat;
|
2020-10-26 00:18:22 +00:00
|
|
|
out AdjChiSqr: Double);
|
|
|
|
var
|
2020-10-26 10:56:48 +00:00
|
|
|
n, m, numCases: Integer;
|
2020-10-26 00:18:22 +00:00
|
|
|
begin
|
2020-10-26 10:56:48 +00:00
|
|
|
MatSize(AFrequencies, n, m);
|
|
|
|
numCases := AFrequencies[n-1, m-1];
|
2020-10-26 00:18:22 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
2020-10-26 14:02:37 +00:00
|
|
|
procedure TChiSqrForm.GetColProportions(const AFrequencies: IntDyneMat;
|
2020-10-26 00:18:22 +00:00
|
|
|
out AProportions: DblDyneMat);
|
|
|
|
var
|
|
|
|
numRows, numCols: Integer;
|
|
|
|
i, j: Integer;
|
|
|
|
begin
|
2020-10-26 10:56:48 +00:00
|
|
|
AProportions := nil;
|
2020-10-26 00:18:22 +00:00
|
|
|
MatSize(AFrequencies, numRows, numCols); // totals in last row/col
|
|
|
|
SetLength(AProportions, numRows, numCols);
|
|
|
|
for j := 0 to numCols-1 do
|
|
|
|
begin
|
|
|
|
for i := 0 to numRows-1 do // Do not process the totals row
|
|
|
|
begin
|
|
|
|
if AFrequencies[numRows-1, j] > 0.0 then
|
|
|
|
AProportions[i, j] := AFrequencies[i, j] / AFrequencies[numRows-1, j]
|
|
|
|
else
|
|
|
|
AProportions[i, j] := 0.0;
|
|
|
|
end;
|
|
|
|
if AFrequencies[numRows-1, j] > 0.0 then
|
|
|
|
AProportions[numRows-1,j] := 1.0
|
|
|
|
else
|
|
|
|
AProportions[numRows-1,j] := 0.0;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
2020-10-26 14:02:37 +00:00
|
|
|
procedure TChiSqrForm.GetRowProportions(const AFrequencies: IntDyneMat;
|
2020-10-26 00:18:22 +00:00
|
|
|
out AProportions: DblDyneMat);
|
|
|
|
var
|
|
|
|
numRows, numCols: Integer;
|
|
|
|
i, j: Integer;
|
|
|
|
begin
|
2020-10-26 10:56:48 +00:00
|
|
|
AProportions := nil;
|
2020-10-26 00:18:22 +00:00
|
|
|
MatSize(AFrequencies, numRows, numCols); // totals in last row/col
|
|
|
|
SetLength(AProportions, numRows, numCols);
|
|
|
|
for i := 0 to numRows-1 do
|
|
|
|
begin
|
|
|
|
for j := 0 to numCols-1 do // do not touch the totals column here
|
|
|
|
begin
|
|
|
|
if AFrequencies[i, numCols-1] > 0.0 then
|
|
|
|
AProportions[i, j] := AFrequencies[i, j] / AFrequencies[i, numCols-1]
|
|
|
|
else
|
|
|
|
AProportions[i-1, j-1] := 0.0;
|
|
|
|
end;
|
|
|
|
if AFrequencies[i, numCols-1] > 0.0 then
|
|
|
|
AProportions[i, numCols-1] := 1.0
|
|
|
|
else
|
|
|
|
AProportions[i, numCols-1] := 0.0;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
2020-10-26 14:02:37 +00:00
|
|
|
procedure TChiSqrForm.GetTotalProportions(const AFrequencies: IntDyneMat;
|
2020-10-26 00:18:22 +00:00
|
|
|
out AProportions: DblDyneMat);
|
|
|
|
var
|
|
|
|
numRows, numCols, numCases: Integer;
|
|
|
|
i, j: Integer;
|
|
|
|
begin
|
|
|
|
MatSize(AFrequencies, numRows, numCols); // totals in last row/col
|
|
|
|
numCases := AFrequencies[numRows-1, numCols-1];
|
|
|
|
|
2020-10-26 10:56:48 +00:00
|
|
|
AProportions := nil;
|
2020-10-26 00:18:22 +00:00
|
|
|
SetLength(AProportions, numRows, numCols);
|
|
|
|
for i := 0 to numRows-1 do
|
|
|
|
for j := 0 to numCols-1 do
|
|
|
|
AProportions[i, j] := AFrequencies[i, j] / numCases;
|
|
|
|
AProportions[numRows-1, numCols-1] := 1.0;
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
2020-10-26 14:02:37 +00:00
|
|
|
procedure TChiSqrForm.InputGrpClick(Sender: TObject);
|
2020-03-30 18:01:44 +00:00
|
|
|
begin
|
2020-10-26 10:56:48 +00:00
|
|
|
// InputGrp = 0: have to count cases in each row and col combination
|
|
|
|
// = 1: frequencies available for each row and column combo
|
|
|
|
// = 2: only proportions available - get N size from NCasesEdit
|
|
|
|
DepEdit.Enabled := (InputGrp.ItemIndex > 0);
|
|
|
|
DepLabel.Enabled := DepEdit.Enabled;
|
|
|
|
|
|
|
|
NCasesEdit.Enabled := (InputGrp.ItemIndex = 2);
|
|
|
|
NCasesLabel.Enabled := NCasesEdit.Enabled;
|
|
|
|
|
2020-10-25 18:33:42 +00:00
|
|
|
UpdateBtnStates;
|
2020-03-30 18:01:44 +00:00
|
|
|
end;
|
|
|
|
|
2020-10-25 18:33:42 +00:00
|
|
|
|
2020-10-26 14:02:37 +00:00
|
|
|
procedure TChiSqrForm.ProcessAndReportCellChiSqr(const ACellChiSqr: DblDyneMat;
|
2020-10-26 10:56:48 +00:00
|
|
|
const ARowLabels, AColLabels: StrDyneVec; ANumCases: Integer);
|
|
|
|
var
|
|
|
|
lReport: TStrings;
|
|
|
|
n, m: Integer;
|
|
|
|
begin
|
|
|
|
MatSize(ACellChiSqr, n, m);
|
|
|
|
lReport := TStringList.Create;
|
|
|
|
try
|
|
|
|
lReport.Add('CHI-SQUARE ANALYSIS RESULTS');
|
|
|
|
lReport.Add('');
|
|
|
|
MatPrint(ACellChiSqr, n, m, 'CHI-SQUARED VALUE FOR CELLS', ARowLabels, AColLabels, ANumCases, lReport);
|
|
|
|
|
|
|
|
FCellChiSqrReportFrame.DisplayReport(lReport);
|
|
|
|
finally
|
|
|
|
lReport.Free;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
2020-10-26 14:02:37 +00:00
|
|
|
procedure TChiSqrForm.ProcessAndReportFrequencies(const AFrequencies: IntDyneMat;
|
2020-10-26 10:56:48 +00:00
|
|
|
const AExpected: DblDyneMat; const ARowLabels, AColLabels: StrDyneVec);
|
|
|
|
var
|
|
|
|
lReport: TStrings;
|
|
|
|
n, m, numCases: Integer;
|
|
|
|
begin
|
|
|
|
lReport := TStringList.Create;
|
|
|
|
try
|
|
|
|
lReport.Add('CHI-SQUARE ANALYSIS RESULTS');
|
|
|
|
|
|
|
|
MatSize(AFrequencies, n, m); // totals in last row and col
|
|
|
|
numCases := AFrequencies[n-1, m-1];
|
|
|
|
|
|
|
|
if ObsChk.Checked then
|
|
|
|
begin
|
|
|
|
IntArrayPrint(AFrequencies, n, m, 'Rows', ARowLabels, AColLabels, 'OBSERVED FREQUENCIES', lReport);
|
|
|
|
if ExpChk.Checked then
|
|
|
|
lReport.Add(DIVIDER_SMALL_AUTO);
|
|
|
|
end;
|
|
|
|
|
|
|
|
if ExpChk.Checked then
|
|
|
|
begin
|
|
|
|
lReport.Add('');
|
|
|
|
MatPrint(AExpected, n-1, m-1, 'EXPECTED FREQUENCIES', ARowLabels, AColLabels, numCases, lReport);
|
|
|
|
end;
|
|
|
|
|
|
|
|
FFrequenciesReportFrame.DisplayReport(lReport);
|
|
|
|
|
|
|
|
finally
|
|
|
|
lReport.Free;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
2020-10-26 14:02:37 +00:00
|
|
|
procedure TChiSqrForm.ProcessAndReportProportions(const AFrequencies: IntDyneMat;
|
2020-10-26 10:56:48 +00:00
|
|
|
const ARowLabels, AColLabels: StrDyneVec);
|
|
|
|
var
|
|
|
|
lReport: TStrings;
|
|
|
|
n, m, numCases: Integer;
|
|
|
|
prop: DblDyneMat;
|
|
|
|
begin
|
|
|
|
MatSize(AFrequencies, n, m);
|
|
|
|
numCases := AFrequencies[n-1, m-1];
|
|
|
|
|
|
|
|
lReport := TStringList.Create;
|
|
|
|
try
|
|
|
|
lReport.Add('CHI-SQUARE ANALYSIS RESULTS');
|
|
|
|
lReport.Add('');
|
|
|
|
|
|
|
|
GetRowProportions(AFrequencies, prop);
|
|
|
|
MatPrint(prop, n, m, 'ROW PROPORTIONS', ARowLabels, AColLabels, numCases, lReport);
|
|
|
|
|
|
|
|
lReport.Add(DIVIDER_SMALL_AUTO);
|
|
|
|
lReport.Add('');
|
|
|
|
|
|
|
|
GetColProportions(AFrequencies, prop);
|
|
|
|
MatPrint(prop, n, m, 'COLUMN PROPORTIONS', ARowLabels, AColLabels, numCases, lReport);
|
|
|
|
|
|
|
|
lReport.Add(DIVIDER_SMALL_AUTO);
|
|
|
|
lReport.Add('');
|
|
|
|
|
|
|
|
GetTotalProportions(AFrequencies, prop);
|
|
|
|
MatPrint(Prop, n, m, 'PROPORTIONS OF TOTAL N', ARowLabels, AColLabels, numCases, lReport);
|
|
|
|
|
|
|
|
FRowColPropsReportFrame.DisplayReport(lReport);
|
|
|
|
finally
|
|
|
|
lReport.Free;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
2020-10-26 14:02:37 +00:00
|
|
|
procedure TChiSqrForm.Reset;
|
2020-10-25 18:33:42 +00:00
|
|
|
var
|
|
|
|
i: integer;
|
|
|
|
begin
|
|
|
|
inherited;
|
|
|
|
|
2020-10-26 08:54:34 +00:00
|
|
|
if FFrequenciesReportFrame <> nil then
|
|
|
|
FFrequenciesReportFrame.Clear;
|
|
|
|
if FRowColPropsReportFrame <> nil then
|
|
|
|
FRowColPropsReportFrame.Clear;
|
|
|
|
if FCellChiSqrReportFrame <> nil then
|
|
|
|
FCellChiSqrReportFrame.Clear;
|
|
|
|
|
2020-10-25 18:33:42 +00:00
|
|
|
InputGrp.ItemIndex := 0;
|
|
|
|
|
|
|
|
VarList.Clear;
|
|
|
|
for i := 1 to NoVariables do
|
|
|
|
VarList.Items.Add(OS3MainFrm.DataGrid.Cells[i,0]);
|
|
|
|
|
|
|
|
RowEdit.Clear;
|
|
|
|
ColEdit.Clear;
|
|
|
|
DepEdit.Clear;
|
|
|
|
|
2020-10-26 10:56:48 +00:00
|
|
|
DepLabel.Enabled := false;
|
2020-10-25 18:33:42 +00:00
|
|
|
NCasesLabel.Enabled := false;
|
|
|
|
NCasesEdit.Text := '';
|
|
|
|
NCasesEdit.Enabled := false;
|
|
|
|
|
|
|
|
ObsChk.Checked := false;
|
|
|
|
ExpChk.Checked := false;
|
|
|
|
PropsChk.Checked := false;
|
|
|
|
CellChiChk.Checked := false;
|
|
|
|
SaveFChk.Checked := false;
|
|
|
|
|
2020-10-25 21:41:09 +00:00
|
|
|
FrequenciesPage.TabVisible := false;
|
|
|
|
RowColPage.TabVisible := false;
|
|
|
|
CellChiSqrPage.TabVisible := false;
|
|
|
|
|
2020-10-25 18:33:42 +00:00
|
|
|
UpdateBtnStates;
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
2020-10-26 14:02:37 +00:00
|
|
|
procedure TChiSqrForm.RowInClick(Sender: TObject);
|
2020-10-25 18:33:42 +00:00
|
|
|
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;
|
|
|
|
|
|
|
|
|
2020-10-26 14:02:37 +00:00
|
|
|
procedure TChiSqrForm.RowOutClick(Sender: TObject);
|
2020-10-25 18:33:42 +00:00
|
|
|
begin
|
|
|
|
if RowEdit.Text <> '' then
|
|
|
|
begin
|
|
|
|
VarList.Items.Add(RowEdit.Text);
|
|
|
|
RowEdit.Text := '';
|
|
|
|
end;
|
|
|
|
UpdateBtnStates;
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
2020-10-26 14:02:37 +00:00
|
|
|
procedure TChiSqrForm.UpdateBtnStates;
|
2020-03-30 18:01:44 +00:00
|
|
|
begin
|
2020-10-25 18:33:42 +00:00
|
|
|
inherited;
|
2020-10-26 08:54:34 +00:00
|
|
|
|
|
|
|
if FFrequenciesReportFrame <> nil then
|
|
|
|
FFrequenciesReportFrame.UpdateBtnStates;
|
|
|
|
if FRowColPropsReportFrame <> nil then
|
|
|
|
FRowColPropsReportFrame.UpdateBtnStates;
|
|
|
|
if FCellChiSqrReportFrame <> nil then
|
|
|
|
FCellChiSqrReportFrame.UpdateBtnStates;
|
|
|
|
|
2020-03-30 18:01:44 +00:00
|
|
|
RowIn.Enabled := (VarList.Items.Count > 0) and (RowEdit.Text = '');
|
|
|
|
ColIn.Enabled := (VarList.Items.Count > 0) and (ColEdit.Text = '');
|
2020-10-25 18:33:42 +00:00
|
|
|
DepIn.Enabled := (VarList.Items.Count > 0) and (DepEdit.Text = '') and (InputGrp.ItemIndex > 0);
|
2020-03-30 18:01:44 +00:00
|
|
|
|
|
|
|
RowOut.Enabled := (RowEdit.Text <> '');
|
|
|
|
ColOut.Enabled := (ColEdit.Text <> '');
|
2020-10-25 18:33:42 +00:00
|
|
|
DepOut.Enabled := (DepEdit.Text <> '') and (InputGrp.ItemIndex > 0);
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
2020-10-26 14:02:37 +00:00
|
|
|
function TChiSqrForm.Validate(out AMsg: String; out AControl: TWinControl): Boolean;
|
2020-10-25 18:33:42 +00:00
|
|
|
var
|
|
|
|
n: Integer;
|
|
|
|
begin
|
|
|
|
Result := false;
|
|
|
|
|
|
|
|
if RowEdit.Text = '' then
|
|
|
|
begin
|
|
|
|
AMsg := 'Row variable not selected.';
|
|
|
|
AControl := RowEdit;
|
|
|
|
exit;
|
|
|
|
end;
|
|
|
|
|
|
|
|
if ColEdit.Text = '' then
|
|
|
|
begin
|
|
|
|
AMsg := 'Column variable not selected.';
|
|
|
|
AControl := ColEdit;
|
|
|
|
exit;
|
|
|
|
end;
|
|
|
|
|
|
|
|
if (DepEdit.Text = '') and (InputGrp.ItemIndex > 0) then
|
|
|
|
begin
|
|
|
|
AMsg := 'Variable to analyze is not selected';
|
|
|
|
AControl := DepEdit;
|
|
|
|
exit;
|
|
|
|
end;
|
|
|
|
|
|
|
|
if InputGrp.ItemIndex = 2 then
|
|
|
|
begin
|
|
|
|
if NCasesEdit.Text = '' then
|
|
|
|
begin
|
|
|
|
AControl := NCasesEdit;
|
|
|
|
AMsg := 'Total number of cases not selected.';
|
|
|
|
exit;
|
|
|
|
end;
|
|
|
|
|
|
|
|
if not TryStrToInt(NCasesEdit.Text, n) then
|
|
|
|
begin
|
|
|
|
AControl := NCasesEdit;
|
|
|
|
AMsg := 'Numberical input expected for total number of cases.';
|
|
|
|
exit;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
Result := True;
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
2020-10-26 14:02:37 +00:00
|
|
|
procedure TChiSqrForm.VarListDblClick(Sender: TObject);
|
2020-10-25 18:33:42 +00:00
|
|
|
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 if ColEdit.Text = '' then
|
|
|
|
ColEdit.Text := s
|
|
|
|
else if (DepEdit.Text = '') and (InputGrp.ItemIndex > 0) then
|
|
|
|
DepEdit.Text := s;
|
|
|
|
VarList.Items.Delete(index);
|
|
|
|
UpdateBtnStates;
|
|
|
|
end;
|
2020-03-30 18:01:44 +00:00
|
|
|
end;
|
|
|
|
|
2020-10-25 18:33:42 +00:00
|
|
|
|
2020-10-26 14:02:37 +00:00
|
|
|
procedure TChiSqrForm.VarListSelectionChange(Sender: TObject; User: boolean);
|
2020-03-30 18:01:44 +00:00
|
|
|
begin
|
|
|
|
UpdateBtnStates;
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
end.
|
|
|
|
|