00001 using System;
00002 using System.Collections.Generic;
00003 using System.Linq;
00004
00005 namespace StephenAshley.Biostatistics
00006 {
00007 using NUMBER = Decimal;
00008
00015 public class MannWhitneyGroupsCollection : GroupsCollection
00016 {
00017 #region *** fields ***
00018 private Int32 iN, iN1, iN2;
00019
00020 private NUMBER decR1, decR2, decU;
00021
00022 Decimal? decSDt, decT, decZt, decZtUncorrected, decPt, decPtUncorrected;
00023
00024 private Boolean bInitialized;
00025
00026 private string sPt, sPtUncorrected;
00027 #endregion
00028
00032 public MannWhitneyGroupsCollection()
00033 : base()
00034 {
00035 bInitialized = false;
00036 }
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00054 public MannWhitneyGroupsCollection(List<Group> lstGroups)
00055 : base(lstGroups)
00056 {
00057 if (lstGroups.Count == 2)
00058 {
00059 Initialize();
00060 bInitialized = true;
00061 }
00062 else
00063 bInitialized = false;
00064 }
00065
00066 #region ***** methods ******
00076 public override void Add(Group group)
00077 {
00078 if (group == null)
00079 {
00080 throw new BiostatisticsException(
00081 "Addition of null Group to MannWhitneyGroupsCollection.");
00082 }
00083
00084 if (groupsArray == null || (groupsArray.Length < 2))
00085 base.Add(group);
00086 else
00087 throw new BiostatisticsException(
00088 "Addition of Group would result in MannWhitneyGroupsCollection with more than 2 Groups.");
00089 if (k() == 2)
00090 Initialize();
00091 }
00092
00103 public override void AddRange(List<Group> lstGroups)
00104 {
00105 if (lstGroups == null)
00106 {
00107 throw new BiostatisticsException(
00108 "lstGroups is a null reference.");
00109 }
00110
00111 if (groupsArray == null || (groupsArray.Length + lstGroups.Count <= 2))
00112 base.AddRange(lstGroups);
00113 else
00114 throw new BiostatisticsException(
00115 "Addition of a Group would result in a MannWhitneyGroupsCollection with more than 2 Groups.");
00116 if (groupsArray.Length == 2)
00117 Initialize();
00118 }
00119
00127 public Int32 N()
00128 {
00129 if (!bInitialized)
00130 throw new BiostatisticsException(
00131 "The MannWhitneyGroupsCollection must contain 2 Groups before N can be calculated.");
00132 return groupsArray[0].n() + groupsArray[1].n();
00133 }
00134
00142 public Int32 N1()
00143 {
00144 if (!bInitialized)
00145 throw new BiostatisticsException(
00146 "The MannWhitneyGroupsCollection must contain 2 Groups before N1 can be calculated.");
00147 return iN1;
00148 }
00149
00157 public Int32 N2()
00158 {
00159 if (!bInitialized)
00160 throw new BiostatisticsException(
00161 "The MannWhitneyGroupsCollection must contain 2 Groups before N2 can be calculated.");
00162 return iN2;
00163 }
00164
00172 public NUMBER R1()
00173 {
00174 if (!bInitialized)
00175 throw new BiostatisticsException(
00176 "The MannWhitneyGroupsCollection must contain 2 Groups before R1 can be calculated.");
00177 return decR1;
00178 }
00179
00187 public NUMBER R2()
00188 {
00189 if (!bInitialized)
00190 throw new BiostatisticsException(
00191 "The MannWhitneyGroupsCollection must contain 2 Groups before R2 can be calculated.");
00192 return decR2;
00193 }
00194
00202 public NUMBER? t()
00203 {
00204 if (!bInitialized)
00205 throw new BiostatisticsException(
00206 "The MannWhitneyGroupsCollection must contain 2 Groups before T can be calculated.");
00207 return decT;
00208 }
00209
00217 public NUMBER U()
00218 {
00219 if (!bInitialized)
00220 throw new BiostatisticsException(
00221 "The MannWhitneyGroupsCollection must contain 2 Groups before U can be calculated.");
00222 return decU;
00223 }
00224
00232 public NUMBER? Zt()
00233 {
00234 if (!bInitialized)
00235 throw new BiostatisticsException(
00236 "The MannWhitneyGroupsCollection must contain 2 Groups before Zt can be calculated.");
00237 return decZt;
00238 }
00239
00248 public NUMBER? ZtUncorrected()
00249 {
00250 if (!bInitialized)
00251 throw new BiostatisticsException(
00252 "The MannWhitneyGroupsCollection must contain 2 Groups before Zt can be calculated.");
00253 return decZtUncorrected;
00254 }
00255
00263 public NUMBER? pT()
00264 {
00265 if (!bInitialized)
00266 throw new BiostatisticsException(
00267 "The MannWhitneyGroupsCollection must contain 2 Groups before Pt can be calculated.");
00268 return decPt;
00269 }
00270
00278 public NUMBER? pTUncorrected()
00279 {
00280 if (!bInitialized)
00281 throw new BiostatisticsException(
00282 "The MannWhitneyGroupsCollection must contain 2 Groups before PtUncorrected can be calculated.");
00283 return decPtUncorrected;
00284 }
00285
00295 public string StringPt()
00296 {
00297 if (!bInitialized)
00298 throw new BiostatisticsException(
00299 "The MannWhitneyGroupsCollection must contain 2 Groups before StringPt can be calculated.");
00300 return sPt;
00301 }
00302
00310 public NUMBER? StandardDeviationT()
00311 {
00312 if (!bInitialized)
00313 throw new BiostatisticsException(
00314 "The MannWhitneyGroupsCollection must contain 2 Groups before StandardDeviationT can be calculated.");
00315 return decSDt;
00316 }
00317
00325 public NUMBER UPrime()
00326 {
00327 if (!bInitialized)
00328 throw new BiostatisticsException(
00329 "The MannWhitneyGroupsCollection must contain 2 Groups before UPrime can be calculated.");
00330 return groupsArray[0].n() * groupsArray[1].n() - U();
00331 }
00332
00333 #endregion
00334
00335 private void Initialize()
00336 {
00337 if (groupsArray == null || groupsArray[0] == null || groupsArray[0].n()
00338 == 0 || groupsArray[1] == null || groupsArray[1].n() == 0)
00339 throw new BiostatisticsException(
00340 "groupsArray in MannWhitneyGroupsCollection does not contain 2 Groups with a positive number of members.");
00341 iN1 = groupsArray[0].n();
00342 iN2 = groupsArray[1].n();
00343
00344 Int32 iNTemp;
00345
00346 List<Rank> lstRanks = new List<Rank>(iNTemp = groupsArray[0].n() +
00347 groupsArray[1].n());
00348 for (Int32 i = 0; i < groupsArray[0].n(); i++)
00349 lstRanks.Add(new Rank(0, groupsArray[0][i], 0));
00350 for (Int32 i = 0; i < groupsArray[1].n(); i++)
00351 lstRanks.Add(new Rank(1, groupsArray[1][i], 0));
00352
00353
00354 lstRanks.Sort(Rank.CompareRanks);
00355
00356
00357 for (Int32 i = 0; i < iNTemp; i++)
00358 lstRanks[i] = new Rank(
00359 lstRanks[i].iGroup,
00360 lstRanks[i].decValue,
00361 i + 1);
00362
00363
00364 Int32 iTieAdjustment = Rank.AdjustTies(ref lstRanks);
00365
00366 bInitialized = true;
00367
00368 List<Rank> lstGroup0 = new List<Rank>();
00369 List<Rank> lstGroup1 = new List<Rank>();
00370 foreach (Rank rank in lstRanks)
00371 {
00372 if (rank.iGroup == 0)
00373 lstGroup0.Add(rank);
00374 else
00375 lstGroup1.Add(rank);
00376 }
00377
00378
00379 decR1 = decR2 = 0.0m;
00380 foreach (Rank rank in lstRanks)
00381 if (rank.iGroup == 0)
00382 decR1 += rank.decRank;
00383 else
00384 decR2 += rank.decRank;
00385
00386
00387 decU = groupsArray[0].n() * groupsArray[1].n();
00388 decU += groupsArray[0].n() * (groupsArray[0].n() + 1) / 2.0m;
00389 decU -= decR1;
00390
00391 NUMBER dUPrime = iN1 * iN2 - decU;
00392 if (dUPrime > decU)
00393 {
00394 NUMBER dTemp = dUPrime;
00395 dUPrime = decU;
00396 decU = dTemp;
00397 }
00398
00399
00400 List<Rank> lstSmall, lstBig;
00401 Int32 iSmall, iBig;
00402 if (lstGroup1.Count() > lstGroup0.Count())
00403 {
00404 lstBig = lstGroup1;
00405 lstSmall = lstGroup0;
00406 }
00407 else
00408 {
00409 lstBig = lstGroup0;
00410 lstSmall = lstGroup1;
00411 }
00412 iBig = lstBig.Count();
00413 iSmall = lstSmall.Count();
00414
00415 decT = 0.0m;
00416 foreach (Rank rank in lstSmall)
00417 {
00418 decT += rank.decRank;
00419 }
00420
00421
00422 iN = iSmall + iBig;
00423
00424 NUMBER decMu = (NUMBER)(iSmall * (iN + 1))
00425 / 2.0m;
00426
00427 NUMBER decSigma = (iSmall * iBig * (iN + 1)) / 12.0m;
00428 decSigma -= (iSmall * iBig * iTieAdjustment) / (12.0m * N() * (N() - 1));
00429 decSigma = DecMath.Sqrt(decSigma);
00430 decSDt = decSigma;
00431
00432 decZt = (DecMath.Abs((NUMBER)decT - decMu) - 0.5m) / (Decimal)decSDt;
00433 decZtUncorrected = ((NUMBER)decT - decMu) / (NUMBER)decSDt;
00434
00435 decPt = (Distributions.ProbabilityZ((NUMBER)decZt));
00436 decPtUncorrected = Distributions.ProbabilityZ((NUMBER)decZtUncorrected);
00437
00438 sPt = decPt.ToString();
00439 sPtUncorrected = decPtUncorrected.ToString();
00440 char cWhichWay;
00441 if (iBig <= 8)
00442 {
00443 decSDt =
00444 decZt =
00445 decZtUncorrected = null;
00446 sPt =
00447 sPtUncorrected = null;
00448 cWhichWay = '>';
00449 switch (iSmall)
00450 {
00451 case 1:
00452 case 2:
00453 cWhichWay = '!';
00454 break;
00455
00456 case 3:
00457 switch (iBig)
00458 {
00459 case 3:
00460 cWhichWay = '!';
00461 break;
00462
00463 case 4:
00464 if ((decT <= 6) || (decT >= 18))
00465 cWhichWay = '<';
00466 break;
00467
00468 case 5:
00469 if ((decT <= 6) || (decT >= 21))
00470 cWhichWay = '<';
00471 break;
00472
00473 case 6:
00474 if ((decT <= 7) || (decT >= 23))
00475 cWhichWay = '<';
00476 break;
00477
00478 case 7:
00479 if ((decT <= 7) || (decT >= 26))
00480 cWhichWay = '<';
00481 break;
00482
00483 case 8:
00484 if ((decT <= 8) || (decT >= 28))
00485 cWhichWay = '<';
00486 break;
00487 }
00488 break;
00489
00490 case 4:
00491 switch (iBig)
00492 {
00493 case 4:
00494 if ((decT <= 11) || (decT >= 25))
00495 cWhichWay = '<';
00496 break;
00497
00498 case 5:
00499 if ((decT <= 12) || (decT >= 28))
00500 cWhichWay = '<';
00501 break;
00502
00503 case 6:
00504 if ((decT <= 12) || (decT >= 32))
00505 cWhichWay = '<';
00506 break;
00507
00508 case 7:
00509 if ((decT <= 13) || (decT >= 35))
00510 cWhichWay = '<';
00511 break;
00512
00513 case 8:
00514 if ((decT <= 14) || (decT >= 38))
00515 cWhichWay = '<';
00516 break;
00517 }
00518 break;
00519
00520 case 5:
00521 switch (iBig)
00522 {
00523 case 5:
00524 if ((decT <= 18) || (decT >= 37))
00525 cWhichWay = '<';
00526 break;
00527
00528 case 6:
00529 if ((decT <= 19) || (decT >= 41))
00530 cWhichWay = '<';
00531 break;
00532
00533 case 7:
00534 if ((decT <= 20) || (decT >= 45))
00535 cWhichWay = '<';
00536 break;
00537
00538 case 8:
00539 if ((decT <= 21) || (decT >= 49))
00540 cWhichWay = '<';
00541 break;
00542 }
00543 break;
00544
00545 case 6:
00546 switch (iBig)
00547 {
00548 case 6:
00549 if ((decT <= 26) || (decT >= 52))
00550 cWhichWay = '<';
00551 break;
00552
00553 case 7:
00554 if ((decT <= 28) || (decT >= 56))
00555 cWhichWay = '<';
00556 break;
00557
00558 case 8:
00559 if ((decT <= 30) || (decT >= 60))
00560 cWhichWay = '<';
00561 break;
00562 }
00563 break;
00564
00565 case 7:
00566 switch (iBig)
00567 {
00568 case 7:
00569 if ((decT <= 37) || (decT >= 68))
00570 cWhichWay = '<';
00571 break;
00572
00573 case 8:
00574 if ((decT <= 39) || (decT >= 73))
00575 cWhichWay = '<';
00576 break;
00577 }
00578 break;
00579
00580 case 8:
00581 if ((decT <= 49) || (decT >= 87))
00582 cWhichWay = '<';
00583 break;
00584 }
00585
00586 switch (cWhichWay)
00587 {
00588 case '!':
00589 sPt = "Sample size too small to reach statistical significance.";
00590 break;
00591
00592 case '<':
00593 sPt = "p < 0.06";
00594 break;
00595
00596 case '>':
00597 sPt = "P > 0.06";
00598 break;
00599 }
00600 }
00601 bInitialized = true;
00602 }
00603 }
00604 }