2020-03-30 18:01:44 +00:00
|
|
|
unit TTestUnit;
|
|
|
|
|
|
|
|
{$mode objfpc}{$H+}
|
|
|
|
|
|
|
|
interface
|
|
|
|
|
|
|
|
uses
|
2020-11-04 23:14:23 +00:00
|
|
|
Classes, SysUtils, Forms, Controls, Graphics, Dialogs,
|
|
|
|
ExtCtrls, StdCtrls, Buttons,
|
|
|
|
MainUnit, Globals, BasicStatsReportFormUnit;
|
2020-03-30 18:01:44 +00:00
|
|
|
|
|
|
|
type
|
|
|
|
|
2020-11-04 23:14:23 +00:00
|
|
|
{ TTtestForm }
|
2020-03-30 18:01:44 +00:00
|
|
|
|
2020-11-04 23:14:23 +00:00
|
|
|
TTtestForm = class(TBasicStatsReportForm)
|
2020-03-30 18:01:44 +00:00
|
|
|
Bevel3: TBevel;
|
|
|
|
Bevel4: TBevel;
|
|
|
|
Bevel5: TBevel;
|
2020-11-04 23:14:23 +00:00
|
|
|
TailCombo: TComboBox;
|
|
|
|
GroupCodeGroup: TGroupBox;
|
|
|
|
GroupCodeChk: TCheckBox;
|
|
|
|
Grp1CodeEdit: TEdit;
|
|
|
|
Grp2CodeEdit: TEdit;
|
2020-03-30 18:01:44 +00:00
|
|
|
GrpCodeLabel1: TLabel;
|
|
|
|
GrpCodeLabel2: TLabel;
|
2020-11-04 23:14:23 +00:00
|
|
|
GrpIn: TBitBtn;
|
|
|
|
GrpOut: TBitBtn;
|
|
|
|
Label2: TLabel;
|
|
|
|
Notebook: TNotebook;
|
2020-03-30 18:01:44 +00:00
|
|
|
Page1: TPage;
|
|
|
|
Page2: TPage;
|
2020-11-04 23:14:23 +00:00
|
|
|
Cor12Label: TLabel;
|
2020-11-05 13:38:59 +00:00
|
|
|
Cor12Edit: TEdit;
|
|
|
|
CIntervalEdit: TEdit;
|
2020-11-04 23:14:23 +00:00
|
|
|
GrpEdit: TEdit;
|
2020-03-30 18:01:44 +00:00
|
|
|
Label1: TLabel;
|
2020-11-04 23:14:23 +00:00
|
|
|
Var1In: TBitBtn;
|
|
|
|
Var1Out: TBitBtn;
|
|
|
|
Var2Edit: TEdit;
|
|
|
|
Var1Edit: TEdit;
|
|
|
|
Var1Label: TLabel;
|
2020-03-30 18:01:44 +00:00
|
|
|
GrpLabel: TLabel;
|
2020-11-04 23:14:23 +00:00
|
|
|
Var2Label: TLabel;
|
|
|
|
VarList: TListBox;
|
2020-03-30 18:01:44 +00:00
|
|
|
SelVarLabel: TLabel;
|
2020-11-05 13:38:59 +00:00
|
|
|
N2Edit: TEdit;
|
|
|
|
N1Edit: TEdit;
|
2020-03-30 18:01:44 +00:00
|
|
|
SampSize2Label: TLabel;
|
|
|
|
SampSize1Label: TLabel;
|
2020-11-05 13:38:59 +00:00
|
|
|
SD2Edit: TEdit;
|
|
|
|
SD1Edit: TEdit;
|
2020-03-30 18:01:44 +00:00
|
|
|
SD2Label: TLabel;
|
|
|
|
SD1Label: TLabel;
|
2020-11-05 13:38:59 +00:00
|
|
|
Mean2Edit: TEdit;
|
|
|
|
Mean1Edit: TEdit;
|
2020-03-30 18:01:44 +00:00
|
|
|
Mean2Label: TLabel;
|
|
|
|
Mean1Label: TLabel;
|
2020-11-04 23:14:23 +00:00
|
|
|
DataEntryGroup: TRadioGroup;
|
|
|
|
DepIndepGroup: TRadioGroup;
|
|
|
|
Var2In: TBitBtn;
|
|
|
|
Var2Out: TBitBtn;
|
|
|
|
procedure GroupCodeChkChange(Sender: TObject);
|
|
|
|
procedure DataEntryGroupClick(Sender: TObject);
|
|
|
|
procedure DepIndepGroupClick(Sender: TObject);
|
|
|
|
procedure GrpInClick(Sender: TObject);
|
|
|
|
procedure GrpOutClick(Sender: TObject);
|
|
|
|
procedure Var1InClick(Sender: TObject);
|
|
|
|
procedure Var1OutClick(Sender: TObject);
|
|
|
|
procedure Var2InClick(Sender: TObject);
|
|
|
|
procedure Var2OutClick(Sender: TObject);
|
|
|
|
procedure VarListDblClick(Sender: TObject);
|
2020-11-06 00:04:57 +00:00
|
|
|
procedure VarListSelectionChange(Sender: TObject; {%H-}User: boolean);
|
2020-11-04 23:14:23 +00:00
|
|
|
|
2020-03-30 18:01:44 +00:00
|
|
|
private
|
|
|
|
independent: boolean;
|
|
|
|
griddata: boolean;
|
2020-11-05 13:38:59 +00:00
|
|
|
|
|
|
|
function Eval_DependentGridData(out AMean1, AMean2, AVariance1, AVariance2,
|
|
|
|
AStdDev1, AStdDev2, ACovar12, r12: Double; out ANumCases1, ANumCases2: Integer): Boolean;
|
|
|
|
|
|
|
|
function Eval_IndependentGridData(out AMean1, AMean2, AVariance1, AVariance2,
|
|
|
|
AStdDev1, AStdDev2: Double; out ANumCases1, ANumCases2: Integer;
|
|
|
|
out ALabel1Str, ALabel2Str: String): Boolean;
|
2020-11-06 00:04:57 +00:00
|
|
|
|
2020-11-04 23:14:23 +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-11-04 23:14:23 +00:00
|
|
|
constructor Create(AOwner: TComponent); override;
|
|
|
|
procedure Reset; override;
|
2020-03-30 18:01:44 +00:00
|
|
|
end;
|
|
|
|
|
|
|
|
var
|
2020-11-04 23:14:23 +00:00
|
|
|
TtestForm: TTtestForm;
|
2020-03-30 18:01:44 +00:00
|
|
|
|
|
|
|
|
2020-11-04 23:14:23 +00:00
|
|
|
implementation
|
2020-03-30 18:01:44 +00:00
|
|
|
|
2020-11-04 23:14:23 +00:00
|
|
|
{$R *.lfm}
|
2020-03-30 18:01:44 +00:00
|
|
|
|
2020-11-04 23:14:23 +00:00
|
|
|
uses
|
|
|
|
Math,
|
2020-11-05 13:38:59 +00:00
|
|
|
Utils, MathUnit, MatrixUnit, GridProcs;
|
2020-03-30 18:01:44 +00:00
|
|
|
|
|
|
|
|
2020-11-04 23:14:23 +00:00
|
|
|
{ TTtestForm }
|
2020-03-30 18:01:44 +00:00
|
|
|
|
2020-11-04 23:14:23 +00:00
|
|
|
constructor TTtestForm.Create(AOwner: TComponent);
|
2020-03-30 18:01:44 +00:00
|
|
|
begin
|
2020-11-04 23:14:23 +00:00
|
|
|
inherited;
|
2020-11-05 13:38:59 +00:00
|
|
|
CIntervalEdit.Text := FormatFloat('0.0', DEFAULT_CONFIDENCE_LEVEL_PERCENT);
|
2020-03-30 18:01:44 +00:00
|
|
|
end;
|
|
|
|
|
|
|
|
|
2020-11-04 23:14:23 +00:00
|
|
|
procedure TTtestForm.AdjustConstraints;
|
2020-03-30 18:01:44 +00:00
|
|
|
begin
|
2020-11-04 23:14:23 +00:00
|
|
|
inherited;
|
|
|
|
|
|
|
|
ParamsPanel.Constraints.MinWidth := Max(
|
|
|
|
DataEntryGroup.Width + DepIndepGroup.BorderSpacing.Left + DepIndepGroup.Width,
|
|
|
|
4*CloseBtn.Width + 3*CloseBtn.BorderSpacing.Left
|
|
|
|
);
|
|
|
|
ParamsPanel.Constraints.MinHeight := DataEntryGroup.Height +
|
|
|
|
TailCombo.BorderSpacing.Top + TailCombo.Height +
|
2020-11-05 13:38:59 +00:00
|
|
|
CIntervalEdit.BorderSpacing.Top + CIntervalEdit.Height + CIntervalEdit.BorderSpacing.Bottom +
|
2020-11-04 23:14:23 +00:00
|
|
|
Bevel3.Height + Bevel3.BorderSpacing.Bottom +
|
|
|
|
GrpIn.Top + GroupCodeGroup.Height +
|
|
|
|
ButtonBevel.Height + CloseBtn.BorderSpacing.Top + CloseBtn.Height;
|
2020-03-30 18:01:44 +00:00
|
|
|
end;
|
|
|
|
|
2020-11-04 23:14:23 +00:00
|
|
|
|
|
|
|
procedure TTtestForm.Compute;
|
2020-03-30 18:01:44 +00:00
|
|
|
var
|
2020-11-05 13:38:59 +00:00
|
|
|
mean1, mean2, Dif, stddev1, stddev2, r12, stderr1, stderr2: double;
|
2020-03-30 18:01:44 +00:00
|
|
|
tequal, tunequal, cov12, lowci, hici, F, Fp, df1, df2: double;
|
2020-11-06 00:04:57 +00:00
|
|
|
tprobability: double;
|
2020-03-30 18:01:44 +00:00
|
|
|
variance1, variance2, pooled, sedif, df, ConfInt, tconfint: double;
|
2020-11-06 00:04:57 +00:00
|
|
|
nCases1, nCases2: integer;
|
2020-03-30 18:01:44 +00:00
|
|
|
label1Str, label2Str: string;
|
|
|
|
lReport: TStrings;
|
|
|
|
begin
|
2020-11-05 13:38:59 +00:00
|
|
|
ConfInt := (100.0 - StrToFloat(CIntervalEdit.Text)) / 2.0 ;
|
2020-03-30 18:01:44 +00:00
|
|
|
ConfInt := (100.0 - ConfInt) / 100.0; // one tail
|
|
|
|
|
|
|
|
if griddata then
|
|
|
|
begin
|
2020-11-05 13:38:59 +00:00
|
|
|
// Read and analyze data from grid
|
2020-03-30 18:01:44 +00:00
|
|
|
if independent then
|
|
|
|
begin
|
2020-11-05 13:38:59 +00:00
|
|
|
if not Eval_IndependentGridData(
|
|
|
|
mean1, mean2, variance1, variance2, stddev1, stddev2,
|
|
|
|
nCases1, nCases2, Label1Str, Label2Str)
|
|
|
|
then
|
|
|
|
exit;
|
|
|
|
end else
|
|
|
|
begin
|
|
|
|
if not Eval_DependentGridData(
|
|
|
|
mean1, mean2, variance1, variance2, stddev1, stddev2,
|
|
|
|
cov12, r12, nCases1, nCases2)
|
|
|
|
then
|
|
|
|
exit;
|
|
|
|
end;
|
|
|
|
end else
|
2020-03-30 18:01:44 +00:00
|
|
|
begin
|
2020-11-05 13:38:59 +00:00
|
|
|
// Read data from form
|
|
|
|
mean1 := StrToFloat(mean1Edit.Text);
|
|
|
|
mean2 := StrToFloat(mean2Edit.Text);
|
|
|
|
stddev1 := StrToFloat(SD1Edit.Text);
|
|
|
|
stddev2 := StrToFloat(SD2Edit.Text);
|
|
|
|
ncases1 := round(StrToFloat(N1Edit.Text));
|
|
|
|
ncases2 := round(StrToFloat(N2Edit.Text));
|
2020-03-30 18:01:44 +00:00
|
|
|
variance1 := stddev1 * stddev1;
|
|
|
|
variance2 := stddev2 * stddev2;
|
|
|
|
Label1Str := 'Group 1';
|
|
|
|
Label2Str := 'Group 2';
|
|
|
|
if not independent then
|
|
|
|
begin
|
2020-11-05 13:38:59 +00:00
|
|
|
r12 := StrToFloat(Cor12Edit.Text);
|
2020-03-30 18:01:44 +00:00
|
|
|
cov12 := r12 * stddev1 * stddev2;
|
|
|
|
end;
|
|
|
|
end;
|
2020-11-05 13:38:59 +00:00
|
|
|
dif := mean1 - mean2;
|
2020-03-30 18:01:44 +00:00
|
|
|
|
|
|
|
// Initialize output form
|
|
|
|
lReport := TStringList.Create;
|
|
|
|
try
|
|
|
|
lReport.Add('COMPARISON OF TWO MEANS');
|
|
|
|
lReport.Add('');
|
|
|
|
|
|
|
|
// Calculate pooled and independent t and z values and test statistic
|
|
|
|
if independent then
|
|
|
|
begin
|
|
|
|
stderr1 := sqrt(variance1 / ncases1);
|
|
|
|
Stderr2 := sqrt(variance2 / ncases2);
|
|
|
|
lReport.Add('Variable Mean Variance Std.Dev. S.E.Mean N');
|
2020-11-05 13:38:59 +00:00
|
|
|
lReport.Add('%-10s%8.2f %8.2f %8.2f %8.2f %d', [Label1Str, mean1, variance1, stddev1, stderr1, ncases1]);
|
|
|
|
lReport.Add('%-10s%8.2f %8.2f %8.2f %8.2f %d', [Label2Str, mean2, variance2, stddev2, stderr2, ncases2]);
|
2020-03-30 18:01:44 +00:00
|
|
|
lReport.Add('');
|
|
|
|
|
|
|
|
pooled := ((ncases1-1) * variance1) + ((ncases2-1) * variance2);
|
|
|
|
pooled := pooled / (ncases1 + ncases2 - 2);
|
|
|
|
pooled := pooled * ( 1.0 / ncases1 + 1.0 / ncases2);
|
|
|
|
sedif := sqrt(pooled);
|
|
|
|
tequal := dif / sedif;
|
|
|
|
df := ncases1 + ncases2 - 2;
|
2020-11-04 23:14:23 +00:00
|
|
|
tprobability := ProbT(tequal, df);
|
|
|
|
if TailCombo.ItemIndex = 1 then tprobability := 0.5 * tprobability;
|
2020-03-30 18:01:44 +00:00
|
|
|
lReport.Add('Assuming equal variances, t = %.3f with probability = %.4f and %.0f degrees of freedom', [
|
|
|
|
tequal, tprobability, df
|
|
|
|
]);
|
|
|
|
lReport.Add('Difference = %.2f and Standard Error of difference = %.2f', [dif, sedif]);
|
|
|
|
|
|
|
|
tconfint := inverset(ConfInt,df);
|
|
|
|
lowci := dif - tconfint * sedif;
|
|
|
|
hici := dif + tconfint * sedif;
|
|
|
|
lReport.Add('Confidence interval = (%.2f ... %.2f)', [lowci, hici]);
|
2020-11-04 23:14:23 +00:00
|
|
|
lReport.Add('');
|
2020-03-30 18:01:44 +00:00
|
|
|
|
|
|
|
// now for unequal variances
|
|
|
|
sedif := sqrt((variance1 / ncases1) + (variance2 / ncases2));
|
|
|
|
tunequal := dif / sedif;
|
|
|
|
df := sqr((variance1 / ncases1) + (variance2 / ncases2));
|
|
|
|
df := df / (sqr(variance1 / ncases1) / (ncases1 - 1) + sqr(variance2 / ncases2) / (ncases2 - 1) );
|
2020-11-04 23:14:23 +00:00
|
|
|
tprobability := ProbT(tequal, df);
|
|
|
|
if TailCombo.ItemIndex = 1 then tprobability := 0.5 * tprobability;
|
2020-03-30 18:01:44 +00:00
|
|
|
lReport.Add('Assuming unequal variances, t = %.3f with probability = %.4f and %.0f degrees of freedom', [
|
|
|
|
tunequal, tprobability, df
|
|
|
|
]);
|
|
|
|
lReport.Add('Difference = %.2f and Standard Error of difference = %.2f', [dif, sedif]);
|
|
|
|
|
|
|
|
tconfint := inverset(ConfInt,df);
|
|
|
|
lowci := dif - tconfint * sedif;
|
|
|
|
hici := dif + tconfint * sedif;
|
|
|
|
lReport.Add('Confidence interval = (%.2f ... %.2f)', [lowci, hici]);
|
2020-11-04 23:14:23 +00:00
|
|
|
lReport.Add('');
|
2020-03-30 18:01:44 +00:00
|
|
|
|
|
|
|
df1 := ncases1 - 1;
|
|
|
|
df2 := ncases2 - 1;
|
|
|
|
if variance1 > variance2 then
|
|
|
|
begin
|
|
|
|
F := variance1 / variance2;
|
2020-09-28 14:05:34 +00:00
|
|
|
Fp := ProbF(F, df1, df2);
|
2020-03-30 18:01:44 +00:00
|
|
|
end else
|
|
|
|
begin
|
|
|
|
F := variance2 / variance1;
|
2020-09-28 14:05:34 +00:00
|
|
|
Fp := ProbF(F, df2, df1);
|
2020-03-30 18:01:44 +00:00
|
|
|
end;
|
|
|
|
lReport.Add('F test for equal variances = %.3f, Probability = %.4f', [F, fp]);
|
|
|
|
end
|
|
|
|
else
|
|
|
|
// dependent t test
|
|
|
|
begin
|
|
|
|
stderr1 := sqrt(variance1 / ncases1);
|
|
|
|
Stderr2 := sqrt(variance2 / ncases2);
|
|
|
|
lReport.Add('Variable Mean Variance Std.Dev. S.E.Mean N');
|
2020-11-05 13:38:59 +00:00
|
|
|
lReport.Add('%-10s%8.2f %8.2f %8.2f %8.2f %d', [Label1Str, mean1, variance1, stddev1, stderr1, ncases1]);
|
|
|
|
lReport.Add('%-10s%8.2f %8.2f %8.2f %8.2f %d', [Label2Str, mean2, variance2, stddev2, stderr2, ncases2]);
|
2020-03-30 18:01:44 +00:00
|
|
|
lReport.Add('');
|
|
|
|
sedif := variance1 + variance2 - (2.0 * cov12);
|
|
|
|
sedif := sqrt(sedif / ncases1);
|
|
|
|
tequal := Dif / sedif;
|
|
|
|
df := ncases1 - 1;
|
|
|
|
tprobability := probt(tequal,df);
|
|
|
|
lReport.Add('Assuming dependent samples, t = %.3f with probability = %.4f and %.0f degrees of freedom', [
|
|
|
|
tequal, tprobability, df
|
|
|
|
]);
|
|
|
|
lReport.Add('Correlation between %s and %s = %.3f', [Label1Str, Label2Str, r12]);
|
|
|
|
lReport.Add('Difference = %.2f and Standard Error of difference = %.2f', [dif, sedif]);
|
|
|
|
|
|
|
|
tconfint := inverset(ConfInt,df);
|
|
|
|
lowci := dif - tconfint * sedif;
|
|
|
|
hici := dif + tconfint * sedif;
|
|
|
|
lReport.Add('Confidence interval = (%.2f ... %.2f)', [lowci, hici]);
|
|
|
|
|
|
|
|
tequal := variance1 - variance2;
|
|
|
|
tequal := tequal / sqrt( (4 * variance1 * variance2)/(ncases1 - 2) * (1.0 - sqr(r12)) );
|
|
|
|
df := ncases1 - 2;
|
|
|
|
tprobability := probt(tequal,df);
|
|
|
|
lReport.Add('t for test of equal variances = %.3f with probability = %.4f', [tequal, tprobability]);
|
|
|
|
end;
|
|
|
|
|
2020-11-04 23:14:23 +00:00
|
|
|
FReportFrame.DisplayReport(lReport);
|
2020-03-30 18:01:44 +00:00
|
|
|
|
|
|
|
finally
|
|
|
|
lReport.Free;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
2020-11-04 23:14:23 +00:00
|
|
|
|
|
|
|
procedure TTtestForm.DataEntryGroupClick(Sender: TObject);
|
|
|
|
var
|
|
|
|
index: integer;
|
2020-03-30 18:01:44 +00:00
|
|
|
begin
|
2020-11-04 23:14:23 +00:00
|
|
|
index := DataEntryGroup.ItemIndex;
|
|
|
|
Notebook.PageIndex := index;
|
|
|
|
gridData := (index = 1);
|
|
|
|
if index = 1 then
|
|
|
|
begin
|
|
|
|
if DepIndepGroup.ItemIndex = 1 then
|
|
|
|
Var2Edit.Visible := true
|
|
|
|
else
|
|
|
|
Var2Edit.Visible := false;
|
|
|
|
end;
|
|
|
|
|
2020-11-05 13:38:59 +00:00
|
|
|
GroupCodeChk.Visible := independent;
|
|
|
|
GroupCodeGroup.Visible := independent;
|
|
|
|
|
2020-11-04 23:14:23 +00:00
|
|
|
Var2Label.Visible := Var2Edit.Visible;
|
|
|
|
Var2In.Visible := Var2Edit.Visible;
|
|
|
|
Var2Out.Visible := Var2Edit.Visible;
|
|
|
|
|
|
|
|
GrpEdit.Visible := not Var2Edit.Visible;
|
|
|
|
GrpLabel.Visible := GrpEdit.Visible;
|
|
|
|
GrpIn.Visible := GrpEdit.Visible;
|
|
|
|
GrpOut.Visible := GrpEdit.Visible;
|
2020-03-30 18:01:44 +00:00
|
|
|
end;
|
|
|
|
|
2020-11-04 23:14:23 +00:00
|
|
|
|
|
|
|
procedure TTtestForm.DepIndepGroupClick(Sender: TObject);
|
2020-03-30 18:01:44 +00:00
|
|
|
begin
|
2020-11-04 23:14:23 +00:00
|
|
|
independent := (DepIndepGroup.ItemIndex = 0);
|
|
|
|
|
|
|
|
GrpEdit.Visible := independent;
|
|
|
|
GrpLabel.Visible := independent;
|
|
|
|
GrpIn.Visible := independent;
|
|
|
|
GrpOut.Visible := independent;
|
|
|
|
|
|
|
|
GroupCodeChk.Visible := independent;
|
|
|
|
GroupCodeGroup.Visible := independent;
|
|
|
|
|
|
|
|
Var2Label.Visible := not independent;
|
|
|
|
Var2Edit.Visible := not independent;
|
|
|
|
Var2In.Visible := not independent;
|
|
|
|
Var2Out.Visible := not independent;
|
|
|
|
|
2020-11-05 13:38:59 +00:00
|
|
|
Cor12Edit.Visible := not independent;
|
2020-11-04 23:14:23 +00:00
|
|
|
Cor12Label.Visible := not independent;
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
2020-11-05 13:38:59 +00:00
|
|
|
function TtTestForm.Eval_DependentGridData(out AMean1, AMean2,
|
|
|
|
AVariance1, AVariance2, AStdDev1, AStdDev2, ACovar12, r12: Double;
|
|
|
|
out ANumCases1, ANumCases2: Integer): Boolean;
|
|
|
|
var
|
|
|
|
colNoSelected: IntDyneVec = nil;
|
|
|
|
values1: DblDyneVec = nil;
|
|
|
|
values2: DblDyneVec = nil;
|
|
|
|
begin
|
|
|
|
SetLength(colNoSelected, 2);
|
|
|
|
colNoSelected[0] := GetVariableIndex(OS3MainFrm.DataGrid, Var1Edit.Text);
|
|
|
|
colNoSelected[1] := GetVariableIndex(OS3MainFrm.DataGrid, Var2Edit.Text);
|
|
|
|
|
|
|
|
values1 := CollectVecValues(OS3MainFrm.DataGrid, colNoSelected[0], colNoSelected);
|
|
|
|
values2 := CollectVecValues(OS3MainFrm.DataGrid, colNoSelected[1], colNoSelected);
|
|
|
|
|
|
|
|
ANumCases1 := Length(values1);
|
|
|
|
ANumCases2 := Length(values2);
|
|
|
|
|
|
|
|
if ANumCases1 <> ANumCases2 then
|
|
|
|
begin
|
|
|
|
ErrorMsg('Both variables must have the same count of cases.');
|
|
|
|
Result := false;
|
|
|
|
exit;
|
|
|
|
end;
|
|
|
|
|
|
|
|
if ANumCases1 < 2 then
|
|
|
|
begin
|
|
|
|
ErrorMsg('There must be at least two cases.');
|
|
|
|
Result := false;
|
|
|
|
exit;
|
|
|
|
end;
|
|
|
|
|
|
|
|
VecMeanVarStdDev(values1, AMean1, AVariance1, AStdDev1);
|
|
|
|
VecMeanVarStdDev(values2, AMean2, AVariance2, AStdDev2);
|
|
|
|
|
|
|
|
ACovar12 := (values1 - AMean1) * (values2 - AMean2) / (ANumCases1-1);
|
|
|
|
r12 := ACovar12 / (AStdDev1 * AStdDev2);
|
|
|
|
|
|
|
|
Result := true;
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
function TtTestForm.Eval_IndependentGridData(out AMean1, AMean2,
|
|
|
|
AVariance1, AVariance2, AStdDev1, AStdDev2: Double;
|
|
|
|
out ANumCases1, ANumCases2: Integer; out ALabel1Str, ALabel2Str: String): Boolean;
|
|
|
|
var
|
|
|
|
colNoSelected: IntDyneVec = nil;
|
|
|
|
values1: DblDyneVec = nil;
|
|
|
|
values2: DblDyneVec = nil;
|
|
|
|
grp1, grp2: Integer;
|
|
|
|
minf, maxf: Double;
|
|
|
|
|
|
|
|
begin
|
|
|
|
SetLength(colNoSelected, 2);
|
|
|
|
colNoSelected[0] := GetVariableIndex(OS3MainFrm.DataGrid, Var1Edit.Text);
|
|
|
|
colNoSelected[1] := GetVariableIndex(OS3MainFrm.DataGrid, GrpEdit.Text);
|
|
|
|
|
|
|
|
if GroupCodeChk.Checked then
|
|
|
|
begin
|
|
|
|
grp1 := StrToInt(Grp1CodeEdit.Text);
|
|
|
|
grp2 := StrToInt(Grp2CodeEdit.Text);
|
|
|
|
end else
|
|
|
|
begin
|
|
|
|
GetMinMax(OS3MainFrm.DataGrid, colNoSelected[1], colNoSelected, minf, maxf);
|
|
|
|
grp1 := round(minf);
|
|
|
|
grp2 := round(maxf);
|
|
|
|
end;
|
|
|
|
|
|
|
|
// Values in group with code given by grp1
|
|
|
|
values1 := CollectFilteredVecValues(OS3MainFrm.DataGrid, colNoSelected[0], colNoSelected[1], grp1, colNoSelected);
|
|
|
|
// Values in group with code given by grp2
|
|
|
|
values2 := CollectFilteredVecValues(OS3MainFrm.DataGrid, colNoSelected[0], colNoSelected[1], grp2, colNoSelected);
|
|
|
|
|
|
|
|
ANumCases1 := Length(values1);
|
|
|
|
ANumCases2 := Length(values2);
|
|
|
|
if ANumCases1 <> ANumCases2 then
|
|
|
|
begin
|
|
|
|
ErrorMsg('Both variables must have the same count of cases.');
|
|
|
|
Result := false;
|
|
|
|
exit;
|
|
|
|
end;
|
|
|
|
|
|
|
|
if ANumCases1 < 2 then begin
|
|
|
|
ErrorMsg('There must be at least 2 cases.');
|
|
|
|
Result := false;
|
|
|
|
exit;
|
|
|
|
end;
|
|
|
|
|
|
|
|
VecMeanVarStdDev(values1, AMean1, AVariance1, AStdDev1);
|
|
|
|
VecMeanVarStdDev(values2, AMean2, AVariance2, AStdDev2);
|
|
|
|
|
|
|
|
ALabel1Str := format('Group %d', [grp1]);
|
|
|
|
ALabel2Str := format('Group %d', [grp2]);
|
|
|
|
|
|
|
|
Result := true;
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
2020-11-04 23:14:23 +00:00
|
|
|
procedure TTtestForm.GroupCodeChkChange(Sender: TObject);
|
|
|
|
begin
|
|
|
|
Grp1CodeEdit.Enabled := GroupCodeChk.Checked;
|
|
|
|
Grp2CodeEdit.Enabled := GroupCodeChk.Checked;
|
|
|
|
GrpCodeLabel1.Enabled := GroupCodeChk.Checked;
|
|
|
|
GrpCodeLabel2.Enabled := GroupCodeChk.Checked;
|
2020-03-30 18:01:44 +00:00
|
|
|
end;
|
|
|
|
|
2020-11-04 23:14:23 +00:00
|
|
|
|
|
|
|
procedure TTtestForm.GrpInClick(Sender: TObject);
|
2020-03-30 18:01:44 +00:00
|
|
|
var
|
2020-11-04 23:14:23 +00:00
|
|
|
index: Integer;
|
2020-03-30 18:01:44 +00:00
|
|
|
begin
|
2020-11-04 23:14:23 +00:00
|
|
|
index := VarList.ItemIndex;
|
|
|
|
if (index > -1) and (GrpEdit.Text = '') then
|
|
|
|
begin
|
|
|
|
GrpEdit.Text := VarList.Items[index];
|
|
|
|
VarList.Items.Delete(index);
|
|
|
|
UpdateBtnStates;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
procedure TTtestForm.GrpOutClick(Sender: TObject);
|
|
|
|
begin
|
|
|
|
if GrpEdit.Text <> '' then
|
|
|
|
begin
|
|
|
|
VarList.Items.Add(GrpEdit.Text);
|
|
|
|
GrpEdit.Text := '';
|
|
|
|
UpdateBtnStates;
|
|
|
|
end;
|
2020-03-30 18:01:44 +00:00
|
|
|
end;
|
|
|
|
|
2020-11-04 23:14:23 +00:00
|
|
|
|
|
|
|
procedure TTtestForm.Reset;
|
|
|
|
var
|
|
|
|
i: integer;
|
|
|
|
begin
|
|
|
|
inherited;
|
|
|
|
DataEntryGroup.ItemIndex := 0;
|
|
|
|
DepIndepGroup.ItemIndex := 0;
|
|
|
|
Notebook.PageIndex := DataEntryGroup.ItemIndex;
|
|
|
|
independent := true;
|
|
|
|
griddata := false;
|
|
|
|
|
|
|
|
VarList.Clear;
|
|
|
|
for i := 1 to NoVariables do
|
|
|
|
VarList.Items.Add(OS3MainFrm.DataGrid.Cells[i,0]);
|
|
|
|
Var1Edit.Clear;
|
|
|
|
Var2Edit.Clear;
|
2020-11-05 13:38:59 +00:00
|
|
|
Mean1Edit.Clear;
|
|
|
|
Mean2Edit.Clear;
|
|
|
|
SD1Edit.Clear;
|
|
|
|
SD2Edit.Clear;
|
|
|
|
N1Edit.Clear;
|
|
|
|
N2Edit.Clear;
|
|
|
|
Cor12Edit.Clear;
|
2020-11-04 23:14:23 +00:00
|
|
|
GroupCodeChk.Checked := false;
|
|
|
|
GrpEdit.Clear;
|
|
|
|
Grp1CodeEdit.Clear;
|
|
|
|
Grp2CodeEdit.Clear;
|
|
|
|
|
|
|
|
DepIndepGroupClick(nil);
|
|
|
|
|
|
|
|
UpdateBtnStates;
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
procedure TTtestForm.UpdateBtnStates;
|
|
|
|
begin
|
|
|
|
inherited UpdateBtnStates;
|
|
|
|
|
|
|
|
Var1In.Enabled := (Var1Edit.Text = '') and (VarList.ItemIndex > -1);
|
|
|
|
Var2In.Enabled := (Var2Edit.Text = '') and (VarList.ItemIndex > -1);
|
|
|
|
GrpIn.Enabled := (GrpEdit.Text = '') and (VarList.ItemIndex > -1);
|
|
|
|
|
|
|
|
Var1Out.Enabled := Var1Edit.Text <> '';
|
|
|
|
Var2Out.Enabled := Var2Edit.Text <> '';
|
|
|
|
GrpOut.Enabled := GrpEdit.Text <> '';
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
function TTtestForm.Validate(out AMsg: String; out AControl: TWinControl): Boolean;
|
2020-03-30 18:01:44 +00:00
|
|
|
var
|
|
|
|
n: Integer;
|
|
|
|
x: Double;
|
|
|
|
begin
|
|
|
|
Result := false;
|
|
|
|
AControl := nil;
|
|
|
|
AMsg := '';
|
2020-11-04 23:14:23 +00:00
|
|
|
if Notebook.PageIndex = 0 then
|
2020-03-30 18:01:44 +00:00
|
|
|
begin
|
2020-11-05 13:38:59 +00:00
|
|
|
if (Mean1Edit.Text = '') or not TryStrToFloat(Mean1Edit.Text, x) then
|
2020-03-30 18:01:44 +00:00
|
|
|
begin
|
2020-11-05 13:38:59 +00:00
|
|
|
AControl := Mean1Edit;
|
2020-03-30 18:01:44 +00:00
|
|
|
AMsg := 'Invalid input for the mean of sample 1';
|
|
|
|
exit;
|
|
|
|
end;
|
2020-11-05 13:38:59 +00:00
|
|
|
if (SD1Edit.Text = '') or not TryStrToFloat(SD1Edit.Text, x) or (x <= 0) then
|
2020-03-30 18:01:44 +00:00
|
|
|
begin
|
2020-11-05 13:38:59 +00:00
|
|
|
AControl := SD1Edit;
|
2020-03-30 18:01:44 +00:00
|
|
|
AMsg := 'Invald input for the standard deviation of sample 1';
|
|
|
|
exit;
|
|
|
|
end;
|
2020-11-05 13:38:59 +00:00
|
|
|
if (N1Edit.Text = '') or not TryStrToInt(N1Edit.Text, n) or (n <= 0) then
|
2020-03-30 18:01:44 +00:00
|
|
|
begin
|
2020-11-05 13:38:59 +00:00
|
|
|
AControl := N1Edit;
|
2020-03-30 18:01:44 +00:00
|
|
|
AMsg := 'Invald input for the size of sample 1';
|
|
|
|
exit;
|
|
|
|
end;
|
2020-11-05 13:38:59 +00:00
|
|
|
if (Mean2Edit.Text = '') or not TryStrToFloat(Mean2Edit.Text, x) then
|
2020-03-30 18:01:44 +00:00
|
|
|
begin
|
2020-11-05 13:38:59 +00:00
|
|
|
AControl := Mean2Edit;
|
2020-03-30 18:01:44 +00:00
|
|
|
AMsg := 'Invalid input for the mean of sample 2';
|
|
|
|
exit;
|
|
|
|
end;
|
2020-11-05 13:38:59 +00:00
|
|
|
if (SD2Edit.Text = '') or not TryStrToFloat(SD2Edit.Text, x) or (x <= 0) then
|
2020-03-30 18:01:44 +00:00
|
|
|
begin
|
2020-11-05 13:38:59 +00:00
|
|
|
AControl := SD2Edit;
|
2020-03-30 18:01:44 +00:00
|
|
|
AMsg := 'Invald input for the standard deviation of sample 2';
|
|
|
|
exit;
|
|
|
|
end;
|
2020-11-05 13:38:59 +00:00
|
|
|
if (N2Edit.Text = '') or not TryStrToInt(N2Edit.Text, n) or (n <= 0) then
|
2020-03-30 18:01:44 +00:00
|
|
|
begin
|
2020-11-05 13:38:59 +00:00
|
|
|
AControl := N2Edit;
|
2020-03-30 18:01:44 +00:00
|
|
|
AMsg := 'Invald input for the size of sample 2';
|
|
|
|
exit;
|
|
|
|
end;
|
|
|
|
end else
|
2020-11-04 23:14:23 +00:00
|
|
|
if Notebook.PageIndex = 1 then
|
2020-03-30 18:01:44 +00:00
|
|
|
begin
|
2020-11-04 23:14:23 +00:00
|
|
|
if (Var1Edit.Text = '') then
|
2020-03-30 18:01:44 +00:00
|
|
|
begin
|
2020-11-04 23:14:23 +00:00
|
|
|
AControl := Var1Edit;
|
2020-03-30 18:01:44 +00:00
|
|
|
AMsg := 'Variable 1 not specified.';
|
|
|
|
exit;
|
|
|
|
end;
|
2020-11-04 23:14:23 +00:00
|
|
|
if Var2Edit.Visible and (Var2Edit.Text = '') then
|
2020-03-30 18:01:44 +00:00
|
|
|
begin
|
2020-11-04 23:14:23 +00:00
|
|
|
AControl := Var2Edit;
|
2020-03-30 18:01:44 +00:00
|
|
|
AMsg := 'Variable 2 not specified.';
|
|
|
|
exit;
|
|
|
|
end;
|
2020-11-04 23:14:23 +00:00
|
|
|
if GrpEdit.Visible and (GrpEdit.Text = '') then
|
2020-03-30 18:01:44 +00:00
|
|
|
begin
|
2020-11-04 23:14:23 +00:00
|
|
|
AControl := GrpEdit;
|
2020-03-30 18:01:44 +00:00
|
|
|
AMsg := 'Group variable not specified.';
|
|
|
|
exit;
|
|
|
|
end;
|
2020-11-05 13:38:59 +00:00
|
|
|
if GroupCodeChk.Checked then
|
2020-03-30 18:01:44 +00:00
|
|
|
begin
|
2020-11-05 13:38:59 +00:00
|
|
|
if Grp1CodeEdit.Visible and
|
|
|
|
((Grp1CodeEdit.Text = '') or not TryStrToInt(Grp1CodeEdit.Text, n)) then
|
|
|
|
begin
|
|
|
|
AControl := Grp1CodeEdit;
|
|
|
|
AMsg := 'Code for group 1 missing.';
|
|
|
|
exit;
|
|
|
|
end;
|
|
|
|
if Grp2CodeEdit.Visible and
|
|
|
|
((Grp2CodeEdit.Text = '') or not TryStrToInt(Grp2CodeEdit.Text, n))then
|
|
|
|
begin
|
|
|
|
AControl := Grp2CodeEdit;
|
|
|
|
AMsg := 'Code for group 2 missing.';
|
|
|
|
exit;
|
|
|
|
end;
|
2020-03-30 18:01:44 +00:00
|
|
|
end;
|
|
|
|
end;
|
|
|
|
Result := true;
|
|
|
|
end;
|
|
|
|
|
2020-11-04 23:14:23 +00:00
|
|
|
|
|
|
|
procedure TTtestForm.Var1InClick(Sender: TObject);
|
|
|
|
var
|
|
|
|
index: Integer;
|
|
|
|
begin
|
|
|
|
index := VarList.ItemIndex;
|
|
|
|
if (index > -1) and (Var1Edit.Text = '') then
|
|
|
|
begin
|
|
|
|
Var1Edit.Text := VarList.Items[index];
|
|
|
|
VarList.Items.Delete(index);
|
|
|
|
UpdateBtnStates;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
procedure TTtestForm.Var1OutClick(Sender: TObject);
|
|
|
|
begin
|
|
|
|
if Var1Edit.Text <> '' then
|
|
|
|
begin
|
|
|
|
VarList.Items.Add(Var1Edit.Text);
|
|
|
|
Var1Edit.Text := '';
|
|
|
|
UpdateBtnStates;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
procedure TTtestForm.Var2InClick(Sender: TObject);
|
|
|
|
var
|
|
|
|
index: Integer;
|
|
|
|
begin
|
|
|
|
index := VarList.ItemIndex;
|
|
|
|
if (index > -1) and (Var2Edit.Text = '') then
|
|
|
|
begin
|
|
|
|
Var2Edit.Text := VarList.Items[index];
|
|
|
|
VarList.Items.Delete(index);
|
|
|
|
UpdateBtnStates;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
procedure TTtestForm.Var2OutClick(Sender: TObject);
|
|
|
|
begin
|
|
|
|
if Var2Edit.Text <> '' then
|
|
|
|
begin
|
|
|
|
VarList.Items.Add(Var2Edit.Text);
|
|
|
|
Var2Edit.Text := '';
|
|
|
|
UpdateBtnStates;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
procedure TTtestForm.VarListDblClick(Sender: TObject);
|
|
|
|
var
|
|
|
|
index: integer;
|
|
|
|
s: String;
|
|
|
|
begin
|
|
|
|
index := VarList.ItemIndex;
|
|
|
|
if index > -1 then
|
|
|
|
begin
|
|
|
|
s := VarList.Items[index];
|
|
|
|
if Var1Edit.Text = '' then
|
|
|
|
begin
|
|
|
|
Var1Edit.Text := s;
|
|
|
|
VarList.Items.Delete(index);
|
|
|
|
end else
|
|
|
|
if independent then
|
|
|
|
begin
|
|
|
|
if GrpEdit.Text = '' then
|
|
|
|
begin
|
|
|
|
GrpEdit.Text := s;
|
|
|
|
VarList.Items.Delete(index);
|
|
|
|
end;
|
|
|
|
end else
|
|
|
|
begin
|
|
|
|
if Var2Edit.Text = '' then
|
|
|
|
begin
|
|
|
|
Var2Edit.Text := s;
|
|
|
|
VarList.Items.Delete(index);
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
UpdateBtnStates;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
procedure TTtestForm.VarListSelectionChange(Sender: TObject; User: boolean);
|
|
|
|
begin
|
|
|
|
UpdateBtnStates;
|
|
|
|
end;
|
|
|
|
|
2020-03-30 18:01:44 +00:00
|
|
|
|
|
|
|
end.
|
|
|
|
|