Files
lazarus-ccr/applications/lazstats/source/forms/analysis/comparisons/twopropunit.pas
wp_xxyyzz 2f33dc9f7b LazStats: initial commit.
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@7345 8e941d3f-bd1b-0410-a28a-d453659cc2b4
2020-03-30 18:01:44 +00:00

542 lines
15 KiB
ObjectPascal

unit TwoPropUnit;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, FileUtil, LResources, Forms, Controls,
Graphics, Dialogs, ExtCtrls, StdCtrls, ComCtrls, MainUnit, Globals,
FunctionsLib, OutPutUnit, DataProcs, contexthelpunit;
type
{ TTwoPropFrm }
TTwoPropFrm = class(TForm)
Bevel1: TBevel;
Bevel2: TBevel;
Bevel3: TBevel;
Bevel4: TBevel;
Bevel5: TBevel;
HelpBtn: TButton;
LabelCorner: TLabel;
Notebook1: TNotebook;
Page1: TPage;
Page2: TPage;
Page3: TPage;
Panel1: TPanel;
Panel3: TPanel;
Panel4: TPanel;
ResetBtn: TButton;
ComputeBtn: TButton;
CloseBtn: TButton;
DepFreq00: TEdit;
DepFreq10: TEdit;
DepFreq01: TEdit;
DepFreq11: TEdit;
CInterval: TEdit;
Grp: TEdit;
GrpLabel: TLabel;
ConfLabel: TLabel;
Var2: TEdit;
SecdVarLabel: TLabel;
Var1: TEdit;
IndSize2: TEdit;
IndSize1: TEdit;
IndFreq2: TEdit;
IndFreq1: TEdit;
Samp1Label: TLabel;
Samp21Label: TLabel;
Label11: TLabel;
FirstVarLabel: TLabel;
Samp2Label: TLabel;
Samp1SizeLabel: TLabel;
Samp2SizeLabel: TLabel;
DepSamp2Label: TLabel;
DepSamp1Label: TLabel;
Samp10Label: TLabel;
Samp11Label: TLabel;
Samp20Label: TLabel;
VarList: TListBox;
RadioGroup1: TRadioGroup;
RadioGroup2: TRadioGroup;
procedure ComputeBtnClick(Sender: TObject);
procedure FormActivate(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormShow(Sender: TObject);
procedure HelpBtnClick(Sender: TObject);
procedure RadioGroup1Click(Sender: TObject);
procedure RadioGroup2Click(Sender: TObject);
procedure ResetBtnClick(Sender: TObject);
procedure VarListClick(Sender: TObject);
private
{ private declarations }
FAutoSized: Boolean;
independent: boolean;
griddata: boolean;
function Validate(out AMsg: String; out AControl: TWinControl): Boolean;
public
{ public declarations }
end;
var
TwoPropFrm: TTwoPropFrm;
implementation
uses
Math;
{ TTwoPropFrm }
procedure TTwoPropFrm.ResetBtnClick(Sender: TObject);
var
i: integer;
begin
CInterval.Text := FormatFloat('0.0', DEFAULT_CONFIDENCE_LEVEL_PERCENT);
RadioGroup1.ItemIndex := 0;
RadioGroup2.ItemIndex := 0;
VarList.Clear;
Var1.Text := '';
Var2.Text := '';
independent := true;
griddata := false;
for i := 1 to NoVariables do
VarList.Items.Add(OS3MainFrm.DataGrid.Cells[i,0]);
GrpLabel.Visible := true;
Grp.Visible := true;
Grp.Text := '';
Var2.Visible := false;
SecdVarLabel.Visible := false;
DepFreq00.Text := '';
DepFreq01.Text := '';
DepFreq10.Text := '';
DepFreq11.Text := '';
IndFreq1.Text := '';
IndFreq2.Text := '';
IndSize1.Text := '';
IndSize2.Text := '';
Notebook1.PageIndex := 1;
end;
procedure TTwoPropFrm.VarListClick(Sender: TObject);
var
index: integer;
begin
index := VarList.ItemIndex;
if not independent then
begin
if Var1.Text <> '' then
Var2.Text := VarList.Items[index]
else
Var1.Text := VarList.Items[index];
end;
if independent then
begin
if Var1.Text <> '' then
Grp.Text := VarList.Items[index]
else
Var1.Text := VarList.Items[index];
end;
end;
procedure TTwoPropFrm.FormShow(Sender: TObject);
begin
ResetBtnClick(self);
end;
procedure TTwoPropFrm.HelpBtnClick(Sender: TObject);
begin
if ContextHelpForm = nil then
Application.CreateForm(TContextHelpForm, ContextHelpForm);
ContextHelpForm.HelpMessage((Sender as TButton).tag);
end;
procedure TTwoPropFrm.ComputeBtnClick(Sender: TObject);
var
ConfInt, Prop1, Prop2, zstatistic, zprobability: double;
PropDif, stderr, UCL, LCL, value1, value2, ztest: double;
P, Q: double;
i, v1, v2, NoSelected, f1, f2, f3, f4, ncases1, ncases2: integer;
min, max, group, AB, AC, CD, BD: integer;
ColNoSelected: IntDyneVec;
msg: String;
C: TWinControl;
lReport: TStrings;
begin
if not Validate(msg, C) then
begin
C.SetFocus;
MessageDlg(msg, mtError, [mbOK], 0);
ModalResult := mrNone;
exit;
end;
// Initialize output form
stderr := 0.0;
PropDif := 0.0;
v2 := 0;
ztest := 0.0;
Prop1 := 0.0;
Prop2 := 0.0;
NoSelected := 0;
v1 := 0;
zstatistic := 0.0;
zprobability := 0.0;
UCL := 0.0;
LCL := 0.0;
SetLength(ColNoSelected,NoVariables);
ConfInt := (100.0 - StrToFloat(CInterval.Text)) / 2.0 ;
ConfInt := (100.0 - ConfInt) / 100.0; // one tail
ncases1 := 0;
ncases2 := 0;
f1 := 0;
f2 := 0;
f3 := 0;
f4 := 0;
if independent then
Var2.Text := Grp.Text;
if griddata then // data read from grid
begin
for i := 1 to NoVariables do
begin
if Var1.Text = OS3MainFrm.DataGrid.Cells[i,0] then
begin
v1 := i;
ColNoSelected[0] := i;
end;
if Var2.Text = OS3MainFrm.DataGrid.Cells[i,0] then
begin
v2 := i;
ColNoSelected[1] := i;
end;
end; // next variable
if not independent then // correlated data
begin
for i := 1 to NoCases do
begin
if not GoodRecord(i,NoSelected,ColNoSelected) then continue;
ncases1 := ncases1 + 1;
value1 := StrToFloat(Trim(OS3MainFrm.DataGrid.Cells[v1,i]));
value2 := StrToFloat(Trim(OS3MainFrm.DataGrid.Cells[v2,i]));
f1 := f1 + round(value1);
f2 := f2 + round(value2);
end; // next case
f3 := ncases1 - f1;
f4 := ncases1 - f2;
AB := f1 + f2;
AC := f1 + f3;
CD := f3 + f4;
BD := f2 + f4;
Prop1 := BD / ncases1;
Prop2 := AB / ncases1;
stderr := sqrt((f1 / ncases1 + f4 / ncases1) / ncases1);
PropDif := Prop1 - Prop2;
zstatistic := PropDif / stderr;
ztest := inversez(ConfInt);
zprobability := 1.0 - probz(abs(zstatistic));
UCL := PropDif + stderr * ztest;
LCL := PropDif - stderr * ztest;
end; // if not independent
if independent then
begin
min := round(StrToFloat(Trim(OS3MainFrm.DataGrid.Cells[v2,1])));
max := min;
for i := 2 to NoCases do
begin
if not GoodRecord(i,NoSelected,ColNoSelected) then continue;
group := round(StrToFloat(Trim(OS3MainFrm.DataGrid.Cells[v2,i])));
if group < min then min := group;
if group > max then max := group;
end;
for i := 1 to NoCases do
begin
if not GoodRecord(i,NoSelected,ColNoSelected) then continue;
value1 := StrToFloat(Trim(OS3MainFrm.DataGrid.Cells[v1,i]));
group := round(StrToFloat(Trim(OS3MainFrm.DataGrid.Cells[v2,i])));
if group = min then
begin
f1 := f1 + round(value1);
ncases1 := ncases1 + 1;
end else
begin
f2 := f2 + round(value1);
ncases2 := ncases2 + 1;
end;
end; // next case
Prop1 := f1 / ncases1;
Prop2 := f2 / ncases2;
PropDif := Prop1 - Prop2;
P := (f1 + f2) / (ncases1 + ncases2);
Q := 1.0 - P;
stderr := sqrt(P * Q * ((1.0 / ncases1) + (1.0 / ncases2)));
zstatistic := (Prop1 - Prop2) / stderr;
zprobability := 1.0 - probz(abs(zstatistic));
ztest := inversez(ConfInt);
UCL := PropDif + ztest * stderr;
LCL := PropDif - ztest * stderr;
end; // end if independent
end; // if reading grid data
if not griddata then // data read from form
begin
if not independent then // correlated data
begin
f1 := round(StrToFloat(DepFreq00.Text));
f2 := round(StrToFloat(DepFreq10.Text));
f3 := round(StrToFloat(DepFreq01.Text));
f4 := round(StrToFloat(DepFreq11.Text));
ncases1 := f1 + f2 + f3 + f4;
AB := f1 + f2;
AC := f1 + f3;
CD := f3 + f4;
BD := f2 + f4;
Prop1 := BD / ncases1;
Prop2 := AB / ncases1;
stderr := sqrt((f1 / ncases1 + f4 / ncases1) / ncases1);
PropDif := Prop1 - Prop2;
zstatistic := PropDif / stderr;
ztest := inversez(ConfInt);
zprobability := 1.0 - probz(abs(zstatistic));
UCL := PropDif + stderr * ztest;
LCL := PropDif - stderr * ztest;
end; // if not independent
if independent then // independent data
begin
f1 := StrToInt(IndFreq1.Text);
f2 := StrToInt(IndFreq2.Text);
ncases1 := StrToInt(IndSize1.Text);
ncases2 := StrToInt(IndSize2.Text);
Prop1 := f1 / ncases1;
Prop2 := f2 / ncases2;
PropDif := Prop1 - Prop2;
P := (f1 + f2) / (ncases1 + ncases2);
Q := 1.0 - P;
stderr := sqrt(P * Q * ((1.0 / ncases1) + (1.0 / ncases2)));
zstatistic := (Prop1 - Prop2) / stderr;
zprobability := 1.0 - probz(abs(zstatistic));
ztest := inversez(ConfInt);
UCL := PropDif + ztest * stderr;
LCL := PropDif - ztest * stderr;
end;
end;
// Print the results
lReport := TStringList.Create;
try
lReport.Add('COMPARISON OF TWO PROPORTIONS');
lReport.Add('');
if not independent then
begin
lReport.Add('Test for Difference Between Two Dependent Proportions');
lReport.Add('');
lReport.Add('Entered Values');
lReport.Add('');
lReport.Add('Sample 1');
lReport.Add(' 0 1 sum');
lReport.Add(' -----------------------');
lReport.Add(' 0 |%5d %5d %5d |', [f1, f2, AB]);
lReport.Add(' 2 --------|-------|------');
lReport.Add(' 1 |%5d %5d %5d |', [f3, f4, CD]);
lReport.Add(' --------|-------|------');
lReport.Add(' sum | %5d %5d %5d |', [AC, BD, ncases1]);
lReport.Add('');
lReport.Add('Confidence Level selected: %s', [CInterval.Text]);
lReport.Add('Proportion 1 = %.3f and Proportion 2 = %.3f with %d cases', [Prop1, Prop2, ncases1]);
lReport.Add('Difference in proportions: %9.3f', [PropDif]);
lReport.Add('Standard Error of Difference: %9.3f', [stderr]);
lReport.Add('z test statistic: %9.3f with probability = %.4f', [zstatistic, zprobability]);
lReport.Add('z value for confidence interval: %9.3f', [ztest]);
lReport.Add('Confidence Interval: (%.3f, %.3f)', [LCL, UCL]);
end;
if independent then
begin
lReport.Add('Test for Difference Between Two Independent Proportions');
lReport.Add('');
lReport.Add('Entered Values');
lReport.Add('');
lReport.Add('Sample 1: Frequency = %5d for %5d cases.', [f1, ncases1]);
lReport.Add('Sample 2: Frequency = %5d for %5d cases.', [f2, ncases2]);
lReport.Add('');
lReport.Add('Proportion 1: %9.3f', [Prop1]);
lReport.Add('Proportion 2: %9.3f', [Prop2]);
lReport.Add('Difference: %9.3f', [PropDif]);
lReport.Add('Standard Error of Difference: %9.3f', [stderr]);
lReport.Add('Confidence Level selected: %9s', [CInterval.Text]);
lReport.Add('z test statistic: %9.3f with probability = %.4f', [zstatistic, zprobability]);
lReport.Add('z value for confidence interval: %9.3f', [ztest]);
lReport.Add('Confidence Interval: (%.3f, %.3f)', [LCL, UCL]);
end;
DisplayReport(lReport);
finally
lReport.Free;
ColNoSelected := nil;
end;
end;
procedure TTwoPropFrm.FormActivate(Sender: TObject);
var
w: Integer;
begin
if FAutoSized then
exit;
RadioGroup2.Constraints.MinWidth := RadioGroup1.Width;
w := MaxValue([HelpBtn.Width, ResetBtn.Width, ComputeBtn.Width, CloseBtn.Width]);
HelpBtn.Constraints.MinWidth := w;
ResetBtn.Constraints.MinWidth := w;
ComputeBtn.Constraints.MinWidth := w;
CloseBtn.Constraints.MinWidth := w;
Width := Max(
RadioGroup2.Left + RadioGroup2.Width + RadioGroup2.BorderSpacing.Right,
Width - HelpBtn.Left + HelpBtn.BorderSpacing.Left
);
Constraints.MinWidth := Width;
Constraints.MinHeight := Height;
FAutoSized := true;
end;
procedure TTwoPropFrm.FormCreate(Sender: TObject);
begin
Assert(OS3MainFrm <> nil);
end;
procedure TTwoPropFrm.RadioGroup1Click(Sender: TObject);
begin
griddata := RadioGroup1.ItemIndex = 1;
RadioGroup2Click(nil);
end;
procedure TTwoPropFrm.RadioGroup2Click(Sender: TObject);
begin
case RadioGroup2.ItemIndex of
0: begin
independent := true;
if griddata then begin
Notebook1.PageIndex := 0;
Var2.Visible := false;
Grp.Visible := true;
SecdVarLabel.Visible := Var2.Visible;
GrpLabel.Visible := Grp.Visible;
end else
Notebook1.PageIndex := 1;
end;
1: begin
independent := false;
if griddata then begin
Notebook1.PageIndex := 0;
Var2.Visible := true;
Grp.Visible := false;
SecdVarLabel.Visible := Var2.Visible;
GrpLabel.Visible := Grp.Visible;
end else
Notebook1.PageIndex := 2;
end;
end;
end;
function TTwoPropFrm.Validate(out AMsg: String; out AControl: TWinControl): Boolean;
var
n: Integer;
begin
Result := false;
AControl := nil;
AMsg := '';
if Notebook1.PageIndex = 0 then
begin
if Var1.Text = '' then
begin
AControl := Var1;
AMsg := 'First variable not specified.';
exit;
end;
case RadioGroup2.ItemIndex of
0: if (Grp.Text = '') then
begin
AControl := Grp;
AMsg := 'Group code not specified';
exit;
end;
1: if (Var2.Text = '') then begin
AControl := Var2;
AMsg := 'Second variable not specified.';
exit;
end;
end;
end else
if Notebook1.PageIndex = 1 then
begin
if (IndFreq1.Text = '') or not TryStrToInt(IndFreq1.Text, n) or (n < 0) then
begin
AControl := IndFreq1;
AMsg := 'Invalid input for Sample 1 frequency';
exit;
end;
if (IndFreq2.Text = '') or not TryStrToInt(IndFreq2.Text, n) or (n < 0) then
begin
AControl := IndFreq2;
AMsg := 'Invalid input for Sample 2 frequency';
exit;
end;
if (IndSize1.Text = '') or not TryStrToInt(IndSize1.Text, n) or (n <= 0) then
begin
AControl := IndSize1;
AMsg := 'Invald input for size of sample 1';
exit;
end;
if (IndSize2.Text = '') or not TryStrToInt(IndSize2.Text, n) or (n <= 0) then
begin
AControl := IndSize2;
AMsg := 'Invalud input for size of sample 2';
exit;
end;
end else
if Notebook1.PageIndex = 2 then
begin
if (DepFreq00.Text = '') or not TryStrToInt(DepFreq00.Text, n) or (n < 0) then
AControl := DepFreq00
else
if (DepFreq01.Text = '') or not TryStrToInt(DepFreq01.Text, n) or (n < 0) then
AControl := DepFreq01
else
if (DepFreq10.Text = '') or not TryStrToInt(DepFreq10.Text, n) or (n < 0) then
AControl := DepFreq10
else
if (DepFreq11.Text = '') or not TryStrToInt(DepFreq11.Text, n) or (n < 0) then
AControl := DepFreq11;
if AControl <> nil then
begin
AMsg := 'Invalid input.';
exit;
end;
end;
Result := true;
end;
initialization
{$I twopropunit.lrs}
end.