Machine Learning for Time Series: Building Workflows That Scale
Focus on pipelines and reproducibility across many series.
Machine Learning for Time Series: Building Workflows That Scale
Focus on pipelines and reproducibility across many series.
This GitHub repository includes scripts and articles covering the full spectrum of time series techniques — Preprocessing, EDA, Modeling, and Evaluation. The current article is just one piece of that broader collection.
[embed]Google Colab Edit descriptioncolab.research.google.com
This notebook contains all the components covered in the article. It is recommended to use it to reproduce and practice everything discussed here.
Time series data is everywhere: energy consumption, stock prices, web traffic, weather, and beyond. A common challenge in time series machine learning is twofold:
- How to transform long sequences into a tabular format suitable for modeling;

- How to structure predictive models when working with many series — (1). should we train one model per series, or (2). build a single model that generalizes across them?

The first question is already answered in **colab notebook and [article](https://medium.com/@injure21/transform-time-series-data-for-supervised-learning-from-sequence-to-samples-a7b12306b077)**,
This post focus on the second question, walks through three practical approaches, with code examples drawn from a working notebook:
- Building a single model for one time series.
- Training many models, one for each series.
- Using pipelines to streamline preprocessing and modeling.
1. Single-Series Modeling: Start Simple
The first step is to pick one series — for example, energy consumption in a single household — and build a regression model to forecast it.
We begin by engineering features:
- Lag features: yesterday’s and last week’s consumption.
- Rolling statistics: 7-day averages or standard deviations.
- Seasonal rolling features: same-hour averages from prior weeks.
- Calendar encodings: month, day of week, time of day (with sin/cos encoding).
- Weather & exogenous features: temperature, humidity, holidays, etc.
Using scikit-learn, we can preprocess continuous, categorical, and boolean features with a ColumnTransformer, then feed them into a simple Ridge regression:
preprocessor = ColumnTransformer(
transformers=[
("num", StandardScaler(), continuous_features),
("cat", OneHotEncoder(handle_unknown="ignore"), categorical_features),
("bool", "passthrough", boolean_features),
]
)
model = Pipeline(steps=[
("preprocessor", preprocessor),
("regressor", Ridge(alpha=1.0))
])
Evaluation uses metrics like MAE, RMSE, and bias.

By looking at the feature importance, we found:
- Current day energy consumption is significantly affected by previous day.
- Special holiday, such as Black Friday (day 342, 343,344 of the year), Chrismas Eve, has significant affect of energy consumption.

2. Scaling Up: Many Series, Many Models
What if we want forecasts for hundreds of households?
One approach is to replicate the single-series workflow, but train a separate model per household (or per product, per sensor, etc.).
This setup has pros and cons:
- ✅ Each model can capture idiosyncrasies of its series.
- ❌ Training and maintaining hundreds or thousands of models becomes computationally expensive and operationally complex.
Still, for moderate scale (say 100–200 entities), it’s a practical way to achieve accuracy while reusing a familiar pipeline.
Pipelines: Making It Reproducible
Feature engineering for time series can quickly become messy. Pipelines solve this by
- Bundling preprocessing, modeling, and evaluation into a single reproducible workflow.
- Swapping models or adjust parameters without rewriting feature code.
- Scaling seamlessly across hundreds of series.
#@title 1.ModelRunner
import pandas as pd
from sklearn.compose import ColumnTransformer
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import OneHotEncoder, StandardScaler
class ModelRunner:
def __init__(self, feature_dict, model_cls, model_params=None,
use_scaler=True, use_onehot=True):
self.feature_dict = feature_dict
self.model_cls = model_cls
self.model_params = model_params or {}
self.use_scaler = use_scaler
self.use_onehot = use_onehot
self.pipeline = self._build_pipeline()
def _build_pipeline(self):
transformers = []
if self.use_scaler and self.feature_dict["continuous_features"]:
transformers.append(("num", StandardScaler(), self.feature_dict["continuous_features"]))
elif self.feature_dict["continuous_features"]:
transformers.append(("num", "passthrough", self.feature_dict["continuous_features"]))
if self.use_onehot and self.feature_dict["categorical_features"]:
transformers.append(("cat", OneHotEncoder(handle_unknown="ignore"), self.feature_dict["categorical_features"]))
elif self.feature_dict["categorical_features"]:
transformers.append(("cat", "passthrough", self.feature_dict["categorical_features"]))
if self.feature_dict["boolean_features"]:
transformers.append(("bool", "passthrough", self.feature_dict["boolean_features"]))
preprocessor = ColumnTransformer(transformers, remainder="drop")
model = self.model_cls(**self.model_params)
return Pipeline(steps=[
("preprocessor", preprocessor),
("regressor", model)
])
def fit(self, X, y):
self.pipeline.fit(X, y)
def predict(self, X):
return self.pipeline.predict(X)
The notebook shows how you can use this ModelRunner to fit/predict multiple model for one series, and then expand to hundreds of series:
all_preds = []
all_metrics = []
for config in model_configs:
runner = ModelRunner(
feature_dict=feature_dict,
model_cls=config["cls"],
model_params=config.get("params", {}),
use_scaler=config.get("use_scaler", True),
use_onehot=config.get("use_onehot", True)
)
model_name = config["name"]
for lcl_id in tqdm(lcl_ids, desc=f"Running {model_name}"):
preds_df, metrics_df = run_model_for_customer(
runner,
model_name = model_name,
lcl_id = lcl_id,
train_df = train_df,
test_df = test_df,
feature_dict = feature_dict)
all_preds.append(preds_df)
metrics_df["LCLid"] = lcl_id
metrics_df["model"] = model_name
all_metrics.append( metrics_df)
all_preds = pd.concat(all_preds, ignore_index=True)
all_metrics = pd.concat(all_metrics, ignore_index=True)
*Model Config
Instead of using sklearn pipeline, you can also use dataclass, feel free to try it. Below is the example:
[embed]Google Colab Edit descriptioncolab.research.google.com
Closing Thoughts
Machine learning for time series isn’t just about finding the “best” algorithm. It’s about designing workflows that scale from one dataset to many, while balancing accuracy, interpretability, and engineering complexity.
In future posts, we’ll explore how global forecasting models (GFMs) can replace “one-model-per-series” with a single unified model across all entities — unlocking massive efficiency gains at scale.
메타데이터
- post_id
- c0136bd321a9
- slug
- machine-learning-for-time-series-prediction-c0136bd321a9
- url
- https://medium.com/@injure21/machine-learning-for-time-series-prediction-c0136bd321a9
- canonical_url
- https://medium.com/@injure21/machine-learning-for-time-series-prediction-c0136bd321a9
- author_url
- https://medium.com/@injure21
- status
- ok
- fetched_at
- 2026-06-25 12:15:08