unit SignTestUnit; {$mode objfpc}{$H+} interface uses Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, Buttons, ExtCtrls, MainUnit, FunctionsLib, Globals, BasicStatsReportFormUnit; type { TSignTestFrm } TSignTestFrm = class(TBasicStatsReportForm) Var1In: TBitBtn; Var1Out: TBitBtn; Var2In: TBitBtn; Var2Out: TBitBtn; Var1Edit: TEdit; Var2Edit: TEdit; Label1: TLabel; Label2: TLabel; Label3: TLabel; VarList: TListBox; procedure Var1InClick(Sender: TObject); procedure Var1OutClick(Sender: TObject); procedure Var2InClick(Sender: TObject); procedure Var2OutClick(Sender: TObject); procedure VarListDblClick(Sender: TObject); procedure VarListSelectionChange(Sender: TObject; {%H-}User: boolean); private protected procedure AdjustConstraints; override; procedure Compute; override; procedure UpdateBtnStates; override; function Validate(out AMsg: String; out AControl: TWinControl): boolean; override; public procedure Reset; override; end; var SignTestFrm: TSignTestFrm; implementation {$R *.lfm} uses Math, GridProcs; { TSignTestFrm } procedure TSignTestFrm.AdjustConstraints; begin inherited; ParamsPanel.Constraints.MinWidth := 4*CloseBtn.Width + 3*CloseBtn.BorderSpacing.Left; ParamsPanel.Constraints.MinHeight := Var2Out.Top + Var2Out.Height + ButtonBevel.Height + CloseBtn.Height + CloseBtn.Borderspacing.Top; end; procedure TSignTestFrm.Compute; var ColNoSelected: IntDyneVec = nil; DifSigns: IntDyneVec = nil; i, col1, col2, X, N, A, b, Temp: integer; p, Q, Probability, z, NoDiff, CorrectedA, x1, x2: double; SumProb: double; lReport: TStrings; begin SumProb := 0.0; SetLength(DifSigns, NoCases); // Get column numbers and labels of variables selected SetLength(ColNoSelected, 2); ColNoSelected[0] := GetVariableIndex(OS3MainFrm.DataGrid, Var1Edit.Text); ColNoSelected[1] := GetVariableIndex(OS3MainFrm.DataGrid, Var2Edit.Text); p := 0.5; Q := 0.5; // Get sign of difference between pairs '(-1 := - ; 0 := no difference; +1 := + A := 0; b := 0; NoDiff := 0.0; for i := 1 to NoCases do begin if (not GoodRecord(OS3MainFrm.DataGrid, i, ColNoSelected)) then continue; col1 := ColNoSelected[0]; col2 := ColNoSelected[1]; x1 := StrToFloat(Trim(OS3MainFrm.DataGrid.Cells[col1, i])); x2 := StrToFloat(Trim(OS3MainFrm.DataGrid.Cells[col2, i])); if (x1 > x2) then begin DifSigns[i-1] := 1; A := A + 1; end; if (x1 < x2) then begin DifSigns[i-1] := -1; b := b + 1; end; if (x1 = x2) then begin DifSigns[i-1] := 0; NoDiff := NoDiff + 1.0; end; end; // Show results lReport := TStringList.Create; try lReport.Add('RESULTS FOR THE SIGN TEST'); lReport.Add(''); lReport.Add('Frequency of %d out of %d observed + sign differences.', [A, NoCases]); lReport.Add('Frequency of %d out of %d observed - sign differences.', [b, NoCases]); lReport.Add('Frequency of %.0f out of %d observed no differences.', [NoDiff, NoCases]); lReport.Add(''); lReport.Add('The theoretical proportion expected for +''s or -''s is 0.5 '); lReport.Add('The test is for the probability of the +''s or -''s (which ever is fewer)');; lReport.Add('as small or smaller than that observed given the expected proportion.'); lReport.Add(''); // Swap A and B around if A > B if (A > b) then begin Temp := A; A := b; b := Temp; end; N := A + b; if (N > 25) then // Use normal distribution approximation begin 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 Distribution approximation: %.3f', [z]); Probability := ProbZ(z); lReport.Add('Probability: %.4f', [Probability]); end else // Use binomial fomula begin X := 0; while X <= A do begin Probability := combos(X, N) * Power(p,X) * Power(Q,(N - X)); lReport.Add('Binary Probability of %3d: %6.4f', [X, Probability]); SumProb := SumProb + Probability; X := X + 1; end; lReport.Add('Binomial Probability of %d or smaller out of %d: %.4f', [A, N, SumProb]); end; FReportFrame.DisplayReport(lReport); finally lReport.Free; end; end; procedure TSignTestFrm.Reset; var i: integer; begin inherited; Var1Edit.Clear; Var2Edit.Clear; VarList.Items.Clear; for i := 1 to NoVariables do VarList.Items.Add(OS3MainFrm.DataGrid.Cells[i,0]); UpdateBtnStates; end; function TSignTestFrm.Validate(out AMsg: String; out AControl: TWinControl): boolean; begin Result := false; if Var1Edit.Text = '' then begin AMsg := 'Variable 1 not selected.'; AControl := Var1Edit; exit; end; if Var2Edit.Text = '' then begin AMsg := 'Variable 2 not selected.'; AControl := Var2Edit; exit; end; Result := true; end; procedure TSignTestFrm.Var1InClick(Sender: TObject); var index: integer; begin index := VarList.ItemIndex; if (index > -1) and (Var1Edit.Text = '') then begin Var1Edit.Text := VarList.Items[index]; VarList.Items.Delete(index); end; UpdateBtnStates; end; procedure TSignTestFrm.Var1OutClick(Sender: TObject); begin if Var1Edit.Text <> '' then begin VarList.Items.Add(Var1Edit.Text); Var1Edit.Text := ''; end; UpdateBtnStates; end; procedure TSignTestFrm.Var2InClick(Sender: TObject); var index: integer; begin index := VarList.ItemIndex; if (index > -1) and (Var2Edit.Text = '') then begin Var2Edit.Text := VarList.Items[index]; VarList.Items.Delete(index); end; UpdateBtnStates; end; procedure TSignTestFrm.Var2OutClick(Sender: TObject); begin if Var2Edit.Text <> '' then begin VarList.Items.Add(Var2Edit.Text); Var2Edit.Text := ''; end; UpdateBtnStates; end; procedure TSignTestFrm.VarListDblClick(Sender: TObject); var index: Integer; s: String; begin index := Varlist.ItemIndex;; if index > -1 then begin s := VarList.Items[index]; if Var1Edit.Text = '' then Var1Edit.Text := s else if Var2Edit.Text = '' then Var2Edit.Text := s; Varlist.Items.Delete(index); UpdateBtnStates; end; end; procedure TSignTestFrm.VarListSelectionChange(Sender: TObject; User: boolean); begin UpdateBtnStates; end; procedure TSignTestFrm.UpdateBtnStates; begin Var1In.Enabled := (VarList.ItemIndex > -1) and (Var1Edit.Text = ''); Var2In.Enabled := (VarList.ItemIndex > -1) and (Var2Edit.Text = ''); Var1Out.Enabled := (Var1Edit.Text <> ''); Var2Out.Enabled := (Var2Edit.Text <> ''); end; end.