Geen omschrijving
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

MeasurementsStatistics.cs 5.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. using System;
  2. using System.Collections.Generic;
  3. namespace Unity.PerformanceTesting.Statistics
  4. {
  5. /// <summary>
  6. /// Provides basic measurement statistics calculated for a sample collection.
  7. /// </summary>
  8. readonly ref struct MeasurementsStatistics
  9. {
  10. /// <summary>
  11. /// Mean of the samples.
  12. /// </summary>
  13. public double Mean { get; }
  14. /// <summary>
  15. /// Margin of error within the requested confidence interval.
  16. /// </summary>
  17. public double MarginOfError { get; }
  18. MeasurementsStatistics(double mean, double marginOfError)
  19. {
  20. Mean = mean;
  21. MarginOfError = marginOfError;
  22. }
  23. /// <summary>
  24. /// Calculates basic measurement statistics for a sample collection.
  25. /// </summary>
  26. /// <param name="measurements">The sample collection.</param>
  27. /// <param name="outlierMode">Outlier removal mode.</param>
  28. /// <param name="confidenceLevel">Confidence interval for calculating the margin of error.</param>
  29. /// <returns>A MeasurementStatistics instance calculated for the provided data.</returns>
  30. /// <exception cref="InvalidOperationException">Thrown if the sample count is zero.</exception>
  31. public static MeasurementsStatistics Calculate(List<double> measurements, OutlierMode outlierMode, ConfidenceLevel confidenceLevel)
  32. {
  33. var n = measurements.Count;
  34. if (n == 0)
  35. throw new InvalidOperationException("Requesting statistic measurements of a sequence which contains no elements.");
  36. double sum;
  37. double mean;
  38. double variance;
  39. double standardDeviation;
  40. double standardError;
  41. double marginOfError;
  42. if (outlierMode == OutlierMode.DontRemove)
  43. {
  44. sum = Sum(measurements);
  45. mean = sum / n;
  46. variance = Variance(measurements, n, mean);
  47. standardDeviation = Math.Sqrt(variance);
  48. standardError = standardDeviation / Math.Sqrt(n);
  49. marginOfError = n <= 2 ? double.NaN : standardError * confidenceLevel.GetZValue(n);
  50. return new MeasurementsStatistics(mean, marginOfError);
  51. }
  52. measurements.Sort();
  53. double q1, q3;
  54. if (n == 1)
  55. q1 = q3 = measurements[0];
  56. else
  57. {
  58. q1 = GetQuartile(measurements, measurements.Count / 2);
  59. q3 = GetQuartile(measurements, measurements.Count * 3 / 2);
  60. }
  61. var interquartileRange = q3 - q1;
  62. var lowerFence = q1 - 1.5 * interquartileRange;
  63. var upperFence = q3 + 1.5 * interquartileRange;
  64. SumWithoutOutliers(outlierMode, measurements, lowerFence, upperFence, out sum, out n);
  65. mean = sum / n;
  66. variance = VarianceWithoutOutliers(outlierMode, measurements, n, mean, lowerFence, upperFence);
  67. standardDeviation = Math.Sqrt(variance);
  68. standardError = standardDeviation / Math.Sqrt(n);
  69. marginOfError = n <= 2 ? double.NaN : standardError * confidenceLevel.GetZValue(n);
  70. return new MeasurementsStatistics(mean, marginOfError);
  71. }
  72. static double Sum(List<double> measurements)
  73. {
  74. var sum = 0d;
  75. foreach (var m in measurements)
  76. {
  77. sum += m;
  78. }
  79. return sum;
  80. }
  81. static void SumWithoutOutliers(OutlierMode outlierMode, List<double> measurements,
  82. double lowerFence, double upperFence, out double sum, out int n)
  83. {
  84. sum = 0;
  85. n = 0;
  86. foreach (var m in measurements)
  87. {
  88. if (!IsOutlier(outlierMode, m, lowerFence, upperFence))
  89. {
  90. sum += m;
  91. ++n;
  92. }
  93. }
  94. }
  95. static double Variance(List<double> measurements, int n, double mean)
  96. {
  97. if (n == 1)
  98. {
  99. return 0;
  100. }
  101. double variance = 0;
  102. foreach (var m in measurements)
  103. {
  104. variance += (m - mean) * (m - mean) / (n - 1);
  105. }
  106. return variance;
  107. }
  108. static double VarianceWithoutOutliers(OutlierMode outlierMode, List<double> measurements, int n, double mean, double lowerFence, double upperFence)
  109. {
  110. if (n == 1)
  111. {
  112. return 0;
  113. }
  114. double variance = 0;
  115. foreach (var m in measurements)
  116. {
  117. if (!IsOutlier(outlierMode, m, lowerFence, upperFence))
  118. {
  119. variance += (m - mean) * (m - mean) / (n - 1);
  120. }
  121. }
  122. return variance;
  123. }
  124. static double GetQuartile(List<double> measurements, int count)
  125. {
  126. if (count % 2 == 0)
  127. {
  128. return (measurements[count / 2 - 1] + measurements[count / 2]) / 2;
  129. }
  130. return measurements[count / 2];
  131. }
  132. static bool IsOutlier(OutlierMode outlierMode, double value, double lowerFence, double upperFence)
  133. {
  134. switch (outlierMode)
  135. {
  136. case OutlierMode.DontRemove:
  137. return false;
  138. case OutlierMode.Remove:
  139. return value < lowerFence || value > upperFence;
  140. default:
  141. throw new ArgumentOutOfRangeException(nameof(outlierMode), outlierMode, "Unknown OutlierMode value.");
  142. }
  143. }
  144. }
  145. }