You've already forked lazarus-ccr
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@7409 8e941d3f-bd1b-0410-a28a-d453659cc2b4
384 lines
8.7 KiB
ObjectPascal
384 lines
8.7 KiB
ObjectPascal
// Use file "cansas.laz" for testing
|
|
|
|
unit NormalityUnit;
|
|
|
|
{$mode objfpc}{$H+}
|
|
|
|
interface
|
|
|
|
uses
|
|
Classes, SysUtils, FileUtil, LResources, Forms, Controls, Graphics, Dialogs,
|
|
StdCtrls, Buttons, ExtCtrls,
|
|
MainUnit, Globals, FunctionsLib, DataProcs, OutputUnit;
|
|
|
|
|
|
type
|
|
|
|
{ TNormalityFrm }
|
|
|
|
TNormalityFrm = class(TForm)
|
|
Bevel1: TBevel;
|
|
ResetBtn: TButton;
|
|
PrintBtn: TButton;
|
|
ApplyBtn: TButton;
|
|
CloseBtn: TButton;
|
|
ConclusionEdit: TEdit;
|
|
Label8: TLabel;
|
|
Panel1: TPanel;
|
|
StatEdit: TEdit;
|
|
KurtosisEdit: TEdit;
|
|
SkewEdit: TEdit;
|
|
GroupBox2: TGroupBox;
|
|
Label5: TLabel;
|
|
Label6: TLabel;
|
|
Label7: TLabel;
|
|
ProbEdit: TEdit;
|
|
Label4: TLabel;
|
|
WEdit: TEdit;
|
|
GroupBox1: TGroupBox;
|
|
Label3: TLabel;
|
|
TestVarEdit: TEdit;
|
|
Label2: TLabel;
|
|
VarInBtn: TBitBtn;
|
|
VarOutBtn: TBitBtn;
|
|
Label1: TLabel;
|
|
VarList: TListBox;
|
|
procedure ApplyBtnClick(Sender: TObject);
|
|
procedure FormActivate(Sender: TObject);
|
|
procedure FormCreate(Sender: TObject);
|
|
procedure FormShow(Sender: TObject);
|
|
procedure PrintBtnClick(Sender: TObject);
|
|
procedure ResetBtnClick(Sender: TObject);
|
|
procedure VarInBtnClick(Sender: TObject);
|
|
procedure VarListSelectionChange(Sender: TObject; User: boolean);
|
|
procedure VarOutBtnClick(Sender: TObject);
|
|
private
|
|
{ private declarations }
|
|
FAutoSized: boolean;
|
|
function Norm(z : double) : double;
|
|
procedure UpdateBtnStates;
|
|
|
|
public
|
|
{ public declarations }
|
|
end;
|
|
|
|
var
|
|
NormalityFrm: TNormalityFrm;
|
|
|
|
implementation
|
|
|
|
uses
|
|
Math;
|
|
|
|
{ TNormalityFrm }
|
|
|
|
procedure TNormalityFrm.PrintBtnClick(Sender: TObject);
|
|
var
|
|
lReport: TStrings;
|
|
begin
|
|
lReport := TStringList.Create;
|
|
try
|
|
lReport.Add('NORMALITY TESTS FOR '+ TestVarEdit.Text);
|
|
lReport.Add('');
|
|
lReport.Add('Shapiro-Wilkes W = ' + WEdit.Text);
|
|
lReport.Add('Shapiro-Wilkes Prob. = ' + ProbEdit.Text);
|
|
lReport.Add('');
|
|
lReport.Add('Skew = ' + SkewEdit.Text);
|
|
lReport.Add('Kurtosis = ' + KurtosisEdit.Text);
|
|
lReport.Add('Lilliefors Test Statistic = ' + StatEdit.Text);
|
|
lReport.Add('Conclusion: ' + ConclusionEdit.Text);
|
|
|
|
DisplayReport(lReport);
|
|
finally
|
|
lReport.Free;
|
|
end;
|
|
end;
|
|
|
|
procedure TNormalityFrm.ResetBtnClick(Sender: TObject);
|
|
var
|
|
i: integer;
|
|
begin
|
|
TestVarEdit.Text := '';
|
|
WEdit.Text := '';
|
|
ProbEdit.Text := '';
|
|
ConclusionEdit.Text := '';
|
|
SkewEdit.Text := '';
|
|
KurtosisEdit.Text := '';
|
|
StatEdit.Text := '';
|
|
VarList.Items.Clear;
|
|
for i := 1 to NoVariables do
|
|
VarList.Items.Add(OS3MainFrm.DataGrid.Cells[i,0]);
|
|
UpdateBtnStates;
|
|
end;
|
|
|
|
procedure TNormalityFrm.FormActivate(Sender: TObject);
|
|
var
|
|
w: Integer;
|
|
begin
|
|
if FAutoSized then
|
|
exit;
|
|
|
|
w := MaxValue([ResetBtn.Width, PrintBtn.Width, ApplyBtn.Width, CloseBtn.Width]);
|
|
ResetBtn.Constraints.MinWidth := w;
|
|
PrintBtn.Constraints.MinWidth := w;
|
|
ApplyBtn.Constraints.MinWidth := w;
|
|
CloseBtn.Constraints.MinWidth := w;
|
|
|
|
FAutoSized := True;
|
|
end;
|
|
|
|
procedure TNormalityFrm.FormCreate(Sender: TObject);
|
|
begin
|
|
Assert(OS3MainFrm <> nil);
|
|
end;
|
|
|
|
procedure TNormalityFrm.FormShow(Sender: TObject);
|
|
begin
|
|
ResetBtnClick(nil);
|
|
end;
|
|
|
|
procedure TNormalityFrm.ApplyBtnClick(Sender: TObject);
|
|
var
|
|
w: Double = 0.0;
|
|
pw: Double = 0.0;
|
|
temp: double;
|
|
skew, kurtosis : double;
|
|
mean, variance, stddev, deviation, devsqr, M2, M3, M4 : double;
|
|
i, j, n, n1, n2, ier : integer;
|
|
selcol : integer;
|
|
data, a, z, x : DblDyneVec;
|
|
freq : IntDyneVec;
|
|
fval, jval, DP : DblDyneVec;
|
|
F1, DPP, D, A0, C1, D15, D10, D05, D025, t2 : double;
|
|
init : boolean;
|
|
msg : string;
|
|
|
|
procedure Cleanup;
|
|
begin
|
|
DP := nil;
|
|
jval := nil;
|
|
fval := nil;
|
|
data := nil;
|
|
a := nil;
|
|
freq := nil;
|
|
z := nil;
|
|
x := nil;
|
|
end;
|
|
|
|
begin
|
|
selcol := 0;
|
|
for i := 1 to NoVariables do
|
|
if OS3MainFrm.DataGrid.Cells[i,0] = TestVarEdit.Text then
|
|
begin
|
|
selcol := i;
|
|
break;
|
|
end;
|
|
if selCol = 0 then
|
|
begin
|
|
MessageDlg('No variable selected.', mtError, [mbOK], 0);
|
|
exit;
|
|
end;
|
|
|
|
init := false;
|
|
n := 0;
|
|
|
|
// place values into the data array
|
|
SetLength(data, NoCases+1); // arrays start at 1
|
|
SetLength(a, NoCases+1);
|
|
SetLength(freq, NoCases+1);
|
|
SetLength(z, NoCases+1);
|
|
SetLength(x, NoCases+1);
|
|
SetLength(fval, NoCases+1);
|
|
SetLength(jval, NoCases+1);
|
|
SetLength(DP, NoCases+1);
|
|
for i := 1 to NoCases do
|
|
begin
|
|
if not ValidValue(i,selcol) then
|
|
continue;
|
|
n := n + 1;
|
|
data[n] := StrToFloat(OS3MainFrm.DataGrid.Cells[selcol,i]);
|
|
end;
|
|
n1 := n;
|
|
n2 := n div 2;
|
|
|
|
// sort into ascending order
|
|
for i := 1 to n - 1 do
|
|
begin
|
|
for j := i + 1 to n do
|
|
begin
|
|
if data[i] > data[j] then
|
|
begin
|
|
temp := data[i];
|
|
data[i] := data[j];
|
|
data[j] := temp;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
// call Shapiro-Wilks function
|
|
swilk(init, data, n, n1, n2, a, w, pw, ier);
|
|
if ier <> 0 then
|
|
begin
|
|
msg := 'Error encountered = ' + IntToStr(ier);
|
|
MessageDlg(msg, mtError, [mbOK], 0);
|
|
Cleanup;
|
|
exit;
|
|
end;
|
|
WEdit.Text := Format('%.4f', [w]);
|
|
ProbEdit.Text := Format('%.4f', [pw]);
|
|
|
|
// Now do Lilliefors
|
|
// Get unique scores and their frequencies
|
|
n1 := 1;
|
|
i := 1;
|
|
freq[1] := 1;
|
|
x[1] := data[1];
|
|
repeat
|
|
//again:
|
|
for j := i + 1 to n do
|
|
begin
|
|
if data[j] = x[n1] then freq[n1] := freq[n1] + 1;
|
|
end;
|
|
i := i + freq[n1];
|
|
if i <= n then
|
|
begin
|
|
n1 := n1 + 1;
|
|
x[n1] := data[i];
|
|
freq[n1] := 1;
|
|
//goto again;
|
|
end;
|
|
until i > n;
|
|
|
|
// now get skew and kurtosis of scores
|
|
mean := 0.0;
|
|
variance := 0.0;
|
|
for i := 1 to n do
|
|
begin
|
|
mean := mean + data[i];
|
|
variance := variance + (data[i] * data[i]);
|
|
end;
|
|
variance := variance - (mean * mean) / n;
|
|
variance := variance / (n - 1);
|
|
stddev := sqrt(variance);
|
|
mean := mean / n;
|
|
|
|
// obtain skew, kurtosis and z scores
|
|
M2 := 0.0;
|
|
M3 := 0.0;
|
|
M4 := 0.0;
|
|
for i := 1 to n do
|
|
begin
|
|
deviation := data[i] - mean;
|
|
devsqr := deviation * deviation;
|
|
M2 := M2 + devsqr;
|
|
M3 := M3 + (deviation * devsqr);
|
|
M4 := M4 + (devsqr * devsqr);
|
|
z[i] := (data[i] - mean) / stddev;
|
|
end;
|
|
for i := 1 to n1 do x[i] := (x[i] - mean) / stddev;
|
|
skew := (n * M3) / ((n - 1) * (n - 2) * stddev * variance);
|
|
kurtosis := (n * (n + 1) * M4) - (3 * M2 * M2 * (n - 1));
|
|
kurtosis := kurtosis /( (n - 1) * (n - 2) * (n - 3) * (variance * variance) );
|
|
SkewEdit.Text := Format('%.3f', [skew]);
|
|
KurtosisEdit.Text := Format('%.3f', [kurtosis]);
|
|
|
|
// obtain the test statistic
|
|
for i := 1 to n1 do
|
|
begin
|
|
F1 := Norm(x[i]);
|
|
if x[i] >= 0 then
|
|
fval[i] := 1.0 - (F1 / 2.0)
|
|
else
|
|
fval[i] := F1 / 2.0;
|
|
end;
|
|
|
|
// cumulative proportions
|
|
jval[1] := freq[1] / n;
|
|
for i := 2 to n1 do jval[i] := jval[i-1] + freq[i] / n;
|
|
for i := 1 to n1 do DP[i] := abs(jval[i] - fval[i]);
|
|
|
|
// sort DP
|
|
for i := 1 to n1-1 do
|
|
begin
|
|
for j := i+1 to n1 do
|
|
begin
|
|
if DP[j] < DP[i] then
|
|
begin
|
|
temp := DP[i];
|
|
DP[i] := DP[j];
|
|
DP[j] := temp;
|
|
end;
|
|
end;
|
|
end;
|
|
DPP := DP[n1];
|
|
D := DPP;
|
|
StatEdit.Text := Format('%.3f', [D]);
|
|
A0 := sqrt(n);
|
|
C1 := A0 - 0.01 + (0.85 / A0);
|
|
D15 := 0.775 / C1;
|
|
D10 := 0.819 / C1;
|
|
D05 := 0.895 / C1;
|
|
D025 := 0.995 / C1;
|
|
t2 := D;
|
|
if t2 > D025 then ConclusionEdit.Text := 'Strong evidence against normality.';
|
|
if ((t2 <= D025) and (t2 > D05)) then ConclusionEdit.Text := 'Sufficient evidence against normality.';
|
|
if ((t2 <= D05) and (t2 > D10)) then ConclusionEdit.Text := 'Suggestive evidence against normality.';
|
|
if ((t2 <= D10) and (t2 > D15)) then ConclusionEdit.Text := 'Little evidence against normality.';
|
|
if (t2 <= D15) then ConclusionEdit.Text := 'No evidence against normality.';
|
|
|
|
Cleanup;
|
|
end;
|
|
|
|
procedure TNormalityFrm.VarInBtnClick(Sender: TObject);
|
|
var
|
|
i: integer;
|
|
begin
|
|
i := VarList.ItemIndex;
|
|
if (i > -1) and (TestVarEdit.Text = '') then
|
|
begin
|
|
TestVarEdit.Text := VarList.Items.Strings[i];
|
|
VarList.Items.Delete(i);
|
|
end;
|
|
UpdateBtnStates;
|
|
end;
|
|
|
|
procedure TNormalityFrm.VarListSelectionChange(Sender: TObject; User: boolean);
|
|
begin
|
|
UpdateBtnStates;
|
|
end;
|
|
|
|
procedure TNormalityFrm.VarOutBtnClick(Sender: TObject);
|
|
begin
|
|
if TestVarEdit.Text <> '' then
|
|
begin
|
|
VarList.Items.Add(TestVarEdit.Text);
|
|
TestVarEdit.Text := '';
|
|
end;
|
|
UpdateBtnStates;
|
|
end;
|
|
|
|
function TNormalityFrm.Norm(z : double) : double;
|
|
var
|
|
p : double;
|
|
begin
|
|
z := abs(z);
|
|
p := 1.0 + z * (0.04986735 + z * (0.02114101 + z * (0.00327763 +
|
|
z * (0.0000380036 + z * (0.0000488906 + z * 0.000005383)))));
|
|
p := p * p;
|
|
p := p * p;
|
|
p := p * p;
|
|
Result := 1.0 / (p * p);
|
|
end;
|
|
|
|
procedure TNormalityFrm.UpdateBtnStates;
|
|
begin
|
|
VarInBtn.Enabled := (VarList.ItemIndex > -1) and (TestVarEdit.Text = '');
|
|
VarOutBtn.Enabled := (TestVarEdit.Text <> '');
|
|
end;
|
|
|
|
initialization
|
|
{$I normalityunit.lrs}
|
|
|
|
end.
|
|
|