2020-04-10 21:56:25 +00:00
|
|
|
// Sample file for testing: cansas.laz, use all variiables.
|
|
|
|
|
2020-11-15 23:31:39 +00:00
|
|
|
// WARNING: THE OUTPUT OF THIS FORM DOES NOT AGREE WITH THE SAME FORM OF
|
|
|
|
// OPENSTAT OR STATS4U
|
|
|
|
|
2020-03-30 18:01:44 +00:00
|
|
|
unit HierarchUnit;
|
|
|
|
|
|
|
|
{$mode objfpc}{$H+}
|
|
|
|
|
|
|
|
interface
|
|
|
|
|
|
|
|
uses
|
2020-11-16 10:25:30 +00:00
|
|
|
Classes, SysUtils, Forms, Controls, Graphics, StdCtrls, Buttons, ExtCtrls, ComCtrls,
|
2020-11-15 23:31:39 +00:00
|
|
|
MainUnit, Globals, MatrixLib, ReportFrameUnit, BasicStatsReportAndChartFormUnit;
|
2020-03-30 18:01:44 +00:00
|
|
|
|
|
|
|
type
|
|
|
|
|
2020-11-15 23:31:39 +00:00
|
|
|
{ THierarchForm }
|
2020-03-30 18:01:44 +00:00
|
|
|
|
2020-11-15 23:31:39 +00:00
|
|
|
THierarchForm = class(TBasicStatsReportAndChartForm)
|
2020-03-30 18:01:44 +00:00
|
|
|
MaxGrps: TEdit;
|
|
|
|
STDChk: TCheckBox;
|
|
|
|
ReplaceChk: TCheckBox;
|
|
|
|
StatsChk: TCheckBox;
|
|
|
|
PlotChk: TCheckBox;
|
|
|
|
MaxGrpsChk: TCheckBox;
|
|
|
|
MembersChk: TCheckBox;
|
2020-11-15 23:31:39 +00:00
|
|
|
StatsPage: TTabSheet;
|
2020-03-30 18:01:44 +00:00
|
|
|
VarChk: TCheckBox;
|
2020-11-15 23:31:39 +00:00
|
|
|
OptionsGroup: TGroupBox;
|
2020-03-30 18:01:44 +00:00
|
|
|
PredIn: TBitBtn;
|
|
|
|
PredOut: TBitBtn;
|
|
|
|
Label1: TLabel;
|
|
|
|
Label2: TLabel;
|
|
|
|
PredList: TListBox;
|
|
|
|
VarList: TListBox;
|
|
|
|
procedure PredInClick(Sender: TObject);
|
2020-11-15 23:31:39 +00:00
|
|
|
procedure PredListDblClick(Sender: TObject);
|
2020-03-30 18:01:44 +00:00
|
|
|
procedure PredOutClick(Sender: TObject);
|
2020-11-15 23:31:39 +00:00
|
|
|
procedure VarListDblClick(Sender: TObject);
|
2020-11-06 00:04:57 +00:00
|
|
|
procedure VarListSelectionChange(Sender: TObject; {%H-}User: boolean);
|
2020-03-30 18:01:44 +00:00
|
|
|
private
|
2020-11-15 23:31:39 +00:00
|
|
|
FStatsReportFrame: TReportFrame;
|
|
|
|
|
|
|
|
procedure Plot_GroupCount_Error(const AGrpCount, AError: DblDyneVec;
|
|
|
|
ADataCount: Integer);
|
|
|
|
|
|
|
|
procedure ShowDescriptiveStats(const AMeans, AVars, AStdDevs: DblDyneVec;
|
|
|
|
ANumCols, ANumCases: Integer; const AVarLabels: StrDyneVec);
|
|
|
|
|
|
|
|
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-15 23:31:39 +00:00
|
|
|
constructor Create(AOwner: TComponent); override;
|
|
|
|
procedure Reset; override;
|
|
|
|
|
2020-03-30 18:01:44 +00:00
|
|
|
end;
|
|
|
|
|
|
|
|
var
|
2020-11-15 23:31:39 +00:00
|
|
|
HierarchForm: THierarchForm;
|
|
|
|
|
2020-03-30 18:01:44 +00:00
|
|
|
|
|
|
|
implementation
|
|
|
|
|
2020-11-15 23:31:39 +00:00
|
|
|
{$R *.lfm}
|
|
|
|
|
2020-03-30 18:01:44 +00:00
|
|
|
uses
|
2020-11-15 23:31:39 +00:00
|
|
|
TAChartUtils, TACustomSeries,
|
2020-11-16 10:25:30 +00:00
|
|
|
Utils, GridProcs, DataProcs, ChartFrameUnit;
|
2020-03-30 18:01:44 +00:00
|
|
|
|
|
|
|
|
2020-11-15 23:31:39 +00:00
|
|
|
{ THierarchForm }
|
2020-03-30 18:01:44 +00:00
|
|
|
|
2020-11-15 23:31:39 +00:00
|
|
|
constructor THierarchForm.Create(AOwner: TComponent);
|
2020-03-30 18:01:44 +00:00
|
|
|
begin
|
2020-11-15 23:31:39 +00:00
|
|
|
inherited;
|
2020-03-30 18:01:44 +00:00
|
|
|
|
2020-11-15 23:31:39 +00:00
|
|
|
InitToolbar(FReportFrame.ReportToolbar, tpTop);
|
|
|
|
FReportFrame.ClearBorderSpacings;
|
2020-03-30 18:01:44 +00:00
|
|
|
|
2020-11-15 23:31:39 +00:00
|
|
|
FStatsReportFrame := TReportFrame.Create(self);
|
|
|
|
FStatsReportFrame.Parent := StatsPage;
|
|
|
|
FStatsReportFrame.Align := alClient;
|
|
|
|
StatsPage.PageIndex := 1;
|
2020-03-30 18:01:44 +00:00
|
|
|
|
2020-11-15 23:31:39 +00:00
|
|
|
{$IFDEF OLD_PLOTS}
|
2020-04-10 21:56:25 +00:00
|
|
|
if GraphFrm = nil then
|
|
|
|
Application.CreateForm(TGraphFrm, GraphFrm);
|
2020-11-15 23:31:39 +00:00
|
|
|
{$ENDIF}
|
|
|
|
|
|
|
|
PageControl.ActivePageIndex := 0;
|
2020-03-30 18:01:44 +00:00
|
|
|
end;
|
|
|
|
|
2020-11-15 23:31:39 +00:00
|
|
|
|
|
|
|
procedure THierarchForm.AdjustConstraints;
|
2020-03-30 18:01:44 +00:00
|
|
|
begin
|
2020-11-15 23:31:39 +00:00
|
|
|
inherited;
|
|
|
|
|
|
|
|
ParamsPanel.Constraints.MinWidth := 4*CloseBtn.Width + 3*CloseBtn.BorderSpacing.Left;
|
|
|
|
ParamsPanel.Constraints.MinHeight := PredOut.Top + PredOut.Height +
|
|
|
|
VarList.BorderSpacing.Bottom + OptionsGroup.Height +
|
|
|
|
ButtonBevel.Height + CloseBtn.Height;
|
2020-03-30 18:01:44 +00:00
|
|
|
end;
|
|
|
|
|
2020-11-15 23:31:39 +00:00
|
|
|
|
|
|
|
procedure THierarchForm.Compute;
|
2020-03-30 18:01:44 +00:00
|
|
|
label next1;
|
|
|
|
var
|
2020-11-15 23:31:39 +00:00
|
|
|
varLabels: StrDyneVec = nil;
|
|
|
|
rowLabels: StrDyneVec = nil;
|
|
|
|
w2: IntDyneVec = nil;
|
|
|
|
k4: IntDyneVec = nil;
|
|
|
|
k5: IntDyneVec = nil;
|
|
|
|
L1: IntDyneVec = nil;
|
|
|
|
ColSelected: IntDyneVec = nil;
|
|
|
|
W: DblDyneVec = nil;
|
|
|
|
XAxis: DblDyneVec = nil;
|
|
|
|
YAxis: DblDyneVec = nil;
|
|
|
|
means: DblDyneVec = nil;
|
|
|
|
variances: DblDyneVec = nil;
|
|
|
|
stddevs: DblDyneVec = nil;
|
|
|
|
Distance : DblDyneMat = nil;
|
2020-04-10 21:56:25 +00:00
|
|
|
i, j, k, k1, k3, L, w3, n3, n4, n5, M, col, count: integer;
|
|
|
|
GrpCnt, Nrows, Ncols, NoSelected: integer;
|
2020-11-15 23:31:39 +00:00
|
|
|
X, Y, d1, x1, MaxError: double;
|
2020-04-10 21:56:25 +00:00
|
|
|
lReport: TStrings;
|
2020-03-30 18:01:44 +00:00
|
|
|
begin
|
2020-04-10 21:56:25 +00:00
|
|
|
MaxError := 0.0;
|
|
|
|
GrpCnt := 0;
|
|
|
|
NoSelected := PredList.Items.Count;
|
|
|
|
if not VarChk.Checked then
|
|
|
|
begin
|
|
|
|
SetLength(w2,NoCases);
|
|
|
|
SetLength(k4,NoCases);
|
|
|
|
SetLength(k5,NoCases);
|
|
|
|
SetLength(L1,NoCases);
|
|
|
|
SetLength(W,NoSelected);
|
|
|
|
SetLength(XAxis,NoCases);
|
|
|
|
SetLength(YAxis,NoCases);
|
|
|
|
SetLength(means,NoSelected);
|
|
|
|
SetLength(variances,NoSelected);
|
|
|
|
SetLength(stddevs,NoSelected);
|
|
|
|
SetLength(Distance,NoCases,NoCases);
|
|
|
|
SetLength(varlabels,NoSelected);
|
|
|
|
SetLength(rowlabels,NoCases);
|
|
|
|
SetLength(ColSelected,NoSelected);
|
2020-11-15 23:31:39 +00:00
|
|
|
nCols := NoSelected;
|
|
|
|
nRows := NoCases;
|
|
|
|
|
2020-11-16 10:25:30 +00:00
|
|
|
for i := 0 to nCols-1 do // nCols = NoSelected!
|
|
|
|
begin
|
|
|
|
varLabels[i] := PredList.Items[i];
|
|
|
|
colSelected[i] := GetVariableIndex(OS3MainFrm.DataGrid, varLabels[i]);
|
|
|
|
end;
|
|
|
|
{
|
2020-11-15 23:31:39 +00:00
|
|
|
for i := 0 to nCols - 1 do
|
2020-04-10 21:56:25 +00:00
|
|
|
begin
|
|
|
|
cellstring := PredList.Items.Strings[i];
|
|
|
|
for j := 1 to NoVariables do
|
|
|
|
begin
|
|
|
|
if (cellstring = OS3MainFrm.DataGrid.Cells[j,0]) then
|
|
|
|
begin
|
|
|
|
varlabels[i] := cellstring;
|
|
|
|
ColSelected[i] := j;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
end;
|
2020-11-16 10:25:30 +00:00
|
|
|
}
|
|
|
|
for i := 0 to NoCases-1 do rowLabels[i] := OS3MainFrm.DataGrid.Cells[0, i+1]; //IntToStr(i);
|
2020-04-10 21:56:25 +00:00
|
|
|
end else
|
|
|
|
begin
|
|
|
|
SetLength(w2,NoSelected);
|
|
|
|
SetLength(k4,NoSelected);
|
|
|
|
SetLength(k5,NoSelected);
|
|
|
|
SetLength(L1,NoSelected);
|
|
|
|
SetLength(W,NoCases);
|
|
|
|
SetLength(XAxis,NoSelected);
|
|
|
|
SetLength(YAxis,NoSelected);
|
|
|
|
SetLength(means,NoCases);
|
|
|
|
SetLength(variances,NoCases);
|
|
|
|
SetLength(stddevs,NoCases);
|
|
|
|
SetLength(Distance,NoSelected,NoCases);
|
|
|
|
SetLength(varlabels,NoCases);
|
|
|
|
SetLength(rowlabels,NoSelected);
|
|
|
|
SetLength(ColSelected,NoSelected);
|
2020-11-16 10:25:30 +00:00
|
|
|
nCols := NoCases;
|
|
|
|
nRows := NoSelected;
|
2020-04-10 21:56:25 +00:00
|
|
|
//Get labels of selected variables
|
2020-11-16 10:25:30 +00:00
|
|
|
for i := 0 to nRows - 1 do // nRows = NoSelected!
|
|
|
|
begin
|
|
|
|
rowLabels[i] := PredList.Items[i];
|
|
|
|
colSelected[i] := GetVariableIndex(OS3MainFrm.DataGrid, rowLabels[i]);
|
|
|
|
end;
|
|
|
|
{
|
2020-11-15 23:31:39 +00:00
|
|
|
for i := 0 to nRows - 1 do
|
2020-04-10 21:56:25 +00:00
|
|
|
begin
|
|
|
|
cellstring := PredList.Items.Strings[i];
|
|
|
|
for j := 1 to NoVariables do
|
|
|
|
begin
|
|
|
|
if (cellstring = OS3MainFrm.DataGrid.Cells[j,0]) then
|
|
|
|
begin
|
|
|
|
ColSelected[i] := j;
|
|
|
|
rowlabels[i] := cellstring;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
end;
|
2020-11-16 10:25:30 +00:00
|
|
|
}
|
2020-04-10 21:56:25 +00:00
|
|
|
for i := 0 to NoCases-1 do
|
2020-11-16 10:25:30 +00:00
|
|
|
varlabels[i] := OS3MainFrm.DataGrid.Cells[0, i+1]; //IntToStr(i);
|
2020-04-10 21:56:25 +00:00
|
|
|
end;
|
|
|
|
|
2020-11-15 23:31:39 +00:00
|
|
|
if MaxGrpsChk.Checked then
|
|
|
|
k1 := StrToInt(MaxGrps.Text);
|
|
|
|
|
|
|
|
if MembersChk.Checked then
|
|
|
|
k3 := 1
|
|
|
|
else
|
|
|
|
k3 := 0;
|
2020-03-30 18:01:44 +00:00
|
|
|
|
2020-11-15 23:31:39 +00:00
|
|
|
for j := 0 to nCols-1 do
|
2020-03-30 18:01:44 +00:00
|
|
|
begin
|
|
|
|
means[j] := 0.0;
|
|
|
|
variances[j] := 0.0;
|
|
|
|
stddevs[j] := 0.0;
|
|
|
|
end;
|
|
|
|
|
2020-11-15 23:31:39 +00:00
|
|
|
if not VarChk.Checked then
|
2020-03-30 18:01:44 +00:00
|
|
|
begin
|
2020-04-10 21:56:25 +00:00
|
|
|
// Get labels of rows
|
2020-03-30 18:01:44 +00:00
|
|
|
// for i := 1 to Nrows do rowlabels[i-1] := MainFrm.Grid.Cells[0,i];
|
|
|
|
|
2020-04-10 21:56:25 +00:00
|
|
|
// Get data into the distance matrix
|
|
|
|
count := 0;
|
2020-11-15 23:31:39 +00:00
|
|
|
for i := 1 to nRows do
|
2020-04-10 21:56:25 +00:00
|
|
|
begin
|
|
|
|
if (not GoodRecord(i,NoSelected,ColSelected)) then continue;
|
|
|
|
count := count + 1;
|
|
|
|
for j := 1 to Ncols do
|
|
|
|
begin
|
|
|
|
col := ColSelected[j-1];
|
|
|
|
X := StrToFloat(Trim(OS3MainFrm.DataGrid.Cells[col,i]));
|
|
|
|
means[j-1] := means[j-1] + X;
|
|
|
|
variances[j-1] := variances[j-1] + (X * X);
|
|
|
|
Distance[i-1,j-1] := X;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
end else
|
|
|
|
begin // cluster variables
|
|
|
|
// Get labels of columns
|
2020-03-30 18:01:44 +00:00
|
|
|
// for i := 1 to Nrows do rowlabels[i-1] := MainFrm.Grid.Cells[i,0];
|
|
|
|
|
2020-04-10 21:56:25 +00:00
|
|
|
// Get data into the distance matrix
|
|
|
|
count := 0;
|
2020-11-15 23:31:39 +00:00
|
|
|
for i := 0 to nRows-1 do // actually grid column in this case
|
2020-04-10 21:56:25 +00:00
|
|
|
begin
|
|
|
|
// if (not GoodRecord(i,NoSelected,ColSelected)) then continue;
|
|
|
|
count := count + 1;
|
2020-11-15 23:31:39 +00:00
|
|
|
for j := 0 to Ncols-1 do // actually grid rows in this case
|
2020-04-10 21:56:25 +00:00
|
|
|
begin
|
|
|
|
// if (not GoodRecord(j,NoSelected,ColSelected)) then continue;
|
2020-11-15 23:31:39 +00:00
|
|
|
col := ColSelected[i];
|
|
|
|
X := StrToFloat(Trim(OS3MainFrm.DataGrid.Cells[col, j+1]));
|
|
|
|
means[j] := means[j] + X;
|
|
|
|
variances[j] := variances[j] + (X * X);
|
|
|
|
Distance[i, j] := X;
|
2020-04-10 21:56:25 +00:00
|
|
|
end;
|
|
|
|
end;
|
2020-03-30 18:01:44 +00:00
|
|
|
end;
|
|
|
|
|
|
|
|
// Calculate means and standard deviations of variables
|
2020-11-15 23:31:39 +00:00
|
|
|
for j := 0 to nCols-1 do
|
2020-03-30 18:01:44 +00:00
|
|
|
begin
|
2020-11-15 23:31:39 +00:00
|
|
|
variances[j] := (variances[j] - sqr(means[j]) / count) / (count - 1);
|
2020-03-30 18:01:44 +00:00
|
|
|
stddevs[j] := sqrt(variances[j]);
|
|
|
|
means[j] := means[j] / count;
|
|
|
|
end;
|
|
|
|
|
2020-11-15 23:31:39 +00:00
|
|
|
// Report descriptive statistics
|
|
|
|
if StatsChk.Checked then
|
|
|
|
begin
|
|
|
|
StatsPage.TabVisible := true;
|
|
|
|
ShowDescriptiveStats(means, variances, stddevs, nCols, count, varlabels);
|
|
|
|
end else
|
|
|
|
StatsPage.TabVisible := false;
|
|
|
|
|
2020-03-30 18:01:44 +00:00
|
|
|
// Ready the output form
|
2020-04-10 21:56:25 +00:00
|
|
|
lReport := TStringList.Create;
|
|
|
|
try
|
|
|
|
lReport.Add('HIERARCHICAL CLUSTER ANALYSIS');
|
|
|
|
lReport.Add('');
|
|
|
|
lReport.Add('Number of objects to cluster: %d on %d variables.', [Nrows, Ncols]);
|
|
|
|
lReport.Add('');
|
|
|
|
|
|
|
|
// Standardize the distance scores if elected
|
|
|
|
if StdChk.Checked then
|
|
|
|
begin
|
2020-11-15 23:31:39 +00:00
|
|
|
for j := 0 to nCols-1 do
|
|
|
|
for i := 0 to nRows-1 do
|
2020-04-10 21:56:25 +00:00
|
|
|
Distance[i,j] := (Distance[i,j] - means[j]) / stddevs[j];
|
|
|
|
end;
|
2020-03-30 18:01:44 +00:00
|
|
|
|
2020-04-10 21:56:25 +00:00
|
|
|
// replace original values in grid with z scores if elected
|
|
|
|
if ReplaceChk.Checked then
|
|
|
|
begin
|
2020-11-15 23:31:39 +00:00
|
|
|
for i := 0 to nRows-1 do
|
2020-03-30 18:01:44 +00:00
|
|
|
begin
|
2020-11-15 23:31:39 +00:00
|
|
|
if not GoodRecord(i+1, NoSelected, ColSelected) then continue;
|
|
|
|
for j := 0 to nCols-1 do
|
2020-03-30 18:01:44 +00:00
|
|
|
begin
|
2020-11-15 23:31:39 +00:00
|
|
|
col := ColSelected[j];
|
|
|
|
OS3MainFrm.DataGrid.Cells[col, i+1] := Format('%6.4f', [Distance[i, j]]);
|
2020-03-30 18:01:44 +00:00
|
|
|
end;
|
|
|
|
end;
|
2020-04-10 21:56:25 +00:00
|
|
|
end;
|
2020-03-30 18:01:44 +00:00
|
|
|
|
2020-04-10 21:56:25 +00:00
|
|
|
// Convert data matrix to initial matrix of error potentials
|
|
|
|
for i := 1 to Nrows do
|
2020-03-30 18:01:44 +00:00
|
|
|
begin
|
2020-04-10 21:56:25 +00:00
|
|
|
// if (not GoodRecord(i,NoSelected,ColSelected)) then continue;
|
|
|
|
for j := 1 to Ncols do
|
|
|
|
W[j-1] := Distance[i-1,j-1];
|
|
|
|
for j := i to Nrows do
|
|
|
|
begin
|
2020-03-30 18:01:44 +00:00
|
|
|
// if (not GoodRecord(i,NoSelected,ColSelected)) then continue;
|
2020-04-10 21:56:25 +00:00
|
|
|
Distance[i-1,j-1] := 0.0;
|
|
|
|
for k := 1 to Ncols do
|
|
|
|
Distance[i-1,j-1] := Distance[i-1,j-1] + (Distance[j-1,k-1] - W[k-1]) * (Distance[j-1,k-1] - W[k-1]);
|
|
|
|
Distance[i-1,j-1] := Distance[i-1,j-1] / 2.0;
|
|
|
|
end;
|
2020-03-30 18:01:44 +00:00
|
|
|
end;
|
2020-04-10 21:56:25 +00:00
|
|
|
for i := 1 to Nrows do
|
|
|
|
for j := i to Nrows do Distance[j-1,i-1] := 0.0;
|
2020-03-30 18:01:44 +00:00
|
|
|
|
2020-04-10 21:56:25 +00:00
|
|
|
// Now, group the cases for maximum groups down
|
|
|
|
if MaxGrpsChk.Checked then
|
2020-11-15 23:31:39 +00:00
|
|
|
k1 := StrToInt(MaxGrps.Text)
|
|
|
|
else
|
2020-04-10 21:56:25 +00:00
|
|
|
k1 := 2;
|
2020-11-15 23:31:39 +00:00
|
|
|
n3 := nRows;
|
2020-03-30 18:01:44 +00:00
|
|
|
|
2020-04-10 21:56:25 +00:00
|
|
|
// Initialize group membership and group-n vectors
|
|
|
|
for i := 0 to Nrows-1 do
|
|
|
|
begin
|
|
|
|
k4[i] := i+1;
|
|
|
|
k5[i] := i+1;
|
|
|
|
w2[i] := 1;
|
|
|
|
end;
|
|
|
|
|
|
|
|
// Locate optimal combination, if more than 2 groups remain
|
2020-03-30 18:01:44 +00:00
|
|
|
|
2020-11-15 23:31:39 +00:00
|
|
|
|
2020-03-30 18:01:44 +00:00
|
|
|
next1:
|
2020-04-10 21:56:25 +00:00
|
|
|
|
|
|
|
n3 := n3 - 1;
|
|
|
|
if (n3 > 1) then
|
2020-03-30 18:01:44 +00:00
|
|
|
begin
|
2020-11-15 23:31:39 +00:00
|
|
|
|
|
|
|
//repeat;
|
|
|
|
// n3 := n3 - 1;
|
2020-04-10 21:56:25 +00:00
|
|
|
x1 := 100000000000.0;
|
|
|
|
for i := 1 to Nrows do
|
2020-03-30 18:01:44 +00:00
|
|
|
begin
|
2020-04-10 21:56:25 +00:00
|
|
|
if (k5[i-1] = i) then
|
2020-03-30 18:01:44 +00:00
|
|
|
begin
|
2020-04-10 21:56:25 +00:00
|
|
|
for j := i to Nrows do
|
2020-03-30 18:01:44 +00:00
|
|
|
begin
|
2020-04-10 21:56:25 +00:00
|
|
|
if ((i <> j) and (k5[j-1] = j)) then
|
2020-03-30 18:01:44 +00:00
|
|
|
begin
|
2020-04-10 21:56:25 +00:00
|
|
|
d1 := Distance[i-1,j-1] - Distance[i-1,i-1] - Distance[j-1,j-1];
|
|
|
|
if (d1 < x1) then
|
|
|
|
begin
|
|
|
|
x1 := d1;
|
|
|
|
L := i;
|
|
|
|
M := j;
|
|
|
|
end; // end if
|
2020-03-30 18:01:44 +00:00
|
|
|
end; // end if
|
2020-04-10 21:56:25 +00:00
|
|
|
end; // next j
|
|
|
|
end; // end if
|
|
|
|
end; // next i
|
|
|
|
n4 := w2[L-1];
|
|
|
|
n5 := w2[M-1];
|
|
|
|
|
2020-11-15 23:31:39 +00:00
|
|
|
XAxis[GrpCnt] := n3;
|
|
|
|
YAxis[GrpCnt] := x1;
|
2020-04-10 21:56:25 +00:00
|
|
|
GrpCnt := GrpCnt + 1;
|
2020-11-15 23:31:39 +00:00
|
|
|
|
2020-04-10 21:56:25 +00:00
|
|
|
if (x1 > MaxError) then MaxError := x1;
|
|
|
|
lReport.Add('%2.d groups after combining group %2.d (n = %2.d) and group %2.d (n = %2.d), error: %7.3f', [n3, L, n4, M, n5, x1]);
|
|
|
|
|
|
|
|
w3 := w2[L-1] + w2[M-1];
|
|
|
|
x1 := Distance[L-1,M-1] * w3;
|
|
|
|
Y := Distance[L-1,L-1] * w2[L-1] + Distance[M-1,M-1] * w2[M-1];
|
|
|
|
Distance[L-1,L-1] := Distance[L-1,M-1];
|
|
|
|
for i := 1 to Nrows do
|
|
|
|
if (k5[i-1] = M) then k5[i-1] := L;
|
|
|
|
for i := 1 to Nrows do
|
2020-03-30 18:01:44 +00:00
|
|
|
begin
|
2020-04-10 21:56:25 +00:00
|
|
|
if ((i <> L) and (k5[i-1] = i)) then
|
2020-03-30 18:01:44 +00:00
|
|
|
begin
|
2020-04-10 21:56:25 +00:00
|
|
|
if (i <= L) then
|
|
|
|
begin
|
|
|
|
Distance[i-1,L-1] := Distance[i-1,L-1] * (w2[i-1] + w2[L-1])
|
|
|
|
+ Distance[i-1,M-1] * (w2[i-1] + w2[M-1])
|
|
|
|
+ x1 - Y - Distance[i-1,i-1] * w2[i-1];
|
|
|
|
Distance[i-1,L-1] := Distance[i-1,L-1] / (w2[i-1] + w3);
|
|
|
|
end else
|
|
|
|
begin
|
|
|
|
Distance[L-1,i-1] := Distance[L-1,i-1] * (w2[L-1] + w2[i-1])
|
|
|
|
+ (Distance[M-1,i-1] + Distance[i-1,M-1]) * (w2[M-1] + w2[i-1]);
|
|
|
|
Distance[L-1,i-1] := (Distance[L-1,i-1]+ x1 - Y
|
|
|
|
- Distance[i-1,i-1] * w2[i-1]) / (w2[i-1] + w3);
|
|
|
|
end;
|
2020-03-30 18:01:44 +00:00
|
|
|
end;
|
|
|
|
end;
|
2020-04-10 21:56:25 +00:00
|
|
|
w2[L-1] := w3;
|
2020-11-15 23:31:39 +00:00
|
|
|
if (n3 > k1) then
|
|
|
|
//Continue;
|
|
|
|
goto next1;
|
2020-03-30 18:01:44 +00:00
|
|
|
|
2020-11-15 23:31:39 +00:00
|
|
|
// Print group memberships of all objects, if optioned
|
2020-11-16 10:25:30 +00:00
|
|
|
if MembersChk.Checked then
|
2020-03-30 18:01:44 +00:00
|
|
|
begin
|
2020-11-16 10:25:30 +00:00
|
|
|
lReport.Add('');
|
|
|
|
for i := 1 to nRows do
|
2020-03-30 18:01:44 +00:00
|
|
|
begin
|
2020-11-16 10:25:30 +00:00
|
|
|
if (k5[i-1] = i) then
|
2020-03-30 18:01:44 +00:00
|
|
|
begin
|
2020-11-16 10:25:30 +00:00
|
|
|
L := 0;
|
|
|
|
for j := 1 to Nrows do
|
2020-04-10 21:56:25 +00:00
|
|
|
begin
|
2020-11-16 10:25:30 +00:00
|
|
|
if (k5[j-1] = i) then
|
|
|
|
begin
|
|
|
|
L := L + 1;
|
|
|
|
L1[L-1] := k4[j-1];
|
|
|
|
if k3 = 1 then L1[L-1] := j;
|
|
|
|
end;
|
2020-04-10 21:56:25 +00:00
|
|
|
end;
|
2020-11-16 10:25:30 +00:00
|
|
|
if k3 = 1 then
|
|
|
|
begin
|
|
|
|
lReport.Add('Group %d (n = %d)', [i, L]);
|
|
|
|
for j := 1 to L do
|
|
|
|
lReport.Add(' Object: %s', [rowLabels[L1[j-1]-1]]);
|
|
|
|
end; // end if
|
2020-04-10 21:56:25 +00:00
|
|
|
end; // end if
|
2020-11-16 10:25:30 +00:00
|
|
|
end; // next i
|
|
|
|
lReport.Add('');
|
|
|
|
end;
|
2020-04-10 21:56:25 +00:00
|
|
|
goto next1;
|
2020-11-15 23:31:39 +00:00
|
|
|
//until n3 = 2;
|
|
|
|
end; // end if
|
2020-03-30 18:01:44 +00:00
|
|
|
|
2020-11-15 23:31:39 +00:00
|
|
|
FReportFrame.DisplayReport(lReport);
|
2020-04-10 21:56:25 +00:00
|
|
|
|
|
|
|
if PlotChk.Checked then
|
|
|
|
begin
|
2020-11-15 23:31:39 +00:00
|
|
|
ChartPage.TabVisible := true;
|
|
|
|
Plot_GroupCount_Error(XAxis, YAxis, GrpCnt);
|
|
|
|
end else
|
|
|
|
ChartPage.TabVisible := false;
|
2020-03-30 18:01:44 +00:00
|
|
|
|
2020-04-10 21:56:25 +00:00
|
|
|
finally
|
|
|
|
lReport.Free;
|
|
|
|
end;
|
2020-03-30 18:01:44 +00:00
|
|
|
end;
|
|
|
|
|
2020-11-15 23:31:39 +00:00
|
|
|
|
|
|
|
procedure THierarchForm.Plot_GroupCount_Error(const AGrpCount, AError: DblDyneVec;
|
|
|
|
ADataCount: Integer);
|
|
|
|
var
|
|
|
|
ser: TChartSeries;
|
|
|
|
i: Integer;
|
|
|
|
begin
|
|
|
|
FChartFrame.Clear;
|
|
|
|
FChartFrame.SetTitle('Number of Groups vs. Grouping Error');
|
|
|
|
FChartFrame.SetXTitle('Number of Groups');
|
|
|
|
FChartFrame.SetYTitle('Grouping Error');
|
|
|
|
|
|
|
|
ser := FChartFrame.PlotXY(ptSymbols, nil, nil, nil, nil, '', DATA_COLORS[0]);
|
|
|
|
for i := 0 to ADataCount-1 do
|
|
|
|
ser.AddXY(i, AError[i], Format('%.0f', [AGrpCount[i]]));
|
|
|
|
|
|
|
|
FChartFrame.Chart.BottomAxis.Marks.Source := ser.Source;
|
|
|
|
FChartFrame.Chart.BottomAxis.Marks.Style := smsLabel;
|
|
|
|
FChartFrame.Chart.Legend.Visible := false;
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
procedure THierarchForm.PredInClick(Sender: TObject);
|
2020-04-10 21:56:25 +00:00
|
|
|
var
|
|
|
|
i: integer;
|
2020-03-30 18:01:44 +00:00
|
|
|
begin
|
2020-04-10 21:56:25 +00:00
|
|
|
i := 0;
|
|
|
|
while i < VarList.Items.Count do
|
|
|
|
begin
|
|
|
|
if VarList.Selected[i] then
|
|
|
|
begin
|
|
|
|
PredList.Items.Add(VarList.Items[i]);
|
|
|
|
VarList.Items.Delete(i);
|
|
|
|
i := 0;
|
|
|
|
end else
|
|
|
|
i := i + 1;
|
|
|
|
end;
|
|
|
|
UpdateBtnStates;
|
2020-03-30 18:01:44 +00:00
|
|
|
end;
|
|
|
|
|
2020-11-15 23:31:39 +00:00
|
|
|
|
|
|
|
procedure THierarchForm.PredListDblClick(Sender: TObject);
|
|
|
|
var
|
|
|
|
index: Integer;
|
|
|
|
begin
|
|
|
|
index := PredList.ItemIndex;
|
|
|
|
if index > -1 then
|
|
|
|
begin
|
|
|
|
VarList.Items.Add(PredList.Items[index]);
|
|
|
|
PredList.Items.Delete(index);
|
|
|
|
UpdateBtnStates;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
procedure THierarchForm.PredOutClick(Sender: TObject);
|
2020-04-10 21:56:25 +00:00
|
|
|
var
|
|
|
|
i: integer;
|
|
|
|
begin
|
|
|
|
i := 0;
|
|
|
|
while i < PredList.Items.Count do
|
|
|
|
begin
|
|
|
|
if PredList.Selected[i] then
|
|
|
|
begin
|
|
|
|
VarList.Items.Add(PredList.Items[i]);
|
|
|
|
PredList.Items.Delete(i);
|
|
|
|
i := 0;
|
|
|
|
end else
|
|
|
|
i := i + 1;
|
|
|
|
end;
|
|
|
|
UpdateBtnStates;
|
|
|
|
end;
|
|
|
|
|
2020-11-15 23:31:39 +00:00
|
|
|
|
|
|
|
procedure THierarchForm.Reset;
|
|
|
|
var
|
|
|
|
i: integer;
|
|
|
|
begin
|
|
|
|
inherited;
|
|
|
|
|
|
|
|
if FStatsReportFrame <> nil then
|
|
|
|
FStatsReportFrame.Clear;
|
|
|
|
|
|
|
|
VarList.Clear;
|
|
|
|
for i := 1 to NoVariables do
|
|
|
|
VarList.Items.Add(OS3MainFrm.DataGrid.Cells[i,0]);
|
|
|
|
PredList.Clear;
|
|
|
|
|
|
|
|
StdChk.Checked := false;
|
|
|
|
ReplaceChk.Checked := false;
|
|
|
|
StatsChk.Checked := false;
|
|
|
|
PlotChk.Checked := false;
|
|
|
|
MaxGrpsChk.Checked := false;
|
|
|
|
VarChk.Checked := false;
|
|
|
|
|
|
|
|
MaxGrps.Clear;
|
|
|
|
|
|
|
|
UpdateBtnStates;
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
procedure THierarchForm.ShowDescriptiveStats(const AMeans, AVars, AStdDevs: DblDyneVec;
|
|
|
|
ANumCols, ANumCases: Integer; const AVarLabels: StrDyneVec);
|
|
|
|
var
|
|
|
|
lReport: TStrings;
|
|
|
|
begin
|
|
|
|
lReport := TStringList.Create;
|
|
|
|
try
|
|
|
|
DynVectorPrint(AMeans, ANumCols, 'Variable Means', AVarLabels, ANumCases, lReport);
|
|
|
|
|
|
|
|
lReport.Add(DIVIDER_SMALL_AUTO);
|
|
|
|
lReport.Add('');
|
|
|
|
|
|
|
|
DynVectorPrint(AVars, ANumCols, 'Variable Variances', AVarLabels, ANumCases, lReport);
|
|
|
|
|
|
|
|
lReport.Add(DIVIDER_SMALL_AUTO);
|
|
|
|
lReport.Add('');
|
|
|
|
|
|
|
|
DynVectorPrint(AStdDevs, ANumCols, 'Variable Standard Deviations', AVarLabels, ANumCases, lReport);
|
|
|
|
|
|
|
|
FStatsReportFrame.DisplayReport(lReport);
|
|
|
|
finally
|
|
|
|
lReport.Free;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
procedure THierarchForm.UpdateBtnStates;
|
2020-04-10 21:56:25 +00:00
|
|
|
begin
|
2020-11-15 23:31:39 +00:00
|
|
|
inherited;
|
|
|
|
|
|
|
|
if FStatsReportFrame <> nil then
|
|
|
|
FStatsReportFrame.UpdateBtnStates;
|
|
|
|
|
2020-04-10 21:56:25 +00:00
|
|
|
PredIn.Enabled := AnySelected(VarList);
|
|
|
|
PredOut.Enabled := AnySelected(PredList);
|
|
|
|
end;
|
|
|
|
|
2020-11-15 23:31:39 +00:00
|
|
|
|
|
|
|
function THierarchForm.Validate(out AMsg: String; out AControl: TWincontrol): Boolean;
|
|
|
|
var
|
|
|
|
n: Integer;
|
|
|
|
begin
|
|
|
|
Result := false;
|
|
|
|
|
|
|
|
if PredList.Items.Count = 0 then
|
|
|
|
begin
|
|
|
|
AMsg := 'No Predictor Variables selected.';
|
|
|
|
AControl := VarList;
|
|
|
|
exit;
|
|
|
|
end;
|
|
|
|
|
|
|
|
if MaxGrpsChk.Checked then
|
|
|
|
begin
|
|
|
|
if MaxGrps.Text = '' then
|
|
|
|
begin
|
|
|
|
AMsg := 'Maximum number of groups not specified.';
|
|
|
|
AControl := MaxGrps;
|
|
|
|
exit;
|
|
|
|
end;
|
|
|
|
if not TryStrToInt(MaxGrps.Text, n) or (n < 1) then
|
|
|
|
begin
|
|
|
|
AMsg := 'No valid number of groups given.';
|
|
|
|
AControl := MaxGrps;
|
|
|
|
exit;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
Result := true;
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
procedure THierarchForm.VarListDblClick(Sender: TObject);
|
|
|
|
var
|
|
|
|
index: Integer;
|
|
|
|
begin
|
|
|
|
index := VarList.ItemIndex;
|
|
|
|
if index > -1 then
|
|
|
|
begin
|
|
|
|
PredList.Items.Add(VarList.Items[index]);
|
|
|
|
VarList.Items.Delete(index);
|
|
|
|
UpdateBtnStates;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
procedure THierarchForm.VarListSelectionChange(Sender: TObject; User: boolean);
|
2020-03-30 18:01:44 +00:00
|
|
|
begin
|
2020-04-10 21:56:25 +00:00
|
|
|
UpdateBtnStates;
|
2020-03-30 18:01:44 +00:00
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
end.
|
|
|
|
|