SIENTIAPDE-1579: Added extra test files and support filters implementation

This commit is contained in:
Kou Kinoshita
2026-02-18 14:16:21 -03:00
parent 8b7bd81328
commit 54a47a1d96
3 changed files with 749 additions and 0 deletions

View File

@@ -47,6 +47,68 @@ def _ensure_date_column_parsed(data: pd.DataFrame, params: TrainModelParams) ->
return data
def _apply_support_filters(
data_view: pd.DataFrame,
target_variable: str,
support_filters: dict,
) -> pd.DataFrame:
"""
Keep only rows where (var, target) lies between the two guide lines for each variable.
For each variable in support_filters, the condition is lower(x_var) <= target <= upper(x_var),
where lower/upper are the two lines (intercept + slope from angle, scaled by y_range/x_range).
Global mask is AND across all variables. Matches DEMO logic in template_01.py.
Args:
data_view: DataFrame after preprocessor transform.
target_variable: Name of the target column (y axis).
support_filters: Per-variable config with upper_line/lower_line, each {intercept, angle}.
Returns:
data_view filtered to rows satisfying all variable conditions; unchanged if support_filters empty.
"""
if not support_filters or target_variable not in data_view.columns:
return data_view
combined_keep_mask = np.ones(len(data_view), dtype=bool)
for var_col, config in support_filters.items():
if var_col not in data_view.columns:
continue
upper = config.get('upper_line') or config.get('upperLine')
lower = config.get('lower_line') or config.get('lowerLine')
if not upper or not lower:
continue
x_vals = data_view[var_col].astype(float).to_numpy()
y_vals = data_view[target_variable].astype(float).to_numpy()
xmin, xmax = float(np.nanmin(x_vals)), float(np.nanmax(x_vals))
ymin, ymax = float(np.nanmin(y_vals)), float(np.nanmax(y_vals))
x_range = (xmax - xmin) if (xmax - xmin) != 0 else 1.0
y_range = (ymax - ymin) if (ymax - ymin) != 0 else 1.0
scale_ratio = y_range / x_range
b1 = float(upper.get('intercept', 0))
deg1 = float(upper.get('angle', 0))
b2 = float(lower.get('intercept', 0))
deg2 = float(lower.get('angle', 0))
m1 = np.tan(np.deg2rad(deg1)) * scale_ratio
m2 = np.tan(np.deg2rad(deg2)) * scale_ratio
y1 = m1 * x_vals + b1
y2 = m2 * x_vals + b2
lower_bound = np.minimum(y1, y2)
upper_bound = np.maximum(y1, y2)
keep_mask = (y_vals >= lower_bound) & (y_vals <= upper_bound)
if len(keep_mask) == len(combined_keep_mask):
combined_keep_mask &= keep_mask
return data_view.loc[combined_keep_mask]
class TrainingRepository:
"""
Repository for machine learning model training operations.
@@ -105,6 +167,13 @@ class TrainingRepository:
process_data.fit(data)
data_view = process_data.transform(data)
if params.support_filters:
data_view = _apply_support_filters(
data_view,
params.target_variable,
params.support_filters,
)
if len(data_view) <= 0:
raise ValueError('Data view is empty after transformation')