LazStats: Fix XBar Control Chart UCL/LCL values to agree with commercial JMP statistics software.

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@7664 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz
2020-09-12 22:29:19 +00:00
parent f3a750effb
commit ed04056db4
5 changed files with 121 additions and 95 deletions

View File

@ -11,11 +11,12 @@ object BasicSPCForm: TBasicSPCForm
OnShow = FormShow
LCLVersion = '2.1.0.0'
object SpecsPanel: TPanel
Left = 0
Left = 8
Height = 438
Top = 0
Width = 357
Align = alLeft
BorderSpacing.Left = 8
BorderSpacing.Right = 3
BevelOuter = bvNone
ClientHeight = 438
@ -111,11 +112,10 @@ object BasicSPCForm: TBasicSPCForm
object VarListLabel: TLabel
AnchorSideLeft.Control = SpecsPanel
AnchorSideTop.Control = SpecsPanel
Left = 8
Left = 0
Height = 15
Top = 8
Width = 97
BorderSpacing.Left = 8
BorderSpacing.Top = 8
Caption = 'Selection Variables'
ParentColor = False
@ -126,12 +126,11 @@ object BasicSPCForm: TBasicSPCForm
AnchorSideTop.Side = asrBottom
AnchorSideRight.Control = MeasInBtn
AnchorSideBottom.Control = ButtonPanel
Left = 8
Left = 0
Height = 363
Top = 25
Width = 150
Width = 158
Anchors = [akTop, akLeft, akRight, akBottom]
BorderSpacing.Left = 8
BorderSpacing.Top = 2
BorderSpacing.Right = 8
BorderSpacing.Bottom = 8
@ -266,17 +265,17 @@ object BasicSPCForm: TBasicSPCForm
end
end
object SpecsSplitter: TSplitter
Left = 360
Left = 368
Height = 438
Top = 0
Width = 5
ResizeStyle = rsPattern
end
object PageControl: TPageControl
Left = 368
Left = 376
Height = 426
Top = 6
Width = 553
Width = 545
ActivePage = ReportPage
Align = alClient
BorderSpacing.Left = 3
@ -288,24 +287,24 @@ object BasicSPCForm: TBasicSPCForm
object ReportPage: TTabSheet
Caption = 'Report'
ClientHeight = 398
ClientWidth = 545
ClientWidth = 537
object Panel1: TPanel
Left = 6
Height = 358
Top = 34
Width = 533
Width = 525
Align = alClient
BorderSpacing.Around = 6
BevelOuter = bvNone
BorderStyle = bsSingle
ClientHeight = 354
ClientWidth = 529
ClientWidth = 521
TabOrder = 0
object ReportMemo: TMemo
Left = 4
Height = 346
Top = 4
Width = 521
Width = 513
Align = alClient
BorderSpacing.Around = 4
BorderStyle = bsNone
@ -320,7 +319,7 @@ object BasicSPCForm: TBasicSPCForm
Left = 0
Height = 22
Top = 6
Width = 541
Width = 533
AutoSize = True
BorderSpacing.Top = 6
BorderSpacing.Right = 4
@ -359,12 +358,12 @@ object BasicSPCForm: TBasicSPCForm
object ChartPage: TTabSheet
Caption = 'Chart'
ClientHeight = 398
ClientWidth = 545
ClientWidth = 537
object ChartToolBar: TToolBar
Left = 0
Height = 22
Top = 6
Width = 541
Width = 533
AutoSize = True
BorderSpacing.Top = 6
BorderSpacing.Right = 4

View File

@ -95,7 +95,7 @@ var
// Constants for correction of standard deviation, needed by some charts.
const
C4: array[1..24] of double = (
C4: array[2..25] of double = (
0.7979, 0.8862, 0.9213, 0.9400, 0.9515, 0.9594, 0.9650, 0.9693,
0.9727, 0.9754, 0.9776, 0.9794, 0.9810, 0.9823, 0.9835, 0.9845, 0.9854, 0.9862,
0.9869, 0.9876, 0.9882, 0.9887, 0.9892, 0.9896);
@ -193,7 +193,7 @@ begin
CloseBtn.Constraints.MinWidth := w;
SpecsPanel.Constraints.MinWidth := Max(
VarListLabel.Left + VarListLabel.Width + MeasLabel.Width,
VarListLabel.Left + VarListLabel.Width + Varlist.BorderSpacing.Right * 2 + MeasInBtn.Width + MeasLabel.Width,
CloseBtn.Left + CloseBtn.Width - HelpBtn.Left + HelpBtn.BorderSpacing.Around
);
Constraints.MinHeight := MeasEdit.Top + MeasEdit.Height + MeasEdit.BorderSpacing.Bottom + ButtonPanel.Height;

View File

@ -1,82 +1,82 @@
inherited XBarChartForm: TXBarChartForm
Left = 572
Height = 443
Height = 431
Top = 215
HelpType = htKeyword
HelpKeyword = 'html/XBarChart.htm'
Caption = 'X-Bar Control Chart'
ClientHeight = 443
ClientHeight = 431
OnActivate = FormActivate
inherited SpecsPanel: TPanel
Height = 443
Width = 475
ClientHeight = 443
ClientWidth = 475
Height = 431
Width = 379
ClientHeight = 431
ClientWidth = 379
inherited ButtonPanel: TPanel
Top = 401
Width = 475
ClientWidth = 475
Top = 389
Width = 379
ClientWidth = 379
TabOrder = 5
inherited CloseBtn: TButton
Left = 420
Left = 324
end
inherited ComputeBtn: TButton
Left = 336
Left = 240
end
inherited ResetBtn: TButton
Left = 274
Left = 178
end
inherited HelpBtn: TButton
Left = 223
Left = 127
end
inherited Bevel1: TBevel
Width = 467
Width = 371
end
end
inherited VarList: TListBox
Height = 368
Width = 209
Height = 356
Width = 169
end
inherited GroupLabel: TLabel
Left = 257
Left = 209
end
inherited GroupEdit: TEdit
Left = 257
Width = 218
Left = 209
Width = 170
end
inherited MeasLabel: TLabel
Left = 257
Left = 209
end
inherited MeasEdit: TEdit
AnchorSideRight.Control = LevelOptns
Left = 257
Width = 218
Left = 209
Width = 170
end
inherited Bevel2: TBevel
Left = 226
Left = 178
end
inherited MeasInBtn: TSpeedButton
Left = 225
Left = 177
end
inherited MeasOutBtn: TSpeedButton
Left = 226
Left = 178
end
inherited GroupInBtn: TSpeedButton
Left = 225
Left = 177
end
inherited GroupOutBtn: TSpeedButton
Left = 226
Left = 178
end
object SigmaOpts: TRadioGroup[12]
AnchorSideLeft.Control = MeasEdit
AnchorSideTop.Control = GroupEdit
AnchorSideLeft.Control = MeasInBtn
AnchorSideTop.Control = GroupOutBtn
AnchorSideTop.Side = asrBottom
AnchorSideRight.Control = LevelOptns
AnchorSideRight.Side = asrBottom
Left = 257
Left = 177
Height = 128
Top = 145
Width = 218
Top = 153
Width = 202
Anchors = [akTop, akLeft, akRight]
AutoFill = True
BorderSpacing.Top = 12
@ -90,7 +90,7 @@ inherited XBarChartForm: TXBarChartForm
ChildSizing.Layout = cclLeftToRightThenTopToBottom
ChildSizing.ControlsPerLine = 1
ClientHeight = 108
ClientWidth = 214
ClientWidth = 198
ItemIndex = 0
Items.Strings = (
'3 Sigma'
@ -106,7 +106,7 @@ inherited XBarChartForm: TXBarChartForm
Left = 128
Height = 23
Top = 80
Width = 74
Width = 58
Alignment = taRightJustify
Anchors = [akLeft, akRight, akBottom]
BorderSpacing.Right = 8
@ -115,22 +115,22 @@ inherited XBarChartForm: TXBarChartForm
end
end
object LevelOptns: TGroupBox[13]
AnchorSideLeft.Control = MeasEdit
AnchorSideLeft.Control = MeasInBtn
AnchorSideTop.Control = SigmaOpts
AnchorSideTop.Side = asrBottom
AnchorSideRight.Control = MeasEdit
AnchorSideRight.Side = asrBottom
Left = 257
Left = 177
Height = 103
Top = 285
Width = 218
Top = 293
Width = 202
Anchors = [akTop, akLeft, akRight]
AutoSize = True
BorderSpacing.Top = 12
BorderSpacing.Bottom = 8
Caption = 'Show...'
ClientHeight = 83
ClientWidth = 214
ClientWidth = 198
TabOrder = 4
object UpperSpecChk: TCheckBox
AnchorSideLeft.Control = LevelOptns
@ -221,28 +221,28 @@ inherited XBarChartForm: TXBarChartForm
end
end
inherited SpecsSplitter: TSplitter
Left = 478
Height = 443
Left = 390
Height = 431
end
inherited PageControl: TPageControl
Left = 486
Height = 431
Width = 435
Left = 398
Height = 419
Width = 523
inherited ReportPage: TTabSheet
ClientHeight = 403
ClientWidth = 427
ClientHeight = 391
ClientWidth = 515
inherited Panel1: TPanel
Height = 363
Width = 415
ClientHeight = 359
ClientWidth = 411
inherited ReportMemo: TMemo
Height = 351
Width = 403
Width = 503
ClientHeight = 347
ClientWidth = 499
inherited ReportMemo: TMemo
Height = 339
Width = 491
end
end
inherited ReportToolBar: TToolBar
Width = 423
Width = 511
end
end
inherited ChartPage: TTabSheet

View File

@ -59,12 +59,15 @@ begin
VarList.Constraints.MinWidth := VarListLabel.Width;
SpecsPanel.Constraints.MinWidth := Max(
CloseBtn.Left + CloseBtn.Width - HelpBtn.Left + HelpBtn.BorderSpacing.Around,
LevelOptns.Width * 2 + VarList.BorderSpacing.Right + VarList.BorderSpacing.Left
LevelOptns.Width * 2 + VarList.BorderSpacing.Right //* 2 + MeasInBtn.Width
);
Constraints.MinHeight := LevelOptns.Top + LevelOptns.Height + LevelOptns.BorderSpacing.Bottom + ButtonPanel.Height;
LevelOptns.AnchorSideRight.Control := MeasEdit;
LevelOptns.AnchorSideRight.Side := asrBottom;
if Height < Constraints.MinHeight then
Height := 1; // enforce height autosizing
finally
EnableAutoSizing;
end;
@ -74,7 +77,6 @@ end;
procedure TXBarChartForm.Compute;
var
i, j: Integer;
sigma: Double;
upperSpec: Double = NaN;
lowerSpec: Double = NaN;
targetSpec: Double = NaN;
@ -83,12 +85,10 @@ var
means: DblDyneVec = nil;
stdDev: DblDyneVec = nil;
count: IntDyneVec = nil;
numGrps: Integer;
numGrps, grpIndex, totalNumCases, grpSize: Integer;
grp: String;
grpIndex: Integer;
totalNumCases: Integer;
X, Xsq: Double;
UCL, LCL, grandMean, grandSD, stdErrMean, C4Value: Double;
sigma, aveStdDev, UCL, LCL, grandMean, grandSD, SEMean, C4Value: Double;
lReport: TStrings;
begin
if GroupEdit.Text <> '' then
@ -126,11 +126,11 @@ begin
SetLength(means, numGrps);
SetLength(count, numGrps);
SetLength(stddev, numGrps);
stdErrMean := 0.0;
SEMean := 0.0;
grandMean := 0.0;
totalNumCases := 0;
// calculate group means, grand mean, group sd's, semeans
// calculate group means, grand mean, group sd's, seMean
for i := 1 to NoCases do
begin
if not GoodRecord(i, Length(ColNoSelected), ColNoSelected) then continue;
@ -151,30 +151,48 @@ begin
means[grpIndex] := means[grpIndex] + X;
stddev[grpIndex] := stddev[grpIndex] + Xsq;
grandMean := grandMean + X;
stdErrMean := stdErrMean + Xsq;
SEMean := SEMean + Xsq;
inc(totalNumCases);
end;
stdErrMean := stdErrMean - sqr(grandMean) / totalNumCases;
stdErrMean := sqrt(stderrMean / (totalNumCases - 1));
grandSD := stdErrMean;
stdErrMean := stdErrMean / sqrt(totalNumCases);
SEMean := SEMean - sqr(grandMean) / totalNumCases;
SEMean := sqrt(SEMean / (totalNumCases - 1));
grandSD := SEMean;
SEMean := SEMean / sqrt(totalNumCases);
grandMean := grandMean / totalNumCases;
if (GroupEdit.Text = '') then
begin
// Individuals chart
grpSize := 1;
SetLength(means, totalNumCases);
SetLength(stddev, totalNumCases);
Setlength(count, totalNumCases);
for i := 0 to totalNumCases-1 do
stddev[i] := stdErrMean;
C4Value := 1.0 / C4[totalNumCases-1];
UCL := grandMean + sigma * stdErrMean * C4Value;
LCL := grandMean - sigma * stdErrMean * C4Value;
stddev[i] := SEMean;
aveStdDev := NaN;
if totalNumCases <= 25 then
C4Value := C4[totalNumCases]
else
C4Value := 1.0;
UCL := grandMean + sigma * grandSD / C4Value;
LCL := grandMean - sigma * grandSD / C4Value;
end else
begin
// Grouped chart
// Check group size - it is assumed that all groups are equally sized
grpSize := count[0];
for i := 1 to numGrps-1 do
if count[i] <> grpSize then
begin
ErrorMsg('All groups must have the same size.');
exit;
end;
aveStdDev := aveStdDev + stdDev[i];
aveStdDev := 0;
for i := 0 to numGrps-1 do
begin
if count[i] = 0 then
@ -188,14 +206,18 @@ begin
else
begin
stddev[i] := stddev[i] - sqr(means[i]) / count[i];
stddev[i] := stddev[i] / (count[i] - 1);
stddev[i] := sqrt(stddev[i]);
stddev[i] := stddev[i] / (count[i] - 1); // Variance of group i
aveStdDev := aveStdDev + stdDev[i]; // Sum of variances
stddev[i] := sqrt(stddev[i]); // StdDev of group i
end;
means[i] := means[i] / count[i];
end;
end;
UCL := grandMean + sigma * stdErrMean;
LCL := grandMean - sigma * stdErrMean;
aveStdDev := sqrt(aveStdDev / (numGrps * grpSize));
UCL := grandMean + sigma * aveStdDev;
LCL := grandMean - sigma * aveStdDev;
// UCL := grandMean + sigma * SEMean; // old LazStats calculation -- does not agree with JMP software.
// LCL := grandMean - sigma * SEMean;
end;
// Print results
@ -203,11 +225,14 @@ begin
try
lReport.Add('X BAR CHART RESULTS');
lReport.Add('');
lReport.Add('Number of samples: %8d', [totalNumCases]);
lReport.Add('Number of values: %8d', [totalNumCases]);
lReport.Add('Number of groups: %8d', [numGrps]);
lReport.Add('Group size: %8d', [grpSize]);
lReport.Add('');
lReport.Add('Grand Mean: %8.3f', [grandMean]);
lReport.Add('Standard Deviation: %8.3f', [grandSD]);
lReport.Add('Standard Error of Mean: %8.3f', [stdErrMean]);
lReport.Add('');
lReport.Add('Standard Error of Mean: %8.3f', [SEMean]);
lReport.Add('Average Std Deviation: %8.3f', [aveStdDev]);
lReport.Add('Lower Control Limit: %8.3f', [LCL]);
lReport.Add('Upper Control Limit: %8.3f', [UCL]);
lReport.Add('');

View File

@ -24,6 +24,8 @@ object ChartFrame: TChartFrame
end
item
Grid.Color = clSilver
Intervals.MaxLength = 80
Intervals.MinLength = 30
Alignment = calBottom
Marks.LabelBrush.Style = bsClear
Minors = <>