From af63896d528d9ab3014a99f4362a45a9ec0f771f Mon Sep 17 00:00:00 2001 From: wp_xxyyzz Date: Mon, 26 Oct 2020 17:25:06 +0000 Subject: [PATCH] LazStats: Minor refactoring of MannWhitUUnit git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@7813 8e941d3f-bd1b-0410-a28a-d453659cc2b4 --- .../analysis/nonparametric/mannwhituunit.pas | 240 ++++++++---------- 1 file changed, 112 insertions(+), 128 deletions(-) diff --git a/applications/lazstats/source/forms/analysis/nonparametric/mannwhituunit.pas b/applications/lazstats/source/forms/analysis/nonparametric/mannwhituunit.pas index c2b1a39e1..e39ce89b5 100644 --- a/applications/lazstats/source/forms/analysis/nonparametric/mannwhituunit.pas +++ b/applications/lazstats/source/forms/analysis/nonparametric/mannwhituunit.pas @@ -53,7 +53,7 @@ implementation uses Math, - Utils; + Utils, MatrixUnit, GridProcs; { TMannWhitUForm } @@ -74,17 +74,15 @@ var Ranks: DblDyneMat = nil; X: DblDyneMat = nil; RankSums: DblDyneVec = nil; - i, j, ind_var, dep_var, min_grp, max_grp, group, total_n : integer; - NoTies, NoTieGroups, n1, n2, nogroups, largestn : integer; - NoSelected : integer; - TieSum, score, t, SumT, Avg, z, prob, U, U2, SD, Temp : double; - cellstring, outline : string; + i, j, ind_var, dep_var, min_grp, max_grp, group, total_n: integer; + NoTies, NoTieGroups, n1, n2, nogroups, largestn: integer; + TieSum, score, t, SumT, Avg, z, prob, U, U2, SD: double; + outline: string; lReport: TStrings; begin total_n := 0; NoTieGroups := 0; - NoSelected := 2; SumT := 0.0; // Check for data @@ -94,38 +92,30 @@ begin exit; end; - // allocate space - SetLength(ColNoSelected, NoVariables); - // Get column numbers of the independent and dependent variables - ind_var := 0; - dep_var := 0; - for i := 1 to NoVariables do - begin - cellstring := GrpEdit.Text; - if (cellstring = OS3MainFrm.DataGrid.Cells[i,0]) then ind_var := i; - cellstring := DepEdit.Text; - if (cellstring = OS3MainFrm.DataGrid.Cells[i,0]) then dep_var := i; - end; - ColNoSelected[0] := ind_var; - ColNoSelected[1] := dep_var; - if ind_var = 0 then + ind_var := GetVariableIndex(OS3MainFrm.DataGrid, GrpEdit.Text); + dep_var := GetVariableIndex(OS3MainFrm.DataGrid, DepEdit.Text); + if ind_var = -1 then begin ErrorMsg('No group variable.'); exit; end; - if dep_var = 0 then + if dep_var = -1 then begin ErrorMsg('No dependent variable.'); exit; end; + SetLength(ColNoSelected, 2); + ColNoSelected[0] := ind_var; + ColNoSelected[1] := dep_var; + //get minimum and maximum group codes min_grp := MaxInt; max_grp := -MaxInt; for i := 1 to NoCases do begin - if (not GoodRecord(i, NoSelected, ColNoSelected)) then continue; + if (not GoodRecord(OS3MainFrm.DataGrid, i, ColNoSelected)) then continue; group := round(StrToFloat(Trim(OS3MainFrm.DataGrid.Cells[ind_var,i]))); if (group < min_grp) then min_grp := group; if (group > max_grp) then max_grp := group; @@ -144,121 +134,115 @@ begin RankSums[i] := 0.0; end; + // Get data + for i := 1 to NoCases do + begin + if (not GoodRecord(OS3mainFrm.DataGrid, i, ColNoSelected)) then continue; + score := StrToFloat(Trim(OS3MainFrm.DataGrid.Cells[dep_var,i])); + group := round(StrToFloat(Trim(OS3MainFrm.DataGrid.Cells[ind_var,i]))); + group := group - min_grp + 1; + if (group > 2) then + begin + ErrorMsg('Group codes must be 1 and 2!'); + exit; + end; + group_count[group-1] := group_count[group-1] + 1; + X[i-1, 0] := score; + X[i-1, 1] := group; + end; + + // Sort all scores in ascending order + for i := 1 to total_n - 1 do + begin + for j := i + 1 to total_n do + begin + if (X[i-1,0] > X[j-1,0]) then + begin + Exchange(X[i-1, 0], X[j-1, 0]); + Exchange(X[i-1, 1], X[j-1, 1]); + end; + end; + end; + + // Store ranks + for i := 0 to total_n-1 do + begin + Ranks[i, 0] := i+1; + Ranks[i, 1] := X[i, 1]; + end; + + // Check for ties in ranks - replace with average rank and calculate + // T for each tie and sum of the T's + i := 1; + while i < total_n do + begin + j := i + 1; + TieSum := 0; + NoTies := 0; + while (j < total_n) do + begin + if (X[j-1,0] > X[i-1,0]) then + break; + if (X[j-1,0] = X[i-1,0]) then // match + begin + TieSum := TieSum + round(Ranks[j-1,0]); + NoTies := NoTies + 1; + end; + j := j + 1; + end; + + if (NoTies > 0) then //At least one tie found + begin + TieSum := TieSum + Ranks[i-1,0]; + NoTies := NoTies + 1; + Avg := TieSum / NoTies; + for j := i to i + NoTies - 1 do Ranks[j-1,0] := Avg; + t := Power(NoTies,3) - NoTies; + SumT := SumT + t; + NoTieGroups := NoTieGroups + 1; + i := i + (NoTies - 1); + end; + i := i + 1; + end; // next i + + // Calculate sum of ranks in each group + for i := 0 to total_n-1 do + begin + group := round(Ranks[i, 1]); + RankSums[group-1] := RankSums[group-1] + Ranks[i, 0]; + end; + + // Calculate U for larger and smaller groups + n1 := group_count[0]; + n2 := group_count[1]; + if (n1 > n2) then + U := n1 * n2 + n1 * (n1 + 1) / 2.0 - RankSums[0] + else + U := n1 * n2 + n2 * (n2 + 1) / 2.0 - RankSums[1]; + U2 := n1 * n2 - U; + SD := n1 * n2 * (n1 + n2 + 1) / 12.0; + SD := sqrt(SD); + if (U2 > U) then + z := (U2 - n1 * n2 / 2) / SD + else + z := (U - n1 * n2 / 2) / SD; + prob := 1.0 - probz(z); + // Setup for printer output lReport := TStringList.Create; try lReport.Add('MANN-WHITNEY U TEST'); lReport.Add('See pages 116-127 in S. Siegel: Nonparametric Statistics for the Behavioral Sciences'); lReport.Add(''); - - // Get data - for i := 1 to NoCases do - begin - if (not GoodRecord(i,NoSelected,ColNoSelected)) then continue; - score := StrToFloat(Trim(OS3MainFrm.DataGrid.Cells[dep_var,i])); - group := round(StrToFloat(Trim(OS3MainFrm.DataGrid.Cells[ind_var,i]))); - group := group - min_grp + 1; - if (group > 2) then - begin - ErrorMsg('Group codes must be 1 and 2!'); - exit; - end; - group_count[group-1] := group_count[group-1] + 1; - X[i-1,0] := score; - X[i-1,1] := group; - end; - - // Sort all scores in ascending order - for i := 1 to total_n - 1 do - begin - for j := i + 1 to total_n do - begin - if (X[i-1,0] > X[j-1,0]) then - begin - Temp := X[i-1,0]; - X[i-1,0] := X[j-1,0]; - X[j-1,0] := Temp; - Temp := X[i-1,1]; - X[i-1,1] := X[j-1,1]; - X[j-1,1] := Temp; - end; - end; - end; - - // Store ranks - for i := 1 to total_n do - begin - Ranks[i-1,0] := i; - Ranks[i-1,1] := X[i-1,1]; - end; - - // Check for ties in ranks - replace with average rank and calculate - // T for each tie and sum of the T's - i := 1; - while i < total_n do - begin - j := i + 1; - TieSum := 0; - NoTies := 0; - while (j < total_n) do - begin - if (X[j-1,0] > X[i-1,0]) then - break; - if (X[j-1,0] = X[i-1,0]) then // match - begin - TieSum := TieSum + round(Ranks[j-1,0]); - NoTies := NoTies + 1; - end; - j := j + 1; - end; - - if (NoTies > 0) then //At least one tie found - begin - TieSum := TieSum + Ranks[i-1,0]; - NoTies := NoTies + 1; - Avg := TieSum / NoTies; - for j := i to i + NoTies - 1 do Ranks[j-1,0] := Avg; - t := Power(NoTies,3) - NoTies; - SumT := SumT + t; - NoTieGroups := NoTieGroups + 1; - i := i + (NoTies - 1); - end; - i := i + 1; - end; // next i - - // Calculate sum of ranks in each group - for i := 1 to total_n do - begin - group := round(Ranks[i-1,1]); - RankSums[group-1] := RankSums[group-1] + Ranks[i-1,0]; - end; - - // Calculate U for larger and smaller groups - n1 := group_count[0]; - n2 := group_count[1]; - if (n1 > n2) then - U := n1 * n2 + n1 * (n1 + 1) / 2.0 - RankSums[0] - else - U := n1 * n2 + n2 * (n2 + 1) / 2.0 - RankSums[1]; - U2 := n1 * n2 - U; - SD := n1 * n2 * (n1 + n2 + 1) / 12.0; - SD := sqrt(SD); - if (U2 > U) then - z := (U2 - n1 * n2 / 2) / SD - else - z := (U - n1 * n2 / 2) / SD; - prob := 1.0 - probz(z); - - // Report results lReport.Add(' Score Rank Group'); lReport.Add(''); - for i := 1 to total_n do - lReport.Add('%10.2f %10.2f %10.0f', [X[i-1,0], Ranks[i-1,0], Ranks[i-1,1]]); + for i := 0 to total_n-1 do + lReport.Add('%10.2f %10.2f %10.0f', [X[i,0], Ranks[i,0], Ranks[i,1]]); lReport.Add(''); lReport.Add('Sum of Ranks in each Group'); lReport.Add('Group Sum No. in Group'); - for i := 1 to nogroups do - lReport.Add('%3d %10.2f %5d', [i+min_grp-1, RankSums[i-1], group_count[i-1]]); + for i := 0 to noGroups-1 do + lReport.Add('%3d %10.2f %5d', [i+min_grp, RankSums[i], group_count[i]]); lReport.Add(''); lReport.Add('No. of tied rank groups: %10d', [NoTieGroups]); if (n1 > n2) then