(+351) 21 24 10006  ·  info@bconcepts.pt
Carnaxide, Lisbon

How to do time series data preprocessing in Azure ML: step by step

João Barros 25 de September de 2026 4 min read

Preparing time series is often the most important part before training a model. This tutorial shows how to do time series data preprocessing in Azure AI & Machine Learning to obtain clean, imputed data with useful temporal features for forecasting or classification models.

Prerequisites

  • Azure account with an active subscription and permissions to create resources.
  • Azure Machine Learning Workspace created.
  • Basic familiarity with Python and Jupyter Notebooks.
  • Python 3.8+ with packages: pandas, azureml-core, azureml-dataset-runtime.

Step 1: Upload the data to the Workspace

Data can be in a blob, Data Lake or local. Here we use a CSV file with minimal columns: timestamp and value. We'll register the file as a Dataset in the Workspace for reproducibility and data governance.

from azureml.core import Workspace, Dataset

ws = Workspace.from_config()
datastore = ws.get_default_datastore()
# carrega o ficheiro local para o datastore (uma única vez)
datastore.upload_files(files=['./series.csv'], target_path='series/', overwrite=True)

# regista como Dataset
ds = Dataset.Tabular.from_delimited_files(path=(datastore, 'series/series.csv'))
ds = ds.register(workspace=ws, name='series_raw', description='Série temporal bruta')

Step 2: Initial exploration and problem detection

Quickly explore to see missing values, duplicates, date formats and frequency irregularities. This helps decide imputation and aggregation.

import pandas as pd

df = ds.to_pandas_dataframe()
df['timestamp'] = pd.to_datetime(df['timestamp'])
df = df.sort_values('timestamp').reset_index(drop=True)
print(df.info())
print(df.head())
print('Missing values:', df['value'].isna().sum())

Step 3: Normalize timestamps and set frequency

Convert to a DatetimeIndex and reindex to a regular frequency (e.g.: hourly, daily). This makes imputation and lag feature creation easier.

# definir índice e reindexar para frequência horária
freq = 'H'  # ajustar conforme a série
idx = pd.date_range(start=df['timestamp'].min(), end=df['timestamp'].max(), freq=freq)
df = df.set_index('timestamp').reindex(idx).rename_axis('timestamp').reset_index()

Step 4: Missing value imputation

Choose a simple method first: forward-fill/backfill, linear interpolation or rolling mean. For series with seasonality, use interpolation or more advanced models later.

# exemplos de imputação
# forward-fill seguido de backfill para extremos
df['value_ffill'] = df['value'].fillna(method='ffill').fillna(method='bfill')

# interpolação linear
df['value_interp'] = df['value'].interpolate(method='time')

# média móvel (janela 3)
df['value_ma3'] = df['value'].fillna(df['value'].rolling(window=3, min_periods=1).mean())

Step 5: Create temporal features and lags

Features like hour, dayofweek, month and lags are essential for models. Create lags and moving averages to capture temporal dependencies.

# características temporais
df['hour'] = df['timestamp'].dt.hour
df['dayofweek'] = df['timestamp'].dt.dayofweek
df['month'] = df['timestamp'].dt.month

# lags e rolling
for lag in [1, 24, 168]:  # ex.: 1h, 1 dia, 1 semana (horária)
    df[f'lag_{lag}'] = df['value_interp'].shift(lag)

# rolling mean
df['rolling_24'] = df['value_interp'].shift(1).rolling(window=24, min_periods=1).mean()

# eliminar primeiras linhas com NaNs decorrentes de lags
df = df.dropna().reset_index(drop=True)

Step 6: Split train/validation and export Dataset

Split temporally (do not shuffle). Register the result as a new Dataset for training and pipeline reproducibility.

train_end = int(len(df) * 0.8)
train_df = df.iloc[:train_end]
val_df = df.iloc[train_end:]

# exportar para CSV e subir para datastore
train_df.to_csv('train_prepared.csv', index=False)
val_df.to_csv('val_prepared.csv', index=False)

datastore.upload_files(files=['train_prepared.csv','val_prepared.csv'], target_path='series/prepared/', overwrite=True)

from azureml.core import Dataset
prepared_train = Dataset.Tabular.from_delimited_files(path=(datastore, 'series/prepared/train_prepared.csv'))
prepared_train = prepared_train.register(workspace=ws, name='series_train_prepared')

Verify the outcome

Confirm there are no NaNs in the features used by the model, check temporal distribution and that lags are correctly aligned. Quick checks:

print('Train rows:', len(train_df))
print('Nulls por coluna:\n', train_df.isna().sum())
print('Timestamp sample:', train_df['timestamp'].iloc[:5])
# visualizar algumas características
print(train_df[['timestamp','value_interp','lag_1','rolling_24']].head())

Conclusion

You now have a basic time series preprocessing pipeline in Azure AI & Machine Learning: you uploaded data, imputed missing values, created temporal features and lags, and registered the prepared Dataset for training. Next steps: try advanced imputation techniques (e.g.: Prophet, KNN imputation), seasonal feature engineering and integrate this code as a Pipeline in Azure ML. Tip: always validate temporally to avoid leakage—have you tried testing different temporal validation windows?