Library with utility functions for Polars DataFrames, similar to scikit-learn & pandas functionalities.
Project description
polars-timeseries-utils
A Python library providing scikit-learn style transformers and utilities for time series data processing with Polars.
Features
- Single Transformers: Scikit-learn style
fit/transformAPI for Polars Series - Composable Transformers: Apply transformers to DataFrames and chain them in pipelines
- Preprocessing Utilities: Frequency detection, timestamp handling, and ETL functions
- Statistics: Rolling and static z-score calculations for anomaly detection
- Full Polars Integration: Works with both
DataFrameandLazyFrame
Installation
pip install polars-timeseries-utils
Or with uv:
uv add polars-timeseries-utils
Package Structure
polars_timeseries_utils/
├── transformers/
│ ├── single/ # Series-level transformers (fit/transform on pl.Series)
│ └── composable/ # DataFrame-level transformers (MultiColumnTransformer, Pipeline)
├── preprocessing/ # ETL, frequency detection, timestamp handling
└── stats/ # Z-score functions for anomaly detection
Quick Start
Single Transformers
All single transformers follow the scikit-learn fit/transform pattern and operate on pl.Series:
import polars as pl
from polars_timeseries_utils.transformers.single import (
Imputer,
MinMaxScaler,
StandardScaler,
RobustScaler,
Smoother,
LagTransformer,
DiffTransformer,
Strategy,
)
# Impute missing values
series = pl.Series("value", [1.0, None, 3.0, None, 5.0])
imputer = Imputer(strategy=Strategy.MEAN)
filled = imputer.fit_transform(series)
# Result: [1.0, 3.0, 3.0, 3.0, 5.0]
# Scale to [0, 1] range
series = pl.Series("value", [0.0, 25.0, 50.0, 75.0, 100.0])
scaler = MinMaxScaler()
scaled = scaler.fit_transform(series)
# Result: [0.0, 0.25, 0.5, 0.75, 1.0]
# Inverse transform to get original values back
original = scaler.inverse_transform(scaled)
# Result: [0.0, 25.0, 50.0, 75.0, 100.0]
Available Single Transformers
| Transformer | Description |
|---|---|
Imputer |
Fill missing values with a constant or strategy (mean, median, min, max, forward, backward) |
RollingImputer |
Fill missing values using rolling window statistics |
MinMaxScaler |
Scale values to [0, 1] range |
StandardScaler |
Standardize to zero mean and unit variance |
RobustScaler |
Scale using median and IQR (robust to outliers) |
Smoother |
Clip outliers based on z-score threshold |
RollingSmoother |
Clip outliers using rolling z-score |
LagTransformer |
Create lag features for time series |
DiffTransformer |
Apply differencing for stationarity |
Imputation Strategies
from polars_timeseries_utils.transformers.single import (
Imputer,
RollingImputer,
Strategy,
RollingStrategy,
)
# Static strategies
Imputer(strategy=Strategy.MEAN) # Fill with column mean
Imputer(strategy=Strategy.MEDIAN) # Fill with column median
Imputer(strategy=Strategy.FORWARD) # Forward fill
Imputer(strategy=Strategy.BACKWARD) # Backward fill
Imputer(value=0) # Fill with constant value
# Rolling strategies
RollingImputer(window_size=5, strategy=RollingStrategy.MEAN)
RollingImputer(window_size=5, strategy=RollingStrategy.MEDIAN)
Composable Transformers
Apply single transformers to multiple DataFrame columns at once:
import polars as pl
from polars_timeseries_utils.transformers.single import Imputer, MinMaxScaler, Strategy
from polars_timeseries_utils.transformers.composable import (
MultiColumnTransformer,
ColumnTransformerMetadata,
)
df = pl.DataFrame({
"timestamp": ["2023-01-01", "2023-01-02", "2023-01-03"],
"temperature": [20.0, None, 22.0],
"humidity": [50.0, 55.0, None],
})
# Define transformers for specific columns
transformer = MultiColumnTransformer([
ColumnTransformerMetadata(
name="imputer",
columns=["temperature", "humidity"],
transformer=Imputer(strategy=Strategy.MEAN),
),
])
result = transformer.fit_transform(df)
You can also select columns by dtype:
import polars as pl
from polars_timeseries_utils.transformers.single import MinMaxScaler
from polars_timeseries_utils.transformers.composable import (
MultiColumnTransformer,
ColumnTransformerMetadata,
)
transformer = MultiColumnTransformer([
ColumnTransformerMetadata(
name="scale_floats",
columns=[pl.Float64], # Apply to all Float64 columns
transformer=MinMaxScaler(),
),
])
Pipelines
Chain multiple transformation steps:
from polars_timeseries_utils.transformers.single import Imputer, MinMaxScaler, Strategy
from polars_timeseries_utils.transformers.composable import (
Pipeline,
MultiColumnTransformer,
MultiColumnTransformerMetadata,
ColumnTransformerMetadata,
)
# Create pipeline steps
impute_step = MultiColumnTransformer([
ColumnTransformerMetadata(
name="imputer",
columns=["value"],
transformer=Imputer(strategy=Strategy.MEAN),
),
])
scale_step = MultiColumnTransformer([
ColumnTransformerMetadata(
name="scaler",
columns=["value"],
transformer=MinMaxScaler(),
),
])
# Build and run pipeline
pipeline = Pipeline([
MultiColumnTransformerMetadata(name="impute", transformer=impute_step),
MultiColumnTransformerMetadata(name="scale", transformer=scale_step),
])
result = pipeline.fit_transform(df)
Preprocessing Utilities
Clean Time Series Data
from datetime import datetime
import polars as pl
from polars_timeseries_utils.preprocessing import clean_timeseries_df
df = pl.DataFrame({
"timestamp": [datetime(2023, 1, 3), datetime(2023, 1, 1), datetime(2023, 1, 2)],
"value": [3.0, None, 100.0], # Contains null and outlier
})
# Sorts, removes duplicates, imputes nulls, and smooths outliers
cleaned = clean_timeseries_df(df, ts_col="timestamp", window_size=3, max_zscore=2.0)
Frequency Detection
from datetime import datetime
import polars as pl
from polars_timeseries_utils.preprocessing import determine_frequency, Frequency
series = pl.Series("ts", [datetime(2023, 1, i) for i in range(1, 11)])
freq = determine_frequency(series)
# Result: Frequency.DAILY
Timestamp Handling
from polars_timeseries_utils.preprocessing import (
handle_timestamp_column_raises_if_error,
next_timestamp,
last_timestamp,
Frequency,
)
# Auto-detect and cast timestamp column
df, ts_col = handle_timestamp_column_raises_if_error(df)
# Get next timestamp in sequence
next_ts = next_timestamp(df[ts_col], Frequency.DAILY)
Statistics
Calculate z-scores for anomaly detection:
from polars_timeseries_utils.stats import zscore_df, rolling_zscore_df
# Static z-score
result = zscore_df(df, col="value", with_median="med", with_std="std")
# Rolling z-score (uses MAD for robustness)
result = rolling_zscore_df(
df,
col="value",
window_size=10,
alias="z_score",
with_median="rolling_med",
with_mad="rolling_mad",
)
LazyFrame Support
All functions work with both DataFrame and LazyFrame:
import polars as pl
from polars_timeseries_utils.transformers.single import MinMaxScaler
from polars_timeseries_utils.transformers.composable import (
MultiColumnTransformer,
ColumnTransformerMetadata,
)
lf = pl.LazyFrame({"value": [1.0, 2.0, 3.0]})
transformer = MultiColumnTransformer([
ColumnTransformerMetadata(
name="scaler",
columns=["value"],
transformer=MinMaxScaler(),
),
])
# Returns LazyFrame
result = transformer.fit_transform(lf)
# Collect when ready
df = result.collect()
API Reference
Single Transformers (transformers.single)
All transformers inherit from BaseColumnTransformer and implement:
fit(series: pl.Series) -> Self- Learn parameters from datatransform(series: pl.Series) -> pl.Series- Apply transformationfit_transform(series: pl.Series) -> pl.Series- Fit and transform in one step
Scalers also implement InverseTransformerMixin:
inverse_transform(series: pl.Series) -> pl.Series- Reverse the transformation
Composable Transformers (transformers.composable)
MultiColumnTransformer- Apply single transformers to DataFrame columnsPipeline- Chain multipleMultiColumnTransformerstepsColumnTransformerMetadata- Configuration for column-transformer mappingMultiColumnTransformerMetadata- Configuration for pipeline steps
Statistics (stats)
zscore(series)- Calculate z-score of a Serieszscore_df(df, col, ...)- Calculate z-score with optional median/std columnsrolling_zscore(series, window_size, ...)- Rolling z-score of a Seriesrolling_zscore_df(df, col, window_size, ...)- Rolling z-score with optional outputs
Preprocessing (preprocessing)
clean_timeseries_df(df, ts_col, ...)- Sort, dedupe, impute, and smoothdetermine_frequency(series)- Detect time series frequencyhandle_timestamp_column_raises_if_error(df, col)- Auto-detect and cast timestampsnext_timestamp(series, frequency)- Get next timestamp in sequencelast_timestamp(series)- Get maximum timestampFrequency- Enum for time series frequencies (HOURLY, DAILY, MONTHLY, YEARLY)
License
MIT
Contributing
Contributions are welcome! Please open an issue or submit a pull request on GitHub.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file polars_timeseries_utils-0.1.5.tar.gz.
File metadata
- Download URL: polars_timeseries_utils-0.1.5.tar.gz
- Upload date:
- Size: 43.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2310a4d3e951a496cca249579f654f7911c0f7cb552d522be8d544ffce2c2099
|
|
| MD5 |
91e0689312e7d09567fc7d17bf8d6539
|
|
| BLAKE2b-256 |
b11c18945a28ed211b0cfb8c14140297d8641494a16bb85a6133d96c0e4e60d1
|
Provenance
The following attestation bundles were made for polars_timeseries_utils-0.1.5.tar.gz:
Publisher:
publish.yml on LeonDavidZipp/polars-timerseries-utils
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
polars_timeseries_utils-0.1.5.tar.gz -
Subject digest:
2310a4d3e951a496cca249579f654f7911c0f7cb552d522be8d544ffce2c2099 - Sigstore transparency entry: 780750585
- Sigstore integration time:
-
Permalink:
LeonDavidZipp/polars-timerseries-utils@fc993799577afd82e73cf8013670b7f6f3560d41 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/LeonDavidZipp
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@fc993799577afd82e73cf8013670b7f6f3560d41 -
Trigger Event:
push
-
Statement type:
File details
Details for the file polars_timeseries_utils-0.1.5-py3-none-any.whl.
File metadata
- Download URL: polars_timeseries_utils-0.1.5-py3-none-any.whl
- Upload date:
- Size: 23.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ddf44392b4051fc52a87bb38efdd71c28566f99c04342d26176ae71c96423d32
|
|
| MD5 |
7da8f7c3913521f428a834a6e3de0a44
|
|
| BLAKE2b-256 |
0773f51a78ebca6534bfd30554d495ef95011d6eff4383e1e54e61b323889206
|
Provenance
The following attestation bundles were made for polars_timeseries_utils-0.1.5-py3-none-any.whl:
Publisher:
publish.yml on LeonDavidZipp/polars-timerseries-utils
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
polars_timeseries_utils-0.1.5-py3-none-any.whl -
Subject digest:
ddf44392b4051fc52a87bb38efdd71c28566f99c04342d26176ae71c96423d32 - Sigstore transparency entry: 780750586
- Sigstore integration time:
-
Permalink:
LeonDavidZipp/polars-timerseries-utils@fc993799577afd82e73cf8013670b7f6f3560d41 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/LeonDavidZipp
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@fc993799577afd82e73cf8013670b7f6f3560d41 -
Trigger Event:
push
-
Statement type: