You've already forked lazarus-ccr
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@7818 8e941d3f-bd1b-0410-a28a-d453659cc2b4
216 lines
5.2 KiB
ObjectPascal
216 lines
5.2 KiB
ObjectPascal
unit BinomialUnit;
|
|
|
|
{$mode objfpc}{$H+}
|
|
|
|
interface
|
|
|
|
uses
|
|
Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls, ExtCtrls,
|
|
FunctionsLib, GraphLib, BasicStatsReportAndChartFormUnit;
|
|
|
|
type
|
|
|
|
{ TBinomialForm }
|
|
|
|
TBinomialForm = class(TBasicStatsReportAndChartForm)
|
|
FreqAEdit: TEdit;
|
|
FreqBEdit: TEdit;
|
|
PropAEdit: TEdit;
|
|
FreqALabel: TLabel;
|
|
FreqBLabel: TLabel;
|
|
PropALabel: TLabel;
|
|
private
|
|
|
|
protected
|
|
procedure AdjustConstraints; override;
|
|
procedure Compute; override;
|
|
function Validate(out AMsg: String; out AControl: TWinControl): Boolean; override;
|
|
|
|
public
|
|
constructor Create(AOwner: TComponent); override;
|
|
procedure Reset; override;
|
|
end;
|
|
|
|
var
|
|
BinomialForm: TBinomialForm;
|
|
|
|
|
|
implementation
|
|
|
|
{$R *.lfm}
|
|
|
|
uses
|
|
Math,
|
|
TACustomSeries,
|
|
Globals, MathUnit, ChartFrameUnit;
|
|
|
|
{ TBinomialForm }
|
|
|
|
constructor TBinomialForm.Create(AOwner: TComponent);
|
|
begin
|
|
inherited;
|
|
FChartFrame.Chart.Margins.Bottom := 0;
|
|
FChartFrame.Chart.BottomAxis.AxisPen.Visible := true;
|
|
FChartFrame.Chart.BottomAxis.ZPosition := 1;
|
|
end;
|
|
|
|
|
|
procedure TBinomialForm.AdjustConstraints;
|
|
begin
|
|
inherited;
|
|
|
|
ParamsPanel.Constraints.MinWidth := Max(
|
|
PropALabel.Width + PropAEdit.Width + PropAEdit.BorderSpacing.Left,
|
|
4*CloseBtn.Width + 3*CloseBtn.BorderSpacing.Left
|
|
);
|
|
ParamsPanel.Constraints.MinHeight := PropAEdit.Top + PropAEdit.Height
|
|
end;
|
|
|
|
|
|
procedure TBinomialForm.Reset;
|
|
begin
|
|
inherited;
|
|
FreqAEdit.Clear;
|
|
FreqBEdit.Clear;
|
|
PropAEdit.Clear;
|
|
end;
|
|
|
|
|
|
procedure TBinomialForm.Compute;
|
|
const
|
|
N_MAX = 35;
|
|
var
|
|
P, Q, probability, z, correctedA, SumProb, mean, sigma: double;
|
|
A, B, N, i: integer;
|
|
xPts: DblDyneVec = nil;
|
|
yPts: DblDyneVec = nil;
|
|
lReport: TStrings;
|
|
ser: TChartSeries;
|
|
begin
|
|
A := round(StrToFloat(FreqAEdit.Text));
|
|
B := round(StrToFloat(FreqBEdit.Text));
|
|
P := StrToFloat(PropAEdit.Text);
|
|
N := A + B;
|
|
Q := 1.0 - P;
|
|
|
|
lReport := TStringList.Create;
|
|
try
|
|
lReport.Add('BINOMIAL PROBABILITY TEST');
|
|
lReport.Add('');
|
|
lReport.Add('Frequency of %d out of %d observed', [A, N]);
|
|
lReport.Add('The theoretical proportion expected in category A is %.3f', [P]);
|
|
lReport.Add('');
|
|
lReport.Add('The test is for the probability of a value in category A as small or smaller');
|
|
lReport.Add('than that observed given the expected proportion.');
|
|
lReport.Add('');
|
|
|
|
if (N > N_MAX) then
|
|
begin
|
|
// Use normal distribution approximation
|
|
correctedA := A;
|
|
if A < N * P then correctedA := A + 0.5;
|
|
if A > N * P then correctedA := A - 0.5;
|
|
z := (correctedA - N * P) / sqrt(N * P * Q);
|
|
lReport.Add('Z value for normal nistribution approximation: %.3f', [z]);
|
|
Probability := NormalDist(z);
|
|
lReport.Add('Probability: %6.4f', [Probability]);
|
|
end else
|
|
begin
|
|
// Use binomial fomula
|
|
sumProb := 0;
|
|
for i := 0 to A do
|
|
begin
|
|
Probability := combos(i, N) * IntPower(P, i) * IntPower(Q, N-i);
|
|
lReport.Add('Probability of %d: %6.4f', [i, Probability]);
|
|
sumProb := sumProb + Probability;
|
|
end;
|
|
lReport.Add('');
|
|
lReport.Add('Binomial Probability of %d or less out of %d: %.4f', [A, N, sumProb]);
|
|
end;
|
|
|
|
FReportFrame.DisplayReport(lReport);
|
|
finally
|
|
lReport.Free;
|
|
end;
|
|
|
|
// Plot the distribution
|
|
FChartFrame.Clear;
|
|
FChartFrame.SetXTitle('Values');
|
|
FChartFrame.SetYTitle('Probability');
|
|
if N > N_MAX then
|
|
begin
|
|
FChartFrame.SetTitle('Binomial Distribution' + LineEnding + '(approximated by Normal Distribution)');
|
|
mean := N*P;
|
|
sigma := sqrt(N * P * Q);
|
|
SetLength(xPts, N+1);
|
|
SetLength(yPts, N+1);
|
|
for i := 0 to N do
|
|
begin
|
|
xPts[i] := i;
|
|
yPts[i] := NormalDistDensity(i, mean, sigma);
|
|
end;
|
|
end else
|
|
begin
|
|
FChartFrame.SetTitle('Binomial Distribution');
|
|
SetLength(xPts, N+1);
|
|
SetLength(yPts, N+1);
|
|
for i := 0 to N do
|
|
begin
|
|
xPts[i] := i;
|
|
yPts[i] := Combos(i, N) * IntPower(p, i) * IntPower(Q, N-i);
|
|
end;
|
|
end;
|
|
if N < 50 then
|
|
ser := FChartFrame.PlotXY(ptBars, xPts, yPts, nil, nil, '', DATA_COLORS[0])
|
|
else
|
|
ser := FChartFrame.PlotXY(ptArea, xPts, yPts, nil, nil, '', DATA_COLORS[0]);
|
|
ser.ZPosition := 2;
|
|
FChartFrame.Chart.Legend.Visible := false;
|
|
end;
|
|
|
|
|
|
function TBinomialForm.Validate(out AMsg: String; out AControl: TWinControl): Boolean;
|
|
var
|
|
x: Double;
|
|
n: Integer;
|
|
begin
|
|
Result := false;
|
|
if (FreqAEdit.Text = '') or (FreqBEdit.Text = '') or (PropAEdit.Text = '') then
|
|
begin
|
|
AMsg := 'Value not specified.';
|
|
if FreqAEdit.Text = '' then AControl := FreqAEdit;
|
|
if FreqBEdit.Text = '' then AControl := FreqBEdit;
|
|
if PropAEdit.Text = '' then AControl := PropAEdit;
|
|
exit;
|
|
end;
|
|
if not TryStrToInt(FreqAEdit.Text, n) then
|
|
begin
|
|
AMsg := 'No valid integer.';
|
|
AControl := FreqAEdit;
|
|
exit;
|
|
end;
|
|
if not TryStrToInt(FreqBEdit.Text, n) then
|
|
begin
|
|
AMsg := 'No valid integer.';
|
|
AControl := FreqBEdit;
|
|
exit;
|
|
end;
|
|
if not TryStrToFloat(PropAEdit.Text, x) then
|
|
begin
|
|
AMsg := 'No valid number.';
|
|
AControl := PropAEdit;
|
|
exit;
|
|
end;
|
|
if (x < 0) or (x > 1) then
|
|
begin
|
|
AMsg := 'Number between 0 and 1 expected.';
|
|
AControl := PropAEdit;
|
|
exit;
|
|
end;
|
|
|
|
Result := true;
|
|
end;
|
|
|
|
end.
|
|
|