Skip to content

Commit 2bf1e02

Browse files
committed
fix doc issue
1 parent 9cd4d0a commit 2bf1e02

File tree

1 file changed

+45
-39
lines changed

1 file changed

+45
-39
lines changed

pyod/test/test_hbos_auto_bins_fix.py

Lines changed: 45 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
"""
1616

1717
import numpy as np
18+
1819
from pyod.models.hbos import HBOS
1920

2021

@@ -26,55 +27,58 @@ def test_hbos_auto_bins_with_out_of_range_values():
2627
exceeded the maximum training value for any feature.
2728
"""
2829
print("Testing HBOS with n_bins='auto' and out-of-range test values...")
29-
30+
3031
# Create training data with limited range
3132
np.random.seed(42)
3233
n_train = 100
3334
n_features = 5
34-
35+
3536
# Training data ranges roughly from 0 to 10
3637
X_train = np.random.randn(n_train, n_features) * 2 + 5
3738
X_train = np.clip(X_train, 0, 10)
38-
39+
3940
print(f"Training data shape: {X_train.shape}")
4041
print(f"Training data range per feature:")
4142
for i in range(n_features):
42-
print(f" Feature {i}: [{X_train[:, i].min():.2f}, {X_train[:, i].max():.2f}]")
43-
43+
print(
44+
f" Feature {i}: [{X_train[:, i].min():.2f}, {X_train[:, i].max():.2f}]")
45+
4446
# Initialize and fit HBOS with auto bins
4547
model = HBOS(n_bins='auto', contamination=0.1)
4648
model.fit(X_train)
47-
49+
4850
print(f"\nNumber of bins per feature after training:")
4951
for i in range(n_features):
5052
print(f" Feature {i}: {model.hist_[i].shape[0]} bins")
51-
53+
5254
# Create test data with some values OUTSIDE the training range
5355
# This is the critical part that triggers the bug
5456
X_test = np.random.randn(10, n_features) * 3 + 5
5557
# Force some values to be higher than training max
56-
X_test[0, 2] = X_train[:, 2].max() + 5 # Way above training max for feature 2
58+
X_test[0, 2] = X_train[:,
59+
2].max() + 5 # Way above training max for feature 2
5760
X_test[1, 3] = X_train[:, 3].max() + 3 # Above training max for feature 3
5861
X_test[2, 0] = X_train[:, 0].min() - 2 # Below training min for feature 0
59-
62+
6063
print(f"\nTest data shape: {X_test.shape}")
6164
print(f"Test data range per feature:")
6265
for i in range(n_features):
63-
print(f" Feature {i}: [{X_test[:, i].min():.2f}, {X_test[:, i].max():.2f}]")
64-
66+
print(
67+
f" Feature {i}: [{X_test[:, i].min():.2f}, {X_test[:, i].max():.2f}]")
68+
6569
# This would fail with IndexError before the fix
6670
try:
6771
predictions = model.predict(X_test)
6872
scores = model.decision_function(X_test)
69-
73+
7074
print(f"\n✓ SUCCESS: Predictions completed without error!")
7175
print(f" Predictions shape: {predictions.shape}")
7276
print(f" Scores shape: {scores.shape}")
7377
print(f" Number of outliers detected: {predictions.sum()}")
7478
print(f" Outlier indices: {np.where(predictions == 1)[0].tolist()}")
75-
79+
7680
return True
77-
81+
7882
except IndexError as e:
7983
print(f"\n✗ FAILED: IndexError occurred!")
8084
print(f" Error: {e}")
@@ -86,26 +90,26 @@ def test_hbos_auto_bins_edge_cases():
8690
"""
8791
Additional edge case tests for HBOS with auto bins.
8892
"""
89-
print("\n" + "="*70)
93+
print("\n" + "=" * 70)
9094
print("Testing edge cases...")
91-
print("="*70)
92-
95+
print("=" * 70)
96+
9397
np.random.seed(123)
94-
98+
9599
# Test 1: All test values above training range
96100
print("\nTest 1: All test values above training range")
97101
X_train = np.random.randn(50, 3) * 1 + 5
98102
model = HBOS(n_bins='auto', contamination=0.1)
99103
model.fit(X_train)
100-
104+
101105
X_test = X_train.max() + np.random.rand(5, 3) * 3
102106
try:
103107
predictions = model.predict(X_test)
104108
print(f" ✓ Success: {predictions.sum()} outliers detected")
105109
except IndexError as e:
106110
print(f" ✗ Failed with IndexError: {e}")
107111
return False
108-
112+
109113
# Test 2: All test values below training range
110114
print("\nTest 2: All test values below training range")
111115
X_test = X_train.min() - np.random.rand(5, 3) * 3
@@ -115,7 +119,7 @@ def test_hbos_auto_bins_edge_cases():
115119
except IndexError as e:
116120
print(f" ✗ Failed with IndexError: {e}")
117121
return False
118-
122+
119123
# Test 3: Mixed in-range and out-of-range values
120124
print("\nTest 3: Mixed in-range and out-of-range values")
121125
X_test = np.vstack([
@@ -131,75 +135,77 @@ def test_hbos_auto_bins_edge_cases():
131135
except IndexError as e:
132136
print(f" ✗ Failed with IndexError: {e}")
133137
return False
134-
138+
135139
return True
136140

137141

138142
def test_hbos_static_bins_comparison():
139143
"""
140144
Compare behavior between auto and static bins to ensure consistency.
141145
"""
142-
print("\n" + "="*70)
146+
print("\n" + "=" * 70)
143147
print("Comparing auto bins vs static bins behavior...")
144-
print("="*70)
145-
148+
print("=" * 70)
149+
146150
np.random.seed(456)
147151
X_train = np.random.randn(100, 4) * 2 + 5
148152
X_test = np.vstack([
149153
X_train[:5],
150154
X_train.max(axis=0) + 2, # One sample above all training ranges
151155
])
152-
156+
153157
# Test with auto bins
154158
model_auto = HBOS(n_bins='auto', contamination=0.1)
155159
model_auto.fit(X_train)
156160
try:
157161
pred_auto = model_auto.predict(X_test)
158162
score_auto = model_auto.decision_function(X_test)
159163
print(f" Auto bins: ✓ Success")
160-
print(f" Outliers: {pred_auto.sum()}, Score range: [{score_auto.min():.4f}, {score_auto.max():.4f}]")
164+
print(
165+
f" Outliers: {pred_auto.sum()}, Score range: [{score_auto.min():.4f}, {score_auto.max():.4f}]")
161166
except Exception as e:
162167
print(f" Auto bins: ✗ Failed - {e}")
163168
return False
164-
169+
165170
# Test with static bins
166171
model_static = HBOS(n_bins=10, contamination=0.1)
167172
model_static.fit(X_train)
168173
try:
169174
pred_static = model_static.predict(X_test)
170175
score_static = model_static.decision_function(X_test)
171176
print(f" Static bins: ✓ Success")
172-
print(f" Outliers: {pred_static.sum()}, Score range: [{score_static.min():.4f}, {score_static.max():.4f}]")
177+
print(
178+
f" Outliers: {pred_static.sum()}, Score range: [{score_static.min():.4f}, {score_static.max():.4f}]")
173179
except Exception as e:
174180
print(f" Static bins: ✗ Failed - {e}")
175181
return False
176-
182+
177183
print(f"\n Both methods handled out-of-range values correctly!")
178184
return True
179185

180186

181187
if __name__ == "__main__":
182-
print("="*70)
188+
print("=" * 70)
183189
print("HBOS IndexError Fix Test Suite")
184190
print("Issue: https://github.com/yzhao062/pyod/issues/476")
185-
print("="*70)
186-
191+
print("=" * 70)
192+
187193
all_passed = True
188-
194+
189195
# Run main test
190196
all_passed &= test_hbos_auto_bins_with_out_of_range_values()
191-
197+
192198
# Run edge case tests
193199
all_passed &= test_hbos_auto_bins_edge_cases()
194-
200+
195201
# Run comparison test
196202
all_passed &= test_hbos_static_bins_comparison()
197-
198-
print("\n" + "="*70)
203+
204+
print("\n" + "=" * 70)
199205
if all_passed:
200206
print("✓ ALL TESTS PASSED!")
201207
print("The fix correctly handles out-of-range test values.")
202208
else:
203209
print("✗ SOME TESTS FAILED!")
204210
print("The bug may not be fully fixed.")
205-
print("="*70)
211+
print("=" * 70)

0 commit comments

Comments
 (0)