LazStats: Fix writing data to grid in ChiSqrUnit. Fix processing of Frequency data in ChiSqrUnit.

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@7807 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz
2020-10-26 10:56:48 +00:00
parent 01c3b379c0
commit e8845a74d3
4 changed files with 237 additions and 162 deletions

View File

@ -80,7 +80,7 @@ inherited ChiSqrFrm: TChiSqrFrm
Caption = 'Available Variables'
ParentColor = False
end
object Label2: TLabel[7]
object RowLabel: TLabel[7]
AnchorSideLeft.Control = RowEdit
AnchorSideBottom.Control = RowEdit
Left = 233
@ -92,7 +92,7 @@ inherited ChiSqrFrm: TChiSqrFrm
Caption = 'Row Variable'
ParentColor = False
end
object Label3: TLabel[8]
object ColLabel: TLabel[8]
AnchorSideLeft.Control = ColEdit
AnchorSideBottom.Control = ColEdit
Left = 233
@ -104,7 +104,7 @@ inherited ChiSqrFrm: TChiSqrFrm
Caption = 'Column Variable'
ParentColor = False
end
object AnalyzeLabel: TLabel[9]
object DepLabel: TLabel[9]
AnchorSideLeft.Control = DepEdit
AnchorSideBottom.Control = DepEdit
Left = 233
@ -382,7 +382,7 @@ inherited ChiSqrFrm: TChiSqrFrm
Height = 19
Top = 46
Width = 178
Caption = 'Save a File of Frequency Data'
Caption = 'Write Frequency Data to Grid'
TabOrder = 5
end
end

View File

@ -7,7 +7,7 @@ interface
uses
Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs,
ExtCtrls, StdCtrls, Buttons, ComCtrls,
MainUnit, FunctionsLib, GraphLib, Globals, MatrixLib, DataProcs,
MainUnit, FunctionsLib, GraphLib, Globals, MatrixLib,
DictionaryUnit, ReportFrameUnit, BasicStatsReportFormUnit;
type
@ -40,9 +40,9 @@ type
DepEdit: TEdit;
InputGrp: TRadioGroup;
Label1: TLabel;
Label2: TLabel;
Label3: TLabel;
AnalyzeLabel: TLabel;
RowLabel: TLabel;
ColLabel: TLabel;
DepLabel: TLabel;
VarList: TListBox;
procedure ColInClick(Sender: TObject);
procedure ColOutClick(Sender: TObject);
@ -52,7 +52,7 @@ type
procedure RowInClick(Sender: TObject);
procedure RowOutClick(Sender: TObject);
procedure VarListDblClick(Sender: TObject);
procedure VarListSelectionChange(Sender: TObject; User: boolean);
procedure VarListSelectionChange(Sender: TObject; {%H-}User: boolean);
private
FFrequenciesReportFrame: TReportFrame;
@ -67,6 +67,8 @@ type
function CalcPearsonR(const AFrequencies: IntDyneMat): Double;
procedure FrequenciesToGrid(const AFrequencies: IntDyneMat);
procedure GetExpectedAndCellChiSqr(const AFrequencies: IntDyneMat;
out AExpected, ACellChiSqr: DblDyneMat;
out AChiSqr: Double);
@ -88,6 +90,15 @@ type
procedure GetTotalProportions(const AFrequencies: IntDyneMat;
out AProportions: DblDyneMat);
procedure ProcessAndReportCellChiSqr(const ACellChiSqr: DblDyneMat;
const ARowLabels, AColLabels: StrDyneVec; ANumCases: Integer);
procedure ProcessAndReportFrequencies(const AFrequencies: IntDyneMat;
const AExpected: DblDyneMat; const ARowLabels, AColLabels: StrDyneVec);
procedure ProcessAndReportProportions(const AFrequencies: IntDyneMat;
const ARowLabels, AColLabels: StrDyneVec);
protected
procedure AdjustConstraints; override;
procedure Compute; override;
@ -272,7 +283,6 @@ procedure TChiSqrFrm.Compute;
var
ColNoSelected: IntDyneVec = nil;
Freq: IntDyneMat = nil;
Prop: DblDyneMat = nil;
Expected: DblDyneMat = nil;
CellChi: DblDyneMat = nil;
RowLabels: StrDyneVec = nil;
@ -282,7 +292,6 @@ var
i, j, rowNo, colNo, depNo: integer;
Row, Col, df: integer;
ChiSquare, probChi, phi: double;
title : string;
AdjChiSqr, AdjProbChi, pearsonr, G, likelihood, MantelHaenszel, prob: double;
CoefCont, CramerV: double;
lReport: TStrings;
@ -308,8 +317,9 @@ begin
// Calculate expected values and cell chi-squares
GetExpectedAndCellChiSqr(Freq, Expected, CellChi, ChiSquare);
ProbChi := 1.0 - ChiSquaredProb(ChiSquare, df); // prob. larger chi
ProbChi := 1.0 - ChiSquaredProb(ChiSquare, df); // prob. > chi
// Yates correction
yates := YatesChk.Checked and (nRows = 2) and (nCols = 2);
if yates then begin
GetYatesCorrection(Freq, AdjChiSqr);
@ -326,76 +336,9 @@ begin
for j := 1 to NCols do ColLabels[j-1] := Format('Col.%d', [j]);
ColLabels[NCols] := 'Total';
// Print results to output frames
// Print main results to report frame
lReport := TStringList.Create;
try
// print frequencies tables requested by user
if ObsChk.Checked or ExpChk.Checked then
begin
FrequenciesPage.TabVisible := true;
lReport.Add('CHI-SQUARE ANALYSIS RESULTS');
if ObsChk.Checked then
begin
IntArrayPrint(Freq, NRows+1, NCols+1, 'Rows', RowLabels, ColLabels, 'OBSERVED FREQUENCIES', lReport);
lReport.Add(DIVIDER_SMALL_AUTO);
lReport.Add('');
end;
if ExpChk.Checked then
begin
title := 'EXPECTED FREQUENCIES';
MatPrint(Expected, NRows, NCols, title, RowLabels, ColLabels, NCases, lReport);
end;
FFrequenciesReportFrame.DisplayReport(lReport);
lReport.Clear;
end else
FrequenciesPage.TabVisible := false;
if PropsChk.Checked then
begin
RowColPage.TabVisible := true;
GetRowProportions(Freq, Prop);
lReport.Add('CHI-SQUARE ANALYSIS RESULTS');
lReport.Add('');
title := 'ROW PROPORTIONS';
MatPrint(Prop, NRows+1, NCols+1, title, RowLabels, ColLabels, NCases, lReport);
lReport.Add(DIVIDER_SMALL_AUTO);
lReport.Add('');
GetColProportions(Freq, Prop);
title := 'COLUMN PROPORTIONS';
MatPrint(Prop, NRows+1, NCols+1, title, RowLabels, ColLabels, NCases, lReport);
lReport.Add(DIVIDER_SMALL_AUTO);
lReport.Add('');
GetTotalProportions(Freq, Prop);
Title := 'PROPORTIONS OF TOTAL N';
MatPrint(Prop, NRows+1, NCols+1, title, RowLabels, ColLabels, NCases, lReport);
lReport.Add(DIVIDER_SMALL_AUTO);
lReport.Add('');
FRowColPropsReportFrame.DisplayReport(lReport);
lReport.Clear;
end else
RowColPage.TabVisible := false;
if CellChiChk.Checked then
begin
CellChiSqrPage.TabVisible := true;
lReport.Add('CHI-SQUARE ANALYSIS RESULTS');
lReport.Add('');
title := 'CHI-SQUARED VALUE FOR CELLS';
MatPrint(CellChi, NRows, NCols, title, RowLabels, ColLabels, NCases, lReport);
FCellChiSqrReportFrame.DisplayReport(lReport);
lReport.Clear;
end else
CellChiSqrPage.TabVisible := false;
lReport.Add('CHI-SQUARE ANALYSIS RESULTS');
lReport.Add('');
lReport.Add('Chi-square: %.3f', [ChiSquare]);
@ -454,50 +397,39 @@ begin
lReport.Free;
end;
// save frequency data file if elected
if SaveFChk.Checked then
// Print frequencies tables if requested by user
if ObsChk.Checked or ExpChk.Checked then
begin
OS3MainFrm.mnuFileCloseClick(self);
OS3MainFrm.FileNameEdit.Text := '';
for i := 1 to DictionaryFrm.DictGrid.RowCount - 1 do
for j := 0 to 7 do DictionaryFrm.DictGrid.Cells[j,i] := '';
DictionaryFrm.DictGrid.RowCount := 1;
FrequenciesPage.TabVisible := true;
ProcessAndReportFrequencies(Freq, Expected, RowLabels, ColLabels);
end else
FrequenciesPage.TabVisible := false;
// get labels for new file
ColLabels[0] := 'ROW';
ColLabels[1] := 'COL';
ColLabels[2] := 'FREQ';
// Print proportions if requested by user
if PropsChk.Checked then
begin
RowColPage.TabVisible := true;
ProcessAndReportProportions(Freq, RowLabels, ColLabels);
end else
RowColPage.TabVisible := false;
// create new variables
Row := 0;
OS3MainFrm.DataGrid.ColCount := 4;
DictionaryFrm.DictGrid.ColCount := 8;
NoVariables := 0;
for i := 1 to 3 do
// Print cell chisqr values if requested by user
if CellChiChk.Checked then
begin
col := NoVariables + 1;
DictionaryFrm.NewVar(col);
DictionaryFrm.DictGrid.Cells[1,col] := ColLabels[i-1];
OS3MainFrm.DataGrid.Cells[col,0] := ColLabels[i-1];
NoVariables := NoVariables + 1;
end;
OS3MainFrm.DataGrid.RowCount := (Nrows * NCols) + 1;
CellChiSqrPage.TabVisible := true;
ProcessAndReportCellChiSqr(CellChi, RowLabels, ColLabels, NCases);
end else
CellChiSqrPage.TabVisible := false;
for i := 1 to Nrows do
begin
for j := 1 to Ncols do
begin
Row := Row + 1;
OS3MainFrm.DataGrid.Cells[0,Row] := Format('Case:%d',[Row]);
OS3MainFrm.DataGrid.Cells[1,Row] := IntToStr(i);
OS3MainFrm.DataGrid.Cells[2,Row] := IntToStr(j);
OS3MainFrm.DataGrid.Cells[3,Row] := IntToStr(Freq[i-1,j-1]);
end;
end;
NoCases := Row;
OS3MainFrm.FileNameEdit.Text := 'ChiSqrFreq.LAZ';
OS3MainFrm.NoCasesEdit.Text := IntToStr(NoCases);
OS3MainFrm.NoVarsEdit.Text := IntToStr(NoVariables);
// Save frequency data in grid if elected.
// NOTE: THIS WILL CLOSE CURRENT FILE!
if SaveFChk.Checked and
(MessageDlg('This operation will close the current data file. Continue?',
mtConfirmation, [mbYes, mbNo], 0) = mrYes)
then begin
FrequenciesToGrid(Freq);
Reset; // the grids contains new variables which must be read.
SaveFChk.Checked := false;
end;
end;
@ -527,25 +459,82 @@ begin
end;
procedure TChiSqrFrm.FrequenciesToGrid(const AFrequencies: IntDyneMat);
var
numRows, numCols: Integer;
row, col: Integer;
i, j: Integer;
colLabels: StrDyneVec = nil;
begin
MatSize(AFrequencies, numRows, numCols); // contains totals in last row/col
dec(numRows); // we don't need the totals
dec(numCols);
OS3MainFrm.mnuFileCloseClick(self);
OS3MainFrm.FileNameEdit.Text := '';
for i := 1 to DictionaryFrm.DictGrid.RowCount - 1 do
for j := 0 to 7 do DictionaryFrm.DictGrid.Cells[j,i] := '';
DictionaryFrm.DictGrid.RowCount := 1;
// get labels for new file
SetLength(colLabels, 3);
colLabels[0] := 'ROW';
colLabels[1] := 'COL';
colLabels[2] := 'FREQ';
// create new variables
OS3MainFrm.DataGrid.ColCount := 4;
DictionaryFrm.DictGrid.ColCount := 8;
NoVariables := 0;
for i := 0 to High(colLabels) do
begin
col := NoVariables + 1;
DictionaryFrm.NewVar(col); // increments NoVariables!
DictionaryFrm.DictGrid.Cells[1, col] := ColLabels[i];
OS3MainFrm.DataGrid.Cells[col, 0] := ColLabels[i];
end;
OS3MainFrm.DataGrid.RowCount := (numRows * numCols) + 1;
row := 0;
for i := 0 to numRows-1 do
begin
for j := 0 to numCols-1 do
begin
row := row + 1;
OS3MainFrm.DataGrid.Cells[0, Row] := Format('Case %d', [row]);
OS3MainFrm.DataGrid.Cells[1, Row] := IntToStr(i+1);
OS3MainFrm.DataGrid.Cells[2, Row] := IntToStr(j+1);
OS3MainFrm.DataGrid.Cells[3, Row] := IntToStr(AFrequencies[i, j]);
end;
end;
NoCases := row;
OS3MainFrm.FileNameEdit.Text := 'ChiSqrFreq.laz';
OS3MainFrm.NoCasesEdit.Text := IntToStr(NoCases);
OS3MainFrm.NoVarsEdit.Text := IntToStr(NoVariables);
end;
procedure TChiSqrFrm.GetExpectedAndCellChiSqr(const AFrequencies: IntDyneMat;
out AExpected, ACellChiSqr: DblDyneMat;
out AChiSqr: Double);
var
numRows, numCols, numCases: Integer;
n, m, numCases: Integer;
i, j: Integer;
begin
MatSize(AFrequencies, numRows, numCols); // contains the totals row/col
numCases := AFrequencies[numRows-1, numCols-1];
MatSize(AFrequencies, n, m); // contains the totals row/col
numCases := AFrequencies[n-1, m-1];
SetLength(AExpected, numRows-1, numCols-1); // -1: we don't need the totals here
SetLength(ACellChiSqr, numRows-1, numCols-1);
AExpected := nil;
ACellChiSqr := nil;
SetLength(AExpected, n-1, m-1); // -1: we don't need the totals here
SetLength(ACellChiSqr, n-1, m-1);
AChiSqr := 0;
for i := 0 to numRows-2 do // -2 instead of -1 to skip the totals row
for i := 0 to n-2 do // -2 instead of -1 to skip the totals row
begin
for j := 0 to numCols-2 do // -2 instead of -1 to skip the totals column
for j := 0 to m-2 do // -2 instead of -1 to skip the totals column
begin
AExpected[i, j] := AFrequencies[numRows-1, j] * AFrequencies[i, numCols-1] / numCases;
AExpected[i, j] := AFrequencies[n-1, j] * AFrequencies[i, m-1] / numCases;
if AExpected[i, j] > 0 then
ACellChiSqr[i, j] := sqr(AFrequencies[i, j] - AExpected[i, j]) / AExpected[i, j]
else begin
@ -608,7 +597,7 @@ begin
begin
if not GoodRecord(OS3MainFrm.DataGrid, i, AColNoSelected) then continue;
row := round(StrToFloat(Trim(OS3MainFrm.DataGrid.Cells[ARowIndex, i])));
col := round(StrToFloat(Trim(OS3MainFrm.DataGrid.Cells[ARowIndex, i])));
col := round(StrToFloat(Trim(OS3MainFrm.DataGrid.Cells[AColIndex, i])));
row := row - minRow;
col := col - minCol;
FObs := round(StrToFloat(Trim(OS3MainFrm.DataGrid.Cells[ADepIndex, i])));
@ -650,10 +639,10 @@ end;
procedure TChiSqrFrm.GetYatesCorrection(const AFrequencies: IntDyneMat;
out AdjChiSqr: Double);
var
numRows, numCols, numCases: Integer;
n, m, numCases: Integer;
begin
MatSize(AFrequencies, numRows, numCols);
numCases := AFrequencies[numRows-1, numCols-1];
MatSize(AFrequencies, n, m);
numCases := AFrequencies[n-1, m-1];
AdjChiSqr := abs((AFrequencies[0,0] * AFrequencies[1,1]) - (AFrequencies[0,1] * AFrequencies[1,0]));
AdjChiSqr := sqr(AdjChiSqr - numCases / 2.0) * numCases; // numerator
@ -667,6 +656,7 @@ var
numRows, numCols: Integer;
i, j: Integer;
begin
AProportions := nil;
MatSize(AFrequencies, numRows, numCols); // totals in last row/col
SetLength(AProportions, numRows, numCols);
for j := 0 to numCols-1 do
@ -692,6 +682,7 @@ var
numRows, numCols: Integer;
i, j: Integer;
begin
AProportions := nil;
MatSize(AFrequencies, numRows, numCols); // totals in last row/col
SetLength(AProportions, numRows, numCols);
for i := 0 to numRows-1 do
@ -720,6 +711,7 @@ begin
MatSize(AFrequencies, numRows, numCols); // totals in last row/col
numCases := AFrequencies[numRows-1, numCols-1];
AProportions := nil;
SetLength(AProportions, numRows, numCols);
for i := 0 to numRows-1 do
for j := 0 to numCols-1 do
@ -730,29 +722,110 @@ end;
procedure TChiSqrFrm.InputGrpClick(Sender: TObject);
begin
case InputGrp.ItemIndex of
0: begin // have to count cases in each row and col. combination
NCasesLabel.Enabled := false;
NCasesEdit.Enabled := false;
DepEdit.Enabled := false;
end;
1: begin // frequencies available for each row and column combo
NCasesLabel.Enabled := false;
NCasesEdit.Enabled := false;
AnalyzeLabel.Enabled := true;
end;
2: begin // only proportions available - get N size
NCasesLabel.Enabled := true;
AnalyzeLabel.Enabled := true;
NCasesEdit.Enabled := true;
NCasesEdit.SetFocus;
DepEdit.Enabled := true;
end;
end;
// InputGrp = 0: have to count cases in each row and col combination
// = 1: frequencies available for each row and column combo
// = 2: only proportions available - get N size from NCasesEdit
DepEdit.Enabled := (InputGrp.ItemIndex > 0);
DepLabel.Enabled := DepEdit.Enabled;
NCasesEdit.Enabled := (InputGrp.ItemIndex = 2);
NCasesLabel.Enabled := NCasesEdit.Enabled;
UpdateBtnStates;
end;
procedure TChiSqrFrm.ProcessAndReportCellChiSqr(const ACellChiSqr: DblDyneMat;
const ARowLabels, AColLabels: StrDyneVec; ANumCases: Integer);
var
lReport: TStrings;
n, m: Integer;
begin
MatSize(ACellChiSqr, n, m);
lReport := TStringList.Create;
try
lReport.Add('CHI-SQUARE ANALYSIS RESULTS');
lReport.Add('');
MatPrint(ACellChiSqr, n, m, 'CHI-SQUARED VALUE FOR CELLS', ARowLabels, AColLabels, ANumCases, lReport);
FCellChiSqrReportFrame.DisplayReport(lReport);
finally
lReport.Free;
end;
end;
procedure TChiSqrFrm.ProcessAndReportFrequencies(const AFrequencies: IntDyneMat;
const AExpected: DblDyneMat; const ARowLabels, AColLabels: StrDyneVec);
var
lReport: TStrings;
n, m, numCases: Integer;
begin
lReport := TStringList.Create;
try
lReport.Add('CHI-SQUARE ANALYSIS RESULTS');
MatSize(AFrequencies, n, m); // totals in last row and col
numCases := AFrequencies[n-1, m-1];
if ObsChk.Checked then
begin
IntArrayPrint(AFrequencies, n, m, 'Rows', ARowLabels, AColLabels, 'OBSERVED FREQUENCIES', lReport);
if ExpChk.Checked then
lReport.Add(DIVIDER_SMALL_AUTO);
end;
if ExpChk.Checked then
begin
lReport.Add('');
MatPrint(AExpected, n-1, m-1, 'EXPECTED FREQUENCIES', ARowLabels, AColLabels, numCases, lReport);
end;
FFrequenciesReportFrame.DisplayReport(lReport);
finally
lReport.Free;
end;
end;
procedure TChiSqrFrm.ProcessAndReportProportions(const AFrequencies: IntDyneMat;
const ARowLabels, AColLabels: StrDyneVec);
var
lReport: TStrings;
n, m, numCases: Integer;
prop: DblDyneMat;
begin
MatSize(AFrequencies, n, m);
numCases := AFrequencies[n-1, m-1];
lReport := TStringList.Create;
try
lReport.Add('CHI-SQUARE ANALYSIS RESULTS');
lReport.Add('');
GetRowProportions(AFrequencies, prop);
MatPrint(prop, n, m, 'ROW PROPORTIONS', ARowLabels, AColLabels, numCases, lReport);
lReport.Add(DIVIDER_SMALL_AUTO);
lReport.Add('');
GetColProportions(AFrequencies, prop);
MatPrint(prop, n, m, 'COLUMN PROPORTIONS', ARowLabels, AColLabels, numCases, lReport);
lReport.Add(DIVIDER_SMALL_AUTO);
lReport.Add('');
GetTotalProportions(AFrequencies, prop);
MatPrint(Prop, n, m, 'PROPORTIONS OF TOTAL N', ARowLabels, AColLabels, numCases, lReport);
FRowColPropsReportFrame.DisplayReport(lReport);
finally
lReport.Free;
end;
end;
procedure TChiSqrFrm.Reset;
var
i: integer;
@ -776,7 +849,7 @@ begin
ColEdit.Clear;
DepEdit.Clear;
AnalyzeLabel.Enabled := false;
DepLabel.Enabled := false;
NCasesLabel.Enabled := false;
NCasesEdit.Text := '';
NCasesEdit.Enabled := false;

View File

@ -289,12 +289,12 @@ procedure TDictionaryFrm.Defaults(Sender: TObject; row : integer);
var
i: integer;
begin
DictGrid.Cells[0,row] := IntToStr(row);
DictGrid.Cells[1,row] := 'VAR.' + IntToStr(row);
DictGrid.Cells[2,row] := 'VARIABLE ' + IntToStr(row);
DictGrid.Cells[3,row] := '8';
DictGrid.Cells[4,row] := 'F';
DictGrid.Cells[5,row] := '2';
DictGrid.Cells[0, row] := IntToStr(row);
DictGrid.Cells[1, row] := 'VAR.' + IntToStr(row);
DictGrid.Cells[2, row] := 'VARIABLE ' + IntToStr(row);
DictGrid.Cells[3, row] := '8';
DictGrid.Cells[4, row] := 'F';
DictGrid.Cells[5, row] := '2';
DictGrid.Cells[6, row] := MissingValueCodes[Options.DefaultMiss];
DictGrid.Cells[7, row] := JustificationCodes[Options.DefaultJust];
for i := 1 to DictGrid.RowCount - 1 do
@ -352,7 +352,7 @@ begin
if OS3MainFrm.DataGrid.ColCount < ARow then
begin
OS3MainFrm.DataGrid.ColCount := OS3MainFrm.DataGrid.ColCount + 1;
OS3MainFrm.DataGrid.Cells[ARow,0] := DictGrid.Cells[1, ARow];
OS3MainFrm.DataGrid.Cells[ARow, 0] := DictGrid.Cells[1, ARow];
end;
ReturnBtnClick(Self);

View File

@ -1477,7 +1477,8 @@ begin
while not done do
begin
AReport.Add(' ' + ytitle);;
if YTitle <> '' then
AReport.Add(' ' + YTitle);;
AReport.Add('Variables');
outline := DupeString(' ', 12+1);
@ -1501,8 +1502,9 @@ begin
AReport.Add('');
first := last + 1;
end;
AReport.Add('');
//AReport.Add('');
end;
//---------------------------------------------------------------------------
procedure eigens(VAR a: DblDyneMat; Var d : DblDyneVec; n : integer);
@ -2383,7 +2385,7 @@ procedure AddVariable(AVarName: String; AData: DblDyneVec;
end;
var
i, j, colIndex, row: Integer;
i, colIndex, row: Integer;
begin
colIndex := GetVariableIndex(OS3MainFrm.DataGrid, AVarname);
if colIndex = -1 then