00001 using System;
00002 using System.Collections.Generic;
00003 using System.Linq;
00004 using System.Text;
00005 using System.Windows.Forms;
00006
00007 namespace StephenAshley.Biostatistics
00008 {
00009 using NUMBER = Decimal;
00010
00018 public class FriedmanGroupsCollection : GroupsCollection
00019 {
00023 public FriedmanGroupsCollection() : base() { }
00024
00030 public FriedmanGroupsCollection(List<Group> groups) : base(groups) { }
00031
00041 public override void Add(Group group)
00042 {
00043 if (group == null)
00044 throw new BiostatisticsException(
00045 "group is a null reference.");
00046
00047 if (group.n() == 0)
00048 throw new BiostatisticsException(
00049 "group has no members.");
00050
00051 if (groupsArray != null && k() > 0)
00052 {
00053 for (int i = 0; i < k(); i++)
00054 {
00055 if (group.n() != groupsArray[i].n())
00056 throw new BiostatisticsException(
00057 "Group size does not match size of other Groups.");
00058 }
00059 }
00060
00061 base.Add(group);
00062 return;
00063 }
00064
00072 public Int32 DegreesOfFreedom()
00073 {
00074 if (groupsArray == null)
00075 throw new BiostatisticsException(
00076 "FriedmanGroupsCollection contains no Groups.");
00077
00078 return k() - 1;
00079 }
00080
00092 public NUMBER FriedmanStatistic()
00093 {
00094 if (N() < 2)
00095 throw new BiostatisticsException(
00096 "FriedmanGroupsClass contains fewer than two subjects.");
00097
00098 if (k() < 2)
00099 throw new BiostatisticsException(
00100 "FriedmanGroupsCollection has fewer than two treatments.");
00101
00102 NUMBER decA = 0.0m;
00103 foreach (NUMBER value in SumsOfRanks())
00104 decA += value * value;
00105
00106 NUMBER decB = N() * k() * (k() + 1);
00107
00108 NUMBER decC = 12.0m / decB;
00109 NUMBER decD = decA * decC;
00110 NUMBER decE = 3.0m * N() * (k() + 1);
00111 NUMBER decF = decD - decE;
00112 NUMBER decG = 1 - (NUMBER)SumOfTaus() / (NUMBER)(N() * k() * (k() * k() - 1));
00113 NUMBER decResult = decF / decG;
00114 return decResult;
00115 }
00116
00138 public NUMBER CriticalValue()
00139 {
00140 if (N() < 2)
00141 throw new BiostatisticsException(
00142 "FriedmanGroupsClass contains fewer than two subjects.");
00143
00144 if (k() < 2)
00145 throw new BiostatisticsException(
00146 "FriedmanGroupsCollection has fewer than two treatments.");
00147
00148 if (k() < 3 || k() > 6)
00149 throw new BiostatisticsException(
00150 "k is outside the range of the critical values table.");
00151
00152 if (N() > 15)
00153 throw new BiostatisticsException(
00154 "N is outside the range of the critical values table.");
00155
00156 if (k() > 4 && N() > 10)
00157 throw new BiostatisticsException(
00158 "N is outside the range of the critical values table.");
00159
00160 NUMBER decFriedman = FriedmanStatistic();
00161 ChiAlpha chiAlpha = GetLowestEntry(k(), N());
00162 if (decFriedman < chiAlpha.Chi)
00163 throw new BiostatisticsException("p > " +
00164 chiAlpha.Alpha.ToString());
00165
00166 chiAlpha = GetHighestEntry(k(), N());
00167
00168 if (decFriedman >= chiAlpha.Chi)
00169 return chiAlpha.Alpha;
00170
00171 chiAlpha = GetClosestEntry(k(), N(), FriedmanStatistic());
00172
00173 return chiAlpha.Alpha;
00174 }
00175
00180 public Int32 N()
00181 {
00182 if (groupsArray == null) return 0;
00183 else
00184 return groupsArray[0].n();
00185 }
00186
00196 public NUMBER p()
00197 {
00198 return (NUMBER)Distributions.ProbabilityChiSq((double)FriedmanStatistic(),
00199 DegreesOfFreedom());
00200 }
00209 public NUMBER[] SumsOfRanks()
00210 {
00211 if (groupsArray == null)
00212 throw new BiostatisticsException(
00213 "FriedmanGroupsCollection contains no Groups.");
00214
00215 Rank[,] ranksArray = new Rank[k(), N()];
00216
00217
00218
00219 for (int iTreatment = 0; iTreatment < k(); iTreatment++)
00220 {
00221 for (int iSubject = 0; iSubject < N(); iSubject++)
00222 {
00223 ranksArray[iTreatment, iSubject] = new Rank(iTreatment,
00224 groupsArray[iTreatment][iSubject], 0.0m);
00225 }
00226 }
00227
00228
00229 List<Rank> lstRanks = new List<Rank>(k());
00230 for (int iSubject = 0; iSubject < N(); iSubject++)
00231 {
00232 for (int iTreatment = 0; iTreatment < k(); iTreatment++)
00233 {
00234 lstRanks.Add(ranksArray[iTreatment, iSubject]);
00235 }
00236 lstRanks.Sort(Rank.CompareRanks);
00237 for (Int32 i = 0; i < k(); i++)
00238 lstRanks[i] = new Rank(lstRanks[i].iGroup,
00239 lstRanks[i].decValue, (NUMBER)(i + 1));
00240 Rank.AdjustTies(ref lstRanks);
00241
00242
00243 for (int iTreatment = 0; iTreatment < k(); iTreatment++)
00244 {
00245 for (int i = 0; i < k(); i++)
00246 {
00247 if (ranksArray[iTreatment, iSubject].decValue ==
00248 lstRanks[i].decValue)
00249 {
00250 ranksArray[iTreatment, iSubject].decRank =
00251 lstRanks[i].decRank;
00252 break;
00253 }
00254 }
00255 }
00256 lstRanks.Clear();
00257 }
00258
00259
00260 NUMBER[] returnArray = new NUMBER[k()];
00261 for (int iTreatment = 0; iTreatment < k(); iTreatment++)
00262 returnArray[iTreatment] = 0.0m;
00263
00264 for (int iTreatment = 0; iTreatment < k(); iTreatment++)
00265 for (int iSubject = 0; iSubject < N(); iSubject++)
00266 returnArray[iTreatment] += ranksArray[iTreatment, iSubject].decRank;
00267
00268 return returnArray;
00269 }
00270
00271 private Int32 SumOfTaus()
00272 {
00273 if (groupsArray == null)
00274 throw new BiostatisticsException(
00275 "FriedmanGroupsCollection contains no Groups.");
00276
00277 Rank[,] ranksArray = new Rank[k(), N()];
00278 Int32[] tiesArray = new Int32[N()];
00279
00280
00281
00282 for (int iTreatment = 0; iTreatment < k(); iTreatment++)
00283 {
00284 for (int iSubject = 0; iSubject < N(); iSubject++)
00285 {
00286 ranksArray[iTreatment, iSubject] = new Rank(iTreatment,
00287 groupsArray[iTreatment][iSubject], 0.0m);
00288 }
00289 }
00290
00291
00292 List<Rank> lstRanks = new List<Rank>(k());
00293 for (int iSubject = 0; iSubject < N(); iSubject++)
00294 {
00295 for (int iTreatment = 0; iTreatment < k(); iTreatment++)
00296 {
00297 lstRanks.Add(ranksArray[iTreatment, iSubject]);
00298 }
00299 lstRanks.Sort(Rank.CompareRanks);
00300 tiesArray[iSubject] = Rank.AdjustTies(ref lstRanks);
00301 lstRanks.Clear();
00302 }
00303 return tiesArray.Sum();
00304 }
00305
00306 private ChiAlpha GetLowestEntry(Int32 iTreatmentCount, Int32 iSubjectCount)
00307 {
00308 Int32 iRow = 0;
00309 Int32 iEntry = 2;
00310
00311
00312 while (true)
00313 {
00314 Int32 iA = (Int32)CriticalValues[iRow, 0];
00315 if (iA == iTreatmentCount)
00316 break;
00317 else
00318 iRow++;
00319 }
00320 while (true)
00321 {
00322 Int32 iB = (Int32)CriticalValues[iRow, 1];
00323 if (iB == iSubjectCount)
00324 break;
00325 else
00326 iRow++;
00327 }
00328
00329
00330 while (true)
00331 {
00332 NUMBER? decEntry = CriticalValues[iRow, iEntry];
00333 if (decEntry == null)
00334 iEntry++;
00335 else
00336 break;
00337 }
00338
00339 return new ChiAlpha((NUMBER)CriticalValues[iRow, iEntry], alphas[iEntry]);
00340 }
00341
00342 private ChiAlpha GetHighestEntry(Int32 iTreatmentCount, Int32 iSubjectCount)
00343 {
00344 Int32 iRow = 0;
00345 Int32 iEntry = 10;
00346
00347
00348 while (true)
00349 {
00350 Int32 iA = (Int32)CriticalValues[iRow, 0];
00351 if (iA == iTreatmentCount)
00352 break;
00353 else
00354 iRow++;
00355 }
00356 while (true)
00357 {
00358 Int32 iB = (Int32)CriticalValues[iRow, 1];
00359 if (iB == iSubjectCount)
00360 break;
00361 else
00362 iRow++;
00363 }
00364
00365
00366 while (true)
00367 {
00368 NUMBER? decEntry = CriticalValues[iRow, iEntry];
00369 if (decEntry == null)
00370 iEntry--;
00371 else
00372 break;
00373 }
00374
00375 return new ChiAlpha((NUMBER)CriticalValues[iRow, iEntry], alphas[iEntry]);
00376 }
00377
00378 private ChiAlpha GetClosestEntry(Int32 iTreatmentCount, Int32 iSubjectCount,
00379 NUMBER decFriedmanStatistic)
00380 {
00381 Int32 iRow = 0;
00382
00383
00384 while (true)
00385 {
00386 Int32 iA = (Int32)CriticalValues[iRow, 0];
00387 if (iA == iTreatmentCount)
00388 break;
00389 else
00390 iRow++;
00391 }
00392 while (true)
00393 {
00394 Int32 iB = (Int32)CriticalValues[iRow, 1];
00395 if (iB == iSubjectCount)
00396 break;
00397 else
00398 iRow++;
00399 }
00400
00401 Int32 i = 2;
00402 NUMBER decResult = 0.0m;
00403 NUMBER decAlpha = 0.0m;
00404 bool[] boolArray = new bool[9];
00405 for (; i < 11; i++)
00406 {
00407 if (CriticalValues[iRow, i] != null
00408 && decFriedmanStatistic >= CriticalValues[iRow, i])
00409 boolArray[i-2] = true;
00410 else
00411 boolArray[i-2] = false;
00412 }
00413 for (int j = 10; j > 1; j--)
00414 {
00415 if (boolArray[j - 2])
00416 {
00417 decResult = (NUMBER)CriticalValues[iRow, j];
00418 decAlpha = alphas[j];
00419 break;
00420 }
00421 }
00422 ChiAlpha chiAlpha = new ChiAlpha(decResult, decAlpha);
00423 return chiAlpha;
00424 }
00425
00426 private readonly NUMBER?[,] CriticalValues =
00427 {
00428 {3.0m, 2.0m, 3.0m, 4.0m, null, null, null, null, null, null, null},
00429 {3.0m, 3.0m, 2.667m, 4.667m, null, 6.0m, null, null, null, null, null},
00430 {3.0m, 4.0m, 2.0m, 4.5m, 6.0m, 6.5m, null, null, 8.0m, null, null},
00431 {3.0m, 5.0m, 2.8m, 3.6m, 5.2m, 6.4m, null, 8.4m, null, null, 10.0m},
00432 {3.0m, 6.0m, 2.33m, 4.0m, 5.33m, 7.0m, 8.33m, 9.0m, null, 10.33m, 12.0m},
00433 {3.0m, 7.0m, 2.0m, 3.714m, 5.429m, 7.143m, 8.0m, 8.857m, 10.286m, 11.143m, 12.286m},
00434 {3.0m, 8.0m, 2.25m, 4.0m, 5.25m, 6.25m, 7.75m, 9.0m, 9.75m, 12.0m, 12.25m},
00435 {3.0m, 9.0m, 2.0m, 3.556m, 5.556m, 6.222m, 8.0m, 9.556m, 10.667m, 11.556m, 12.667m},
00436 {3.0m, 10.0m, 1.8m, 3.8m, 5m, 6.2m, 7.8m, 9.6m, 10.4m, 12.2m, 12.6m},
00437 {3.0m, 11.0m, 1.636m, 3.818m, 4.909m, 6.545m, 7.818m, 9.455m, 10.364m, 11.636m, 13.273m},
00438 {3.0m, 12.0m, 1.5m, 3.5m, 5.167m, 6.167m, 8.0m, 9.5m, 10.167m, 12.167m, 12.5m},
00439 {3.0m, 13.0m, 1.846m, 3.846m, 4.769m, 6.0m, 8.0m, 9.385m, 10.308m, 11.538m, 12.923m},
00440 {3.0m, 14.0m, 1.714m, 3.571m, 5.143m, 6.143m, 8.143m, 9.0m, 10.426m, 42.0m, 13.286m},
00441 {3.0m, 15.0m, 1.733m, 3.6m, 4.933m, 6.4m, 8.133m, 8.933m, 10.0m, 12.133m, 12.933m},
00442 {4.0m, 2.0m, 3.6m, 5.4m, null, 6.0m, null, null, null, null, null},
00443 {4.0m, 3.0m, 3.4m, 5.4m, 6.6m, 7.4m, 8.2m, 9.0m, null, 9.0m, null},
00444 {4.0m, 4.0m, 3.0m, 4.8m, 6.3m, 7.8m, 8.4m, 9.6m, null, 10.2m, 11.1m},
00445 {4.0m, 5.0m, 3.0m, 5.16m, 6.36m, 7.8m, 9.24m, 9.96m, 10.92m, 11.64m, 12.6m},
00446 {4.0m, 6.0m, 3.0m, 4.8m, 6.4m, 7.6m, 9.4m, 10.2m, 11.4m, 12.2m, 12.8m},
00447 {4.0m, 7.0m, 2.829m, 4.886m, 6.429m, 7.8m, 9.343m, 10.371m, 11.4m, 12.771m, 13.8m},
00448 {4.0m, 8.0m, 2.55m, 4.8m, 6.3m, 7.65m, 9.45m, 10.35m, 11.85m, 12.9m, 13.8m},
00449 {4.0m, 9.0m, null, null, 6.467m, 7.8m, 9.133m, 10.867m, 12.067m, null, 14.467m},
00450 {4.0m, 10.0m, null, null, 6.36m, 7.8m, 9.12m, 10.8m, 12.0m, null, 14.640m},
00451 {4.0m, 11.0m, null, null, 6.382m, 7.909m, 9.327m, 11.073m, 12.273m, null, 14.891m},
00452 {4.0m, 12.0m, null, null, 6.4m, 7.9m, 9.2m, 11.1m, 12.3m, null, 15.0m},
00453 {4.0m, 13.0m, null, null, 6.415m, 7.965m, 7.369m, 11.123m, 12.323m, null, 15.277m},
00454 {4.0m, 14.0m, null, null, 6.343m, 7.386m, 9.343m, 11.143m, 12.514m, null, 15.257m},
00455 {4.0m, 15.0m, null, null, 6.440m, 8.040m, 9.4m, 11.24m, 12.52m, null, 15.4m},
00456 {5.0m, 2.0m, null, null, 7.2m, 7.6m, 8.0m, 8.0m, null, null, null},
00457 {5.0m, 3.0m, null, null, 7.467m, 8.533m, 9.6m, 10.133m, 10.667m, null, 11.467m},
00458 {5.0m, 4.0m, null, null, 7.6m, 8.8m, 9.5m, 11.2m, 12.0m, null, 13.2m},
00459 {5.0m, 5.0m, null, null, 7.68m, 8.96m, 10.24m, 11.68m, 12.48m, null, 14.4m},
00460 {5.0m, 6.0m, null, null, 7.733m, 9.067m, 10.4m, 11.867m, 13.067m, null, 15.2m},
00461 {5.0m, 7.0m, null, null, 7.771m, 9.143m, 10.514m, 12.114m, 13.257m, null, 15.657m},
00462 {5.0m, 8.0m, null, null, 7.8m, 9.3m, 10.6m, 12.3m, 13.5m, null, 16.0m},
00463 {5.0m, 9.0m, null, null, 7.733m, 9.244m, 10.667m, 12.444m, 13.689m, null, 16.356m},
00464 {5.0m, 10.0m, null, null, 7.76m, 9.28m, 10.72m, 12.48m, 13.48m, null, 16.48m},
00465 {6.0m, 2.0m, null, null, 8.286m, 9.143m, 9.429m, 9.714m, 10.0m, null, null},
00466 {6.0m, 3.0m, null, null, 8.714m, 9.857m, 10.81m, 11.762m, 12.524m, null, 13.286m},
00467 {6.0m, 4.0m, null, null, 9.0m, 10.286m, 11.429m, 12.712m, 13.571m, null, 15.286m},
00468 {6.0m, 5.0m, null, null, 9.0m, 10.486m, 11.743m, 13.229m, 14.257m, null, 16.429m},
00469 {6.0m, 6.0m, null, null, 9.048m, 10.571m, 12.0m, 13.619m, 14.762m, null, 17.048m},
00470 {6.0m, 7.0m, null, null, 9.122m, 10.674m, 12.061m, 13.857m, 15.0m, null, 17.612m},
00471 {6.0m, 8.0m, null, null, 9.143m, 10.714m, 12.214m, 14.0m, 15.286m, null, 18.0m},
00472 {6.0m, 9.0m, null, null, 9.127m, 10.778m, 12.302m, 14.143m, 15.476m, null, 18.27m},
00473 {6.0m, 10m, null, null, 9.143m, 10.8m, 12.343m, 14.299m, 15.6m, null, 18.514m}
00474 };
00475
00476 private readonly NUMBER[] alphas =
00477 {
00478 0.0m, 0.0m, 0.5m, 0.2m, 0.1m, 0.05m, 0.02m, 0.01m, 0.005m, 0.002m, 0.001m
00479 };
00480
00481
00482 }
00483
00484 struct ChiAlpha
00485 {
00486 public NUMBER Chi;
00487 public NUMBER Alpha;
00488
00489 public ChiAlpha(NUMBER decX, NUMBER decY)
00490 {
00491 Chi = decX;
00492 Alpha = decY;
00493 }
00494 }
00495 }