enumerable-stats 1.2.1 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4b7a1951101022de006735e6276e1db4a974d98a5ae23c617a0f0c54b116ec80
4
- data.tar.gz: 0efb5538568ded644e36e5f0a5ffb70cd52c86f678c490751e8c9b5987e99e46
3
+ metadata.gz: c0131e566d1175fe367fb75c840914ae752eea76a1a194a8d35a02d24591d6ad
4
+ data.tar.gz: bb99194f3965132256bb9cdabed80bf58c5da172f7cd10e4f56277c0417fe7d0
5
5
  SHA512:
6
- metadata.gz: 20ddf5dd46540ff3a3ce31de0a153babcb1f005556d782e82371dbc70ddf7f882960dd4bd3197fe43571072561a812fb1ccc3b6cb8d5cb9c87cedfd61e9e1c48
7
- data.tar.gz: 8bcfa97b1be3d3a1cb6887b1aa1f2ec733250361fe8a5834ef090273c97e75aebab38e0ec27d6277a843ad7ef5f8176176e41b7e39fa5d4641ad3daf319a66aa
6
+ metadata.gz: 022f98715f44e7788749adb509bbef27bf759d2d09c7d946ebbdf21e34ea6e8a7225e011be6ad39e3260cec3f7daad17c61ecefbd9a197457b0e75d9bd10889c
7
+ data.tar.gz: d1e0a0052b175fe9fc4175961d0b52248c8cc78c39258048fa7846d9e67c8bd2ff6fe6da365b41284b9b9e2d48c8a9c1fcc165d621a25d9227df88716849ae34
@@ -93,6 +93,9 @@ module EnumerableStats
93
93
  # treatment = [15, 17, 16, 18, 14]
94
94
  # t_stat = control.t_value(treatment) # => ~-4.2 (negative means treatment > control)
95
95
  def t_value(other)
96
+ raise ArgumentError, "Cannot compare with an empty collection" if empty? || other.empty?
97
+ raise ArgumentError, "Parameter must be an Enumerable" unless other.respond_to?(:mean)
98
+
96
99
  signal = (mean - other.mean)
97
100
  noise = Math.sqrt(
98
101
  ((standard_deviation**2) / count) +
@@ -144,6 +147,16 @@ module EnumerableStats
144
147
  t_stat > critical_value
145
148
  end
146
149
 
150
+ # Alias for greater_than?
151
+ def >(other, alpha: 0.05)
152
+ greater_than?(other, alpha: alpha)
153
+ end
154
+
155
+ # Alias for less_than?
156
+ def <(other, alpha: 0.05)
157
+ less_than?(other, alpha: alpha)
158
+ end
159
+
147
160
  # Tests if this collection's mean is significantly less than another collection's mean
148
161
  # using a one-tailed Student's t-test. Returns true if the test indicates statistical
149
162
  # significance at the specified alpha level.
@@ -374,12 +387,28 @@ module EnumerableStats
374
387
  # Cauchy distribution: exact inverse
375
388
  return Math.tan(Math::PI * (0.5 - alpha))
376
389
  elsif df == 2
377
- # Exact formula for df=2: t = z / sqrt(1 - z^2/(z^2 + 2))
378
- # This is more numerically stable
379
- z_sq = z**2
380
- # Exact formula for df=2: t = z / sqrt(1 - z^2/(z^2 + 2))
381
- return z / Math.sqrt(1.0 - (z_sq / (z_sq + 2.0)))
390
+ # Exact closed-form solution for df=2
391
+ # For df=2, CDF: F(t) = 1/2 * (1 + t/√(t² + 2))
392
+ # Quantile function: t = (2p - 1)/√(2p(1 - p)) where p = 1 - α
393
+
394
+ p = 1.0 - alpha
382
395
 
396
+ # Handle edge cases
397
+ return Float::INFINITY if p >= 1.0
398
+ return -Float::INFINITY if p <= 0.0
399
+
400
+ # For p very close to 0.5, use normal approximation to avoid numerical issues
401
+ return 0.0 if (p - 0.5).abs < 1e-10
402
+
403
+ # Apply exact formula: t = (2p - 1)/√(2p(1 - p))
404
+ numerator = (2.0 * p) - 1.0
405
+ denominator_sq = 2.0 * p * (1.0 - p)
406
+
407
+ # Ensure we don't have numerical issues with the square root
408
+ return numerator / Math.sqrt(denominator_sq) if denominator_sq.positive?
409
+
410
+ # Fallback to normal approximation for edge cases
411
+ return z
383
412
  end
384
413
 
385
414
  # Use Cornish-Fisher expansion for general case
@@ -388,29 +417,31 @@ module EnumerableStats
388
417
  # Base normal quantile
389
418
  t = z
390
419
 
391
- # First-order correction
420
+ # First-order correction - Cornish-Fisher expansion
421
+ # Standard form: (z³ + z)/(4ν)
392
422
  if df >= 4
393
- c1 = z / 4.0
423
+ c1 = ((z**3) + z) / 4.0
394
424
  t += c1 / df
395
425
  end
396
426
 
397
- # Second-order correction
427
+ # Second-order correction - Cornish-Fisher expansion
428
+ # Standard form: (5z⁵ + 16z³ + 3z)/(96ν²)
398
429
  if df >= 6
399
- c2 = ((5.0 * (z**3)) + (16.0 * z)) / 96.0
430
+ c2 = ((5.0 * (z**5)) + (16.0 * (z**3)) + (3.0 * z)) / 96.0
400
431
  t += c2 / (df**2)
401
432
  end
402
433
 
403
434
  # Third-order correction for better accuracy
435
+ # Standard form: (3z⁷ + 19z⁵ + 17z³ - 15z)/(384ν³)
404
436
  if df >= 8
405
- c3 = ((3.0 * (z**5)) + (19.0 * (z**3)) + (17.0 * z)) / 384.0
437
+ c3 = ((3.0 * (z**7)) + (19.0 * (z**5)) + (17.0 * (z**3)) - (15.0 * z)) / 384.0
406
438
  t += c3 / (df**3)
407
439
  end
408
440
 
409
- # Fourth-order correction for very high accuracy
410
- if df >= 10
411
- c4 = ((79.0 * (z**7)) + (776.0 * (z**5)) +
412
- (1482.0 * (z**3)) + (776.0 * z)) / CORNISH_FISHER_FOURTH_ORDER_DENOMINATOR
413
-
441
+ # Fourth-order correction - using standard coefficients
442
+ # More conservative approach for high accuracy
443
+ if df >= 12
444
+ c4 = ((79.0 * (z**7)) + (776.0 * (z**5)) + (1482.0 * (z**3)) + (776.0 * z)) / CORNISH_FISHER_FOURTH_ORDER_DENOMINATOR
414
445
  t += c4 / (df**4)
415
446
  end
416
447
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: enumerable-stats
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.1
4
+ version: 1.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jon Daniel
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-08-02 00:00:00.000000000 Z
11
+ date: 2025-08-03 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: |
14
14
  A Ruby gem that extends all Enumerable objects (Arrays, Ranges, Sets, etc.) with essential statistical methods.