SIENTIAPDE-1255: Add thread-safety documentation and in-place modification warnings to LinearRegressionModel and DataPreprocessor classes.

This commit is contained in:
Bruno Domingues
2025-10-20 17:27:58 -03:00
parent 56f3db350c
commit 2292ae57cc

View File

@@ -10,6 +10,19 @@ from sklearn.preprocessing import StandardScaler
class LinearRegressionModel(BaseEstimator, TransformerMixin):
"""
Linear Regression Model for Time Series Analysis.
Thread-safety: This class is NOT thread-safe during fit() operations.
Do not call fit() on the same instance from multiple threads simultaneously.
After fitting, predict() is thread-safe for read-only operations.
For multi-threaded environments:
- Fit the model in a single thread
- Share the fitted instance across threads for prediction only
- Or create separate instances per thread
"""
def __init__(
self,
target_variable: str = '',
@@ -99,6 +112,21 @@ class LinearRegressionModel(BaseEstimator, TransformerMixin):
class DataPreprocessor(BaseEstimator, TransformerMixin):
"""
Data Preprocessor for Time Series Analysis.
Thread-safety: This class is NOT thread-safe during fit() operations.
Do not call fit() on the same instance from multiple threads simultaneously.
After fitting, transform() is thread-safe for read-only operations IF the
input DataFrames are not shared between threads.
For multi-threaded environments:
- Fit the preprocessor in a single thread
- Share the fitted instance across threads for transform() only
- Ensure each thread passes its own DataFrame copy to transform()
- Or create separate instances per thread
"""
def __init__(
self,
date_column: str = '',
@@ -176,9 +204,11 @@ class DataPreprocessor(BaseEstimator, TransformerMixin):
self.static_threshold = static_threshold
self.low_lim = low_lim
self.upp_lim = upp_lim
# self.window = window
# self.window = window # Not implemented yet
self.scaler_name = scaler_name
self.scaler_params = scaler_params
self.feature_names_order: list[str] = [] # Initialize to avoid AttributeError
if self.scaler_name == 'Standard Scaler':
self.scaler = StandardScaler()
elif self.scaler_name == 'None':
@@ -299,11 +329,16 @@ class DataPreprocessor(BaseEstimator, TransformerMixin):
Returns:
pandas.DataFrame: The treated data
Note:
This method modifies input_data in-place. Ensure the caller passes
a copy if the original DataFrame needs to be preserved.
"""
if lag_dict:
for var, lag in lag_dict.items():
if lag > 0:
input_data[var] = input_data[var].shift(lag)
# WARNING: Modifies DataFrame in-place
input_data.dropna(inplace=True)
return input_data
@@ -366,9 +401,13 @@ class DataPreprocessor(BaseEstimator, TransformerMixin):
Returns:
pandas.DataFrame: The treated data
Note:
This method modifies input_data in-place.
"""
if self.ar_var:
input_data[self.ar_var] = input_data[self.target_variable].shift(1)
# WARNING: Modifies DataFrame in-place
input_data.dropna(inplace=True)
return input_data
@@ -381,12 +420,16 @@ class DataPreprocessor(BaseEstimator, TransformerMixin):
Returns:
pandas.DataFrame: The treated data
Note:
This method modifies input_data in-place.
"""
if self.created_lags:
for var, lag in self.created_lags.items():
if lag > 0 and var in input_data.columns:
new_col = f'{var}_lag{lag}'
input_data[new_col] = input_data[var].shift(lag)
# WARNING: Modifies DataFrame in-place
input_data.dropna(inplace=True)
return input_data