Spaces:
Running on Zero
Running on Zero
| """ | |
| test_feature_schema.py | |
| ---------------------- | |
| Unit tests verifying feature schema, dtypes, non-null guarantees, and absence of infinite values. | |
| """ | |
| from __future__ import annotations | |
| from pathlib import Path | |
| import numpy as np | |
| import pandas as pd | |
| import pytest | |
| ROOT = Path(__file__).resolve().parents[1] | |
| DATA_DIR = ROOT / "data" / "processed" | |
| def dataset_a_features(): | |
| path = DATA_DIR / "dataset_a_features.parquet" | |
| if not path.exists(): | |
| pytest.skip(f"Feature file not found: {path}") | |
| return pd.read_parquet(path) | |
| def dataset_b_features(): | |
| path = DATA_DIR / "dataset_b_features.parquet" | |
| if not path.exists(): | |
| pytest.skip(f"Feature file not found: {path}") | |
| return pd.read_parquet(path) | |
| def test_dataset_a_feature_schema(dataset_a_features): | |
| """Verify Dataset A required engineered features exist and have valid dtypes.""" | |
| expected_cols = [ | |
| "amount_log1p", | |
| "hour", | |
| "day_of_week", | |
| "is_weekend", | |
| "customer_txn_count_past", | |
| "customer_amount_mean_past", | |
| "customer_amount_std_past", | |
| "device_txn_count_past", | |
| "customer_amount_dev", | |
| "identity_available", | |
| "missing_p_email", | |
| "missing_r_email", | |
| "missing_addr1", | |
| "missing_device_info", | |
| ] | |
| for col in expected_cols: | |
| assert col in dataset_a_features.columns, f"Missing required feature column: {col}" | |
| def test_dataset_a_no_infinite_values(dataset_a_features): | |
| """Verify Dataset A engineered features contain zero infinite values.""" | |
| num_cols = dataset_a_features.select_dtypes(include=[np.number]).columns | |
| inf_count = np.isinf(dataset_a_features[num_cols]).sum().sum() | |
| assert inf_count == 0, f"Found {inf_count} infinite values in Dataset A features!" | |
| def test_dataset_a_features_no_nans(dataset_a_features): | |
| """Verify engineered numerical features in Dataset A have zero NaNs.""" | |
| a_engineered = [ | |
| "amount_log1p", | |
| "hour", | |
| "day_of_week", | |
| "is_weekend", | |
| "customer_txn_count_past", | |
| "customer_amount_mean_past", | |
| "customer_amount_std_past", | |
| "device_txn_count_past", | |
| "customer_amount_dev", | |
| ] | |
| nan_counts = dataset_a_features[a_engineered].isna().sum().to_dict() | |
| assert all(c == 0 for c in nan_counts.values()), f"Found NaNs in Dataset A engineered features: {nan_counts}" | |
| def test_dataset_b_feature_schema(dataset_b_features): | |
| """Verify Dataset B required scenario features exist.""" | |
| expected_cols = [ | |
| "rolling_txn_15m", | |
| "rolling_fraud_rate_15m", | |
| "baseline_txn_15m", | |
| "baseline_fraud_rate", | |
| "velocity_ratio", | |
| "fraud_rate_deviation", | |
| "amount_deviation", | |
| ] | |
| for col in expected_cols: | |
| assert col in dataset_b_features.columns, f"Missing required scenario feature: {col}" | |
| def test_dataset_b_no_infinite_values(dataset_b_features): | |
| """Verify Dataset B features contain zero infinite values.""" | |
| num_cols = dataset_b_features.select_dtypes(include=[np.number]).columns | |
| inf_count = np.isinf(dataset_b_features[num_cols]).sum().sum() | |
| assert inf_count == 0, f"Found {inf_count} infinite values in Dataset B features!" | |
| def test_dataset_b_features_no_nans(dataset_b_features): | |
| """Verify engineered numerical features in Dataset B have zero NaNs.""" | |
| b_engineered = [ | |
| "rolling_txn_15m", | |
| "rolling_fraud_rate_15m", | |
| "baseline_txn_15m", | |
| "baseline_fraud_rate", | |
| "velocity_ratio", | |
| "fraud_rate_deviation", | |
| "amount_deviation", | |
| ] | |
| nan_counts = dataset_b_features[b_engineered].isna().sum().to_dict() | |
| assert all(c == 0 for c in nan_counts.values()), f"Found NaNs in Dataset B engineered features: {nan_counts}" | |