-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathlev_calculator_test.py
More file actions
145 lines (116 loc) · 5.29 KB
/
lev_calculator_test.py
File metadata and controls
145 lines (116 loc) · 5.29 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
#!/usr/bin/env python3
"""
Test script to verify the rigorous LEV calculation is working correctly.
"""
import numpy as np
from datetime import datetime, timedelta
def test_daily_probability_conversion():
"""Test the conversion from 30-day EPSS to daily probability."""
print("Testing daily probability conversion...")
# Test cases: [30-day EPSS, expected daily probability (approximate)]
test_cases = [
(0.0, 0.0),
(0.1, 0.00351), # Small probability: should be close to 0.1/30 = 0.00333
(0.5, 0.02257), # Medium probability: diverges from 0.5/30 = 0.01667
(0.9, 0.07696), # High probability: much different from 0.9/30 = 0.03
(1.0, 1.0),
]
def calculate_daily_prob_rigorous(p30, window_size=30):
"""Calculate daily probability using rigorous formula."""
if p30 == 0.0:
return 0.0
if p30 == 1.0:
return 1.0
complement = 1.0 - p30
if complement < np.finfo(float).eps:
return 1.0
return 1.0 - (complement ** (1.0/window_size))
def calculate_daily_prob_approximation(p30, window_size=30):
"""Calculate daily probability using NIST approximation."""
return p30 / window_size
for p30, expected in test_cases:
rigorous = calculate_daily_prob_rigorous(p30)
approx = calculate_daily_prob_approximation(p30)
print(f"P30={p30:.1f} -> Rigorous={rigorous:.5f}, Approx={approx:.5f}, Expected≈{expected:.5f}")
# Verify rigorous calculation is working
if p30 == 0.0:
assert rigorous == 0.0, f"Expected 0.0 for P30=0.0, got {rigorous}"
elif p30 == 1.0:
assert rigorous == 1.0, f"Expected 1.0 for P30=1.0, got {rigorous}"
else:
assert 0.0 < rigorous < 1.0, f"Daily prob should be between 0 and 1, got {rigorous}"
assert rigorous > 0, f"Daily prob should be positive for positive P30, got {rigorous}"
print("✓ Daily probability conversion tests passed!")
def test_lev_calculation():
"""Test LEV calculation with simple scenarios."""
print("\nTesting LEV calculation logic...")
# Test case 1: Single day with EPSS score
def simple_lev_calculation(daily_probs):
"""Calculate LEV for a series of daily probabilities."""
if len(daily_probs) == 0:
return 0.0
# Filter out zeros
non_zero_probs = [p for p in daily_probs if p > 0]
if len(non_zero_probs) == 0:
return 0.0
# Calculate product of (1 - daily_prob)
product = 1.0
for p in non_zero_probs:
product *= (1.0 - p)
return 1.0 - product
# Test cases
test_cases = [
([0.1], 0.1), # Single day, 10% daily prob -> 10% LEV
([0.1, 0.1], 0.19), # Two days, 10% each -> 1 - 0.9^2 = 0.19
([0.0, 0.1, 0.0], 0.1), # Only one non-zero day
([0.01] * 30, 0.2593), # 30 days of 1% daily prob -> 1 - 0.99^30 ≈ 0.26
([], 0.0), # No data
]
for daily_probs, expected in test_cases:
result = simple_lev_calculation(daily_probs)
print(f"Daily probs: {daily_probs[:3]}{'...' if len(daily_probs) > 3 else ''} -> LEV={result:.4f}, Expected≈{expected:.4f}")
# Check result is reasonable
assert 0.0 <= result <= 1.0, f"LEV should be between 0 and 1, got {result}"
if len(daily_probs) > 0 and any(p > 0 for p in daily_probs):
assert result > 0, f"LEV should be positive when there are positive daily probs, got {result}"
print("✓ LEV calculation logic tests passed!")
def test_edge_cases():
"""Test edge cases that might cause issues."""
print("\nTesting edge cases...")
# Test very small EPSS scores
small_scores = [1e-6, 1e-9, 1e-12]
for score in small_scores:
daily_prob = 1.0 - (1.0 - score)**(1.0/30)
print(f"Very small EPSS {score:.0e} -> Daily prob {daily_prob:.10e}")
assert daily_prob > 0, f"Daily prob should be positive for positive EPSS"
assert daily_prob < score, f"Daily prob should be less than 30-day prob for small values"
# Test values very close to 1.0
high_scores = [0.999, 0.9999, 0.99999]
for score in high_scores:
daily_prob = 1.0 - (1.0 - score)**(1.0/30)
print(f"High EPSS {score} -> Daily prob {daily_prob:.6f}")
assert 0.0 < daily_prob < 1.0, f"Daily prob should be between 0 and 1"
print("✓ Edge case tests passed!")
def main():
"""Run all tests."""
print("=" * 50)
print("Testing Rigorous LEV Calculation Components")
print("=" * 50)
try:
test_daily_probability_conversion()
test_lev_calculation()
test_edge_cases()
print("\n" + "=" * 50)
print("✓ All tests passed! The rigorous calculation logic is correct.")
print("The issue might be in:")
print("1. Data loading/access")
print("2. Date range calculation")
print("3. EPSS score retrieval")
print("4. Array handling in the vectorized implementation")
print("=" * 50)
except Exception as e:
print(f"\n✗ Test failed: {e}")
import traceback
traceback.print_exc()
if __name__ == "__main__":
main()