unit DescriptiveUnit; {$mode objfpc}{$H+} interface uses Classes, SysUtils, FileUtil, LResources, Forms, Controls, Graphics, Dialogs, StdCtrls, ExtCtrls, Buttons, MainUnit, Globals, FunctionsLib, OutputUnit, DataProcs, DictionaryUnit, ContextHelpUnit; type { TDescriptiveFrm } TDescriptiveFrm = class(TForm) Bevel1: TBevel; ComputeBtn: TButton; CaseChk: TCheckBox; CheckBox1: TCheckBox; AltQrtilesChk: TCheckBox; HelpBtn: TButton; Label2: TLabel; Label3: TLabel; PcntileChk: TCheckBox; GroupBox1: TGroupBox; InBtn: TBitBtn; OutBtn: TBitBtn; AllBtn: TBitBtn; ResetBtn: TButton; CloseBtn: TButton; CIEdit: TEdit; Label1: TLabel; VarList: TListBox; SelList: TListBox; procedure AllBtnClick(Sender: TObject); procedure ComputeBtnClick(Sender: TObject); procedure FormActivate(Sender: TObject); procedure FormCreate(Sender: TObject); procedure FormShow(Sender: TObject); procedure HelpBtnClick(Sender: TObject); procedure InBtnClick(Sender: TObject); procedure OutBtnClick(Sender: TObject); procedure ResetBtnClick(Sender: TObject); procedure VarListSelectionChange(Sender: TObject; User: boolean); private { private declarations } FAutoSized: Boolean; sum, variance, stddev, value, mean, min, max, range, skew, prob, df, CI : double; kurtosis, z, semean, seskew, sekurtosis, deviation, devsqr, M2, M3, M4 : double; Q1, Q2, Q3, Q12, Q13, Q14, Q15, Q16, Q17, Q18, Q22, Q23, Q24, Q25, Q26 : double; Q27, Q28, Q32, Q33, Q34, Q35, Q36, Q37, Q38, IQrange : double; ncases, noselected : integer; cellstring, gridstring: string; selected : IntDyneVec; procedure UpdateBtnStates; public { public declarations } end; var DescriptiveFrm: TDescriptiveFrm; implementation uses Math; { TDescriptiveFrm } procedure TDescriptiveFrm.ResetBtnClick(Sender: TObject); var i: integer; begin CIEdit.Text := FormatFloat('0.0', DEFAULT_CONFIDENCE_LEVEL_PERCENT); VarList.Clear; SelList.Clear; for i := 1 to NoVariables do VarList.Items.Add(OS3MainFrm.DataGrid.Cells[i,0]); Selected := nil; UpdateBtnStates; end; procedure TDescriptiveFrm.FormActivate(Sender: TObject); var w: Integer; begin if FAutoSized then exit; w := MaxValue([HelpBtn.Width, ResetBtn.Width, ComputeBtn.Width, CloseBtn.Width]); HelpBtn.Constraints.MinWidth := w; ResetBtn.Constraints.MinWidth := w; ComputeBtn.Constraints.MinWidth := w; CloseBtn.Constraints.MinWidth := w; Constraints.MinWidth := Width; Constraints.MinHeight := Height; FAutoSized := true; end; procedure TDescriptiveFrm.FormCreate(Sender: TObject); begin Assert(OS3MainFrm <> nil); if DictionaryFrm = nil then Application.CreateForm(TDictionaryFrm, DictionaryFrm); end; procedure TDescriptiveFrm.FormShow(Sender: TObject); begin ResetBtnClick(self); end; procedure TDescriptiveFrm.HelpBtnClick(Sender: TObject); begin if ContextHelpForm = nil then Application.CreateForm(TContextHelpForm, ContextHelpForm); ContextHelpForm.HelpMessage((Sender as TButton).tag); end; procedure TDescriptiveFrm.InBtnClick(Sender: TObject); var i: integer; begin i := 0; while i < VarList.Items.Count do begin if VarList.Selected[i] then begin SelList.Items.Add(VarList.Items[i]); VarList.Items.Delete(i); i := 0; end else inc(i); end; UpdateBtnStates; end; procedure TDescriptiveFrm.ComputeBtnClick(Sender: TObject); var i, j, k, m: integer; num, den, cases: double; values, pcntrank: DblDyneVec; lReport: TStrings; begin noselected := SelList.Items.Count; if noSelected = 0 then begin MessageDlg('No variables selected.', mtError, [mbOK], 0); exit; end; SetLength(Selected, noselected); // Get selected variables for i := 1 to noselected do begin cellstring := SelList.Items.Strings[i-1]; for j := 1 to NoVariables do if cellstring = OS3MainFrm.DataGrid.Cells[j,0] then selected[i-1] := j; end; lReport := TStringList.Create; try lReport.Add('DISTRIBUTION PARAMETER ESTIMATES'); lReport.Add(''); SetLength(Values, NoCases); SetLength(pcntrank, NoCases); for j := 1 to noselected do begin deviation := 0.0; devsqr := 0.0; M2 := 0.0; M3 := 0.0; M4 := 0.0; sum := 0.0; variance := 0.0; stddev := 0.0; range := 0.0; skew := 0.0; kurtosis := 0.0; ncases := 0; df := 0.0; seskew := 0.0; kurtosis := 0.0; sekurtosis := 0.0; k := selected[j-1]; CI := StrToFloat(CIEdit.Text) / 100.0; prob := CI; CI := (1.0 - CI) / 2.0; CI := 1.0 - CI; if CheckBox1.Checked then // add a new column to the grid begin gridstring := OS3MainFrm.DataGrid.Cells[k,0]; gridstring := Gridstring + 'z'; DictionaryFrm.NewVar(NoVariables+1); DictionaryFrm.DictGrid.Cells[1,NoVariables] := gridstring; OS3MainFrm.DataGrid.Cells[NoVariables,0] := gridstring; end; // Accumulate sums of squares, sums, etc. for variable j min := 1.0e308; max := -1.0e308; for i := 1 to NoCases do begin if not GoodRecord(i,noselected,selected) then continue; if CaseChk.Checked then begin if not ValidValue(i,selected[j-1]) then continue; end else if not GoodRecord(i,noselected,selected) then continue; value := StrToFloat(OS3MainFrm.DataGrid.Cells[k,i]); ncases := ncases + 1; values[ncases-1] := value; df := df + 1.0; sum := sum + value; variance := variance + (value * value); if (value < min) then min := value; if (value > max) then max := value; end; if ncases > 0 then begin mean := sum / ncases; range := max - min; end; if ncases > 1 then begin variance := variance - (sum * sum) / ncases; variance := variance / (ncases - 1); stddev := sqrt(variance); semean := sqrt(variance / ncases); if ncases < 120 then CI := semean * inverset(CI,df) else CI := semean * inversez(CI); end; if variance = 0.0 then begin cellstring := OS3MainFrm.DataGrid.Cells[k,0]; MessageDlg('No Variability in '+ cellstring + ' variable - ending analysis.', mtInformation, [mbOK], 0); exit; end; if ncases > 3 then // obtain skew, kurtosis and z scores begin for i := 1 to NoCases do begin if CaseChk.Checked then begin if not ValidValue(i,selected[j-1]) then continue; end else if not GoodRecord(i,noselected,selected) then continue; value := StrToFloat(OS3MainFrm.DataGrid.Cells[k,i]); if stddev > 0.0 then begin deviation := value - mean; devsqr := deviation * deviation; M2 := M2 + devsqr; M3 := M3 + (deviation * devsqr); M4 := M4 + (devsqr * devsqr); z := (value - mean) / stddev; if CheckBox1.Checked then begin cellstring := format('%8.5f',[z]); OS3MainFrm.DataGrid.Cells[NoVariables,i] := cellstring; end; end; end; if ncases > 2 then begin skew := (ncases * M3) / ((ncases - 1) * (ncases - 2) * stddev * variance); cases := ncases; num := 6.0 * cases * (cases - 1.0); den := (cases - 2.0) * (cases + 1.0) * (cases + 3.0); seskew := sqrt(num / den); end; if ncases > 3 then begin kurtosis := (ncases * (ncases + 1) * M4) - (3 * M2 * M2 * (ncases - 1)); kurtosis := kurtosis / ( (ncases - 1) * (ncases - 2) * (ncases - 3) * (variance * variance) ); sekurtosis := sqrt((4.0 * (ncases * ncases - 1) * (seskew * seskew)) / ((ncases - 3) * (ncases + 5))); end; end; // output results for the kth variable cellstring := OS3MainFrm.DataGrid.Cells[k,0]; if j > 1 then lReport.Add(''); lReport.Add('VARIABLE: %10s', ['"' + cellString + '"']); lReport.Add(''); lReport.Add('Number of cases: %10d', [nCases]); lReport.Add('Sum: %10.3f', [sum]); lReport.Add('Mean: %10.3f', [mean]); lReport.Add('Variance: %10.3f', [variance]); lReport.Add('Std.Dev.: %10.3f', [stddev]); lReport.Add('Std.Error of Mean %10.3f', [seMean]); lReport.Add('%.2f%% Conf.Interval Mean: %10.3f to %.3f', [prob*100.0, mean - CI, mean + CI]); lReport.Add('Range: %10.3f', [range]); lReport.Add('Minimum: %10.3f', [min]); lReport.Add('Maximum: %10.3f', [max]); lReport.Add('Skewness: %10.3f', [skew]); lReport.Add('Std.Error of Skew: %10.3f', [seSkew]); lReport.Add('Kurtosis: %10.3f', [kurtosis]); lReport.Add('Std. Error of Kurtosis: %10.3f', [seKurtosis]); lReport.Add(''); if ncases > 4 then // get percentiles and quartiles begin // get percentile ranks if pcntileChk.Checked then PRank(k, pcntRank, lReport); // sort values and get quartiles for i := 0 to ncases - 2 do begin for m := i + 1 to ncases -1 do begin if values[i] > values[m] then begin value := values[i]; values[i] := values[m]; values[m] := value; end; end; end; Q1 := Quartiles(2,0.25,ncases,values); Q2 := Quartiles(2,0.5,ncases,values); Q3 := Quartiles(2,0.75,ncases,values); IQrange := Q3 - Q1; lReport.Add('First Quartile: %10.3f', [Q1]); lReport.Add('Median: %10.3f', [Q2]); lReport.Add('Third Quartile: %10.3f', [Q3]); lReport.Add('Interquartile range: %10.3f', [IQrange]); lReport.Add(''); end; if (AltQrtilesChk.Checked) then begin lReport.Add('Alternative Methods for Obtaining Quartiles'); lReport.Add(' Method 1 2 3 4 5 6 7 8'); lReport.Add('Pcntile'); Q1 := Quartiles(1,0.25,ncases,values); Q12 := Quartiles(2,0.25,ncases,values); Q13 := Quartiles(3,0.25,ncases,values); Q14 := Quartiles(4,0.25,ncases,values); Q15 := Quartiles(5,0.25,ncases,values); Q16 := Quartiles(6,0.25,ncases,values); Q17 := Quartiles(7,0.25,ncases,values); Q18 := Quartiles(8,0.25,ncases,values); lReport.Add('Q1 %8.3f%8.3f%8.3f%8.3f%8.3f%8.3f%8.3f%8.3f', [Q1,Q12,Q13,Q14,Q15,Q16,Q17,Q18]); Q2 := Quartiles(1,0.5,ncases,values); Q22 := Quartiles(2,0.5,ncases,values); Q23 := Quartiles(3,0.5,ncases,values); Q24 := Quartiles(4,0.5,ncases,values); Q25 := Quartiles(5,0.5,ncases,values); Q26 := Quartiles(6,0.5,ncases,values); Q27 := Quartiles(7,0.5,ncases,values); Q28 := Quartiles(8,0.5,ncases,values); lReport.Add('Q2 %8.3f%8.3f%8.3f%8.3f%8.3f%8.3f%8.3f%8.3f', [Q2,Q22,Q23,Q24,Q25,Q26,Q27,Q28]); Q3 := Quartiles(1,0.75,ncases,values); Q32 := Quartiles(2,0.75,ncases,values); Q33 := Quartiles(3,0.75,ncases,values); Q34 := Quartiles(4,0.75,ncases,values); Q35 := Quartiles(5,0.75,ncases,values); Q36 := Quartiles(6,0.75,ncases,values); Q37 := Quartiles(7,0.75,ncases,values); Q38 := Quartiles(8,0.75,ncases,values); lReport.Add('Q3 %8.3f%8.3f%8.3f%8.3f%8.3f%8.3f%8.3f%8.3f', [Q3,Q32,Q33,Q34,Q35,Q36,Q37,Q38]); lReport.Add('NOTES:'); lReport.Add('Method 1 is the weighted average at X[np] where n is no. of cases, p is percentile / 100'); lReport.Add('Method 2 is the weighted average at X[(n+1)p] This is used in this program.'); lReport.Add('Method 3 is the empirical distribution function.'); lReport.Add('Method 4 is called the empirical distribution function - averaging.'); lReport.Add('Method 5 is called the empirical distribution function = Interpolation.'); lReport.Add('Method 6 is the closest observation method.'); lReport.Add('Method 7 is from the TrueBasic Statistics Graphics Toolkit.'); lReport.Add('Method 8 was used in an older Microsoft Excel version.'); lReport.Add('See the internet site http://www.xycoon.com/ for the above.'); lReport.Add(''); end; // end of experimental alternatives lReport.Add('--------------------------------------------------------------'); end; // next j variable DisplayReport(lReport); finally lReport.Free; Selected := nil; Values := nil; pcntrank := nil; end; end; procedure TDescriptiveFrm.OutBtnClick(Sender: TObject); var i: integer; begin i := 0; while i < SelList.Items.Count do begin if SelList.Selected[i] then begin VarList.Items.Add(SelList.Items[i]); SelList.Items.Delete(i); i := 0; end else inc(i); end; UpdateBtnStates; end; procedure TDescriptiveFrm.AllBtnClick(Sender: TObject); var i : integer; begin for i := 0 to VarList.Items.Count-1 do SelList.Items.Add(VarList.Items.Strings[i]); VarList.Clear; UpdateBtnStates; end; procedure TDescriptiveFrm.UpdateBtnStates; var lSelected: Boolean; i: Integer; begin lSelected := false; for i := 0 to VarList.Items.Count-1 do if VarList.Selected[i] then begin lSelected := true; break; end; InBtn.Enabled := lSelected; lSelected := false; for i := 0 to SelList.Items.Count-1 do if SelList.Selected[i] then begin lSelected := true; break; end; OutBtn.Enabled := lSelected; AllBtn.Enabled := VarList.Count > 0; end; procedure TDescriptiveFrm.VarListSelectionChange(Sender: TObject; User: boolean); begin UpdateBtnStates; end; initialization {$I descriptiveunit.lrs} end.