SIENTIAPDE-1579: Added date format and convert methods
This commit is contained in:
@@ -21,6 +21,32 @@ from model_manager.utils.models.train_model_params import TrainModelParams
|
||||
from model_manager.utils.models.train_model_result import TrainModelResult
|
||||
|
||||
|
||||
def _frontend_format_to_strftime(fmt: str) -> str:
|
||||
"""Convert front-end date format (dd/MM/yyyy HH:mm:ss) to Python strftime (%d/%m/%Y %H:%M:%S)."""
|
||||
if not fmt:
|
||||
return fmt
|
||||
out = fmt.replace('yyyy', '%Y').replace('MM', '%m').replace('dd', '%d')
|
||||
out = out.replace('HH', '%H').replace('mm', '%M').replace('ss', '%S')
|
||||
return out
|
||||
|
||||
|
||||
def _ensure_date_column_parsed(data: pd.DataFrame, params: TrainModelParams) -> pd.DataFrame:
|
||||
"""If date_column and date_format are set, parse the column as datetime to avoid comparison errors downstream."""
|
||||
if not params.date_column or not params.date_format or params.date_column not in data.columns:
|
||||
return data
|
||||
try:
|
||||
python_fmt = _frontend_format_to_strftime(params.date_format)
|
||||
data = data.copy()
|
||||
data[params.date_column] = pd.to_datetime(
|
||||
data[params.date_column], format=python_fmt, errors='coerce'
|
||||
)
|
||||
except Exception as e:
|
||||
raise ValueError(
|
||||
f'Failed to parse date column "{params.date_column}" with format "{params.date_format}": {e}'
|
||||
) from e
|
||||
return data
|
||||
|
||||
|
||||
class TrainingRepository:
|
||||
"""
|
||||
Repository for machine learning model training operations.
|
||||
@@ -67,10 +93,13 @@ class TrainingRepository:
|
||||
Exception: If data loading, preprocessing, or training fails
|
||||
"""
|
||||
data = load_data(uploaded_file, params.line_separator, params.decimal_separator)
|
||||
|
||||
# Configure datetime index if timestamp column exists
|
||||
# Required for TimeSeriesDiscontinuityAnalyzer (static window removal)
|
||||
data = self._configure_datetime_index(data)
|
||||
if data is None:
|
||||
raise ValueError(
|
||||
'Failed to load CSV data: load_data returned None. '
|
||||
'Check file encoding, line separator and decimal separator.'
|
||||
)
|
||||
data = _ensure_date_column_parsed(data, params)
|
||||
data = self._configure_datetime_index(data, params)
|
||||
|
||||
process_data = self._init_data_preprocessor(params)
|
||||
process_data.fit(data)
|
||||
@@ -350,40 +379,41 @@ class TrainingRepository:
|
||||
'original_features': params.variable_columns,
|
||||
}
|
||||
|
||||
def _configure_datetime_index(self, data: pd.DataFrame) -> pd.DataFrame:
|
||||
def _configure_datetime_index(
|
||||
self, data: pd.DataFrame | None, params: TrainModelParams
|
||||
) -> pd.DataFrame:
|
||||
"""
|
||||
Configure datetime index for the DataFrame.
|
||||
|
||||
This method attempts to identify a timestamp column and set it as the
|
||||
DataFrame index with DatetimeIndex type. This is required for
|
||||
TimeSeriesDiscontinuityAnalyzer (used in static window removal).
|
||||
|
||||
The method looks for common timestamp column names and converts the
|
||||
first matching column to datetime, then sets it as the index.
|
||||
|
||||
Args:
|
||||
data: Input DataFrame
|
||||
|
||||
Returns:
|
||||
pd.DataFrame: DataFrame with DatetimeIndex if timestamp column found,
|
||||
otherwise returns original DataFrame unchanged
|
||||
Guards against None to avoid 'NoneType' object has no attribute 'index' downstream.
|
||||
Prefers params.date_column when set; otherwise looks for common timestamp column names.
|
||||
"""
|
||||
# If index is already DatetimeIndex, just ensure it's sorted
|
||||
if data is None:
|
||||
raise ValueError(
|
||||
'Data is None after load_data. '
|
||||
'Check file format, line separator and decimal separator.'
|
||||
)
|
||||
if not isinstance(data, pd.DataFrame):
|
||||
raise TypeError(f'Expected DataFrame, got {type(data).__name__}')
|
||||
|
||||
if isinstance(data.index, pd.DatetimeIndex):
|
||||
self.logger.info('DataFrame already has DatetimeIndex')
|
||||
return data.sort_index()
|
||||
|
||||
# Common timestamp column names
|
||||
timestamp_columns = [
|
||||
common_timestamp_columns = [
|
||||
'timestamp',
|
||||
'Timestamp',
|
||||
'TIMESTAMP',
|
||||
'date',
|
||||
'Date',
|
||||
'DATE',
|
||||
'DATA',
|
||||
'datetime',
|
||||
'DateTime',
|
||||
]
|
||||
timestamp_columns = (
|
||||
[params.date_column] if params.date_column else []
|
||||
) + [c for c in common_timestamp_columns if c != params.date_column]
|
||||
|
||||
for col in timestamp_columns:
|
||||
if col in data.columns:
|
||||
|
||||
Reference in New Issue
Block a user