SIENTIAPDE-2201: fix: keep the timestamp column in train/test data CSVs
generate_report wrote train_data.csv and test_data.csv with index=False, which dropped the UTC time index. laborious drift reads test_data.csv from MLflow as its reference and needs a timestamp column; without it, every model trained here drifted against the first 30% of its own target window. Both CSVs now write the index as timestamp. If a column already has that name, the CSV is written as before and a warning is logged, so training never fails over drift. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -514,6 +514,58 @@ def test_generate_report_adds_target_alias_for_reports(tmp_path):
|
||||
assert test_csv['target'].equals(test_csv['t'])
|
||||
|
||||
|
||||
_UTC_INDEX = pd.DatetimeIndex(['2024-01-01 02:00', '2024-01-01 01:00'], tz='UTC')
|
||||
|
||||
|
||||
def _dated_result(**train_columns: list[float]) -> TrainModelResult:
|
||||
"""Frames indexed by UTC time, like prepare_training_data + predict produce them."""
|
||||
columns = train_columns or {'v1': [1.0, 2.0], 't': [1.0, 2.0]}
|
||||
return TrainModelResult(
|
||||
params=TrainModelParams.from_dict(_minimal_dict_for_prepare()),
|
||||
train_data=pd.DataFrame(columns, index=_UTC_INDEX),
|
||||
val_data=pd.DataFrame(columns, index=_UTC_INDEX),
|
||||
y_train_pred=pd.DataFrame({'t': [1.0, 2.0]}, index=_UTC_INDEX),
|
||||
y_pred=pd.DataFrame({'t': [1.0, 2.0]}, index=_UTC_INDEX),
|
||||
run_name='testrun',
|
||||
)
|
||||
|
||||
|
||||
def _generate_report(repo, tmr: TrainModelResult, tmp_path) -> TrainModelResult:
|
||||
with (
|
||||
patch.object(repo, '_get_reports_directory', return_value=str(tmp_path)),
|
||||
patch('model_manager.utils.repository.data_manager_repository.Reports'),
|
||||
):
|
||||
return repo.generate_report(tmr, {})
|
||||
|
||||
|
||||
def test_generate_report_csvs_keep_the_time_index_as_timestamp(tmp_path):
|
||||
"""laborious drift reads test_data.csv as its reference and needs ``timestamp``."""
|
||||
repo = dmr.DataManagerRepository(MagicMock())
|
||||
|
||||
out = _generate_report(repo, _dated_result(), tmp_path)
|
||||
|
||||
for csv_path in (out.train_data_path, out.test_data_path):
|
||||
csv = pd.read_csv(csv_path)
|
||||
assert list(csv.columns) == ['timestamp', 'prediction', 'v1', 't', 'target']
|
||||
assert pd.to_datetime(csv['timestamp']).tolist() == list(_UTC_INDEX)
|
||||
|
||||
|
||||
def test_generate_report_csvs_skip_timestamp_when_a_column_already_has_the_name(tmp_path):
|
||||
"""A variable literally named ``timestamp`` wins; training must not fail over drift."""
|
||||
repo = dmr.DataManagerRepository(MagicMock())
|
||||
tmr = _dated_result(timestamp=[5.0, 6.0], v1=[1.0, 2.0], t=[1.0, 2.0])
|
||||
|
||||
with patch.object(repo, 'warning') as warning:
|
||||
out = _generate_report(repo, tmr, tmp_path)
|
||||
|
||||
for csv_path in (out.train_data_path, out.test_data_path):
|
||||
csv = pd.read_csv(csv_path)
|
||||
assert list(csv.columns) == ['prediction', 'timestamp', 'v1', 't', 'target']
|
||||
assert csv['timestamp'].tolist() == [5.0, 6.0]
|
||||
assert warning.call_count == 2
|
||||
assert "Column 'timestamp' already exists" in warning.call_args.args[0]
|
||||
|
||||
|
||||
def test_generate_report_skips_equation_file_when_not_linear(tmp_path):
|
||||
repo = dmr.DataManagerRepository(MagicMock())
|
||||
p = TrainModelParams.from_dict(_minimal_dict_for_prepare())
|
||||
|
||||
Reference in New Issue
Block a user