Metadata-Version: 2.4
Name: UR2CUTE
Version: 2.0.0
Summary: A time-series forecasting model using UR2CUTE: Using Repetitively 2 CNN for Unsteady Timeseries Estimation
Author: Patrick Brandtner, Zuzana Komínková Oplatková, Taha Falatouri, Mehran Naseri, Farzaneh Darbanian
Author-email: Sina Mirshahi <sina7th@gmail.com>
Maintainer-email: Sina Mirshahi <sina7th@gmail.com>
License-Expression: MIT
Project-URL: Homepage, https://github.com/FH-Prevail/UR2CUTE_torch
Project-URL: Repository, https://github.com/FH-Prevail/UR2CUTE_torch
Project-URL: Documentation, https://github.com/FH-Prevail/UR2CUTE_torch#readme
Project-URL: Bug Tracker, https://github.com/FH-Prevail/UR2CUTE_torch/issues
Project-URL: Changelog, https://github.com/FH-Prevail/UR2CUTE_torch/blob/main/CHANGES.md
Keywords: time-series,forecasting,intermittent-demand,CNN,deep-learning,pytorch,machine-learning,demand-forecasting,inventory-management
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Science/Research
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.7
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: numpy>=1.20.0
Requires-Dist: pandas>=1.1.0
Requires-Dist: torch>=1.7.0
Requires-Dist: scikit-learn>=0.24.0
Provides-Extra: dev
Requires-Dist: pytest>=7.0.0; extra == "dev"
Requires-Dist: pytest-cov>=3.0.0; extra == "dev"
Requires-Dist: black>=22.0.0; extra == "dev"
Requires-Dist: flake8>=4.0.0; extra == "dev"
Requires-Dist: mypy>=0.950; extra == "dev"
Requires-Dist: isort>=5.10.0; extra == "dev"
Provides-Extra: test
Requires-Dist: pytest>=7.0.0; extra == "test"
Requires-Dist: pytest-cov>=3.0.0; extra == "test"
Provides-Extra: docs
Requires-Dist: sphinx>=4.0.0; extra == "docs"
Requires-Dist: sphinx-rtd-theme>=1.0.0; extra == "docs"
Requires-Dist: sphinxcontrib-napoleon>=0.7; extra == "docs"
Dynamic: license-file

# UR2CUTE

Using Repetitively 2 CNNs for Unsteady Timeseries Estimation. UR2CUTE is a dual-stage, PyTorch powered model dedicated to intermittent demand forecasting. A classifier estimates demand occurrence while a regressor predicts magnitude, allowing the library to focus on the sparse structure typical of slow-moving inventory.

## What's New in 2.0

Version 2.0.0 keeps the two-CNN hurdle design but overhauls how the networks see the data. **This is a breaking release.**

- **Multichannel temporal windows** replace the old flat lag vector. Each CNN now receives `(channels, window)` where the window axis is genuine time: target history, optional covariates, and engineered intermittency channels (time-since-last-demand, causal rolling mean).
- **Dilated causal convolutions (TCN-style)** so the convolutions slide over consecutive time steps and cover long inter-demand gaps cheaply.
- **Better training objectives:** `BCEWithLogitsLoss` with per-step `pos_weight` for the classifier (heavy zero-class imbalance) and a Huber (SmoothL1) loss for the regressor (robust to spikes).
- **Smarter scaling:** per-channel min-max plus an automatic `log1p` transform on non-negative targets.

Migration notes:

- **Models saved with 1.x cannot be loaded in 2.0** — retrain and re-save.
- The default `n_steps_lag` changed from `3` to `12` (it is now a lookback window, not a count of lag columns). Set it explicitly to pin behaviour.

## Overview

Intermittent demand is dominated by long zero stretches punctuated by irregular spikes. Traditional statistical models struggle to capture both the timing and the size of those bursts. UR2CUTE tackles the problem with a hurdle-style architecture:

1. A dilated-causal CNN classifier predicts the probability of non-zero demand for each step in the forecast horizon.
2. A dilated-causal CNN regressor estimates the corresponding quantities.
3. Final forecasts combine the two outputs through an adaptive threshold so the regressor only contributes when demand is likely.

Both CNNs consume the same multichannel temporal window — target history, optional covariates, and engineered intermittency channels — so the convolutions slide over a genuine time axis and capture long inter-demand gaps cheaply.

The estimator follows the scikit-learn API, includes thorough input validation, and automatically selects CPU or GPU devices.

## Features

- Pure PyTorch implementation with GPU support when available.
- Direct multi-step forecasting: predicts the entire horizon in a single forward pass.
- Multichannel temporal windows: target history, optional external covariates, and engineered intermittency channels (time-since-last-demand, causal rolling mean).
- Dilated causal convolutions (TCN-style) so each CNN slides over a genuine time axis and cheaply covers long inter-demand gaps.
- Customizable hyperparameters (epochs, batch size, independent learning rates, dropout).
- Auto-threshold mode that derives an occurrence cutoff from the training set.
- Early stopping that restores the best weights, kept in memory during training.
- Reproducible results through explicit random seed management.
- Model persistence through `save_model` and `load_model`.
- Complete type hints and packaged type information (`py.typed`).

## Dependencies

- Python 3.7 or newer
- PyTorch 1.7+
- NumPy 1.20+ (for `sliding_window_view`)
- pandas
- scikit-learn

## Installation

### From PyPI

```bash
pip install UR2CUTE
```

### From Source

```bash
git clone https://github.com/FH-Prevail/UR2CUTE_torch.git
cd UR2CUTE_torch
pip install -e .

# Optional extras
pip install -e ".[dev]"
pip install -e ".[test]"
pip install -e ".[docs]"
```

### Verify Installation

```python
from UR2CUTE import UR2CUTE
print(UR2CUTE.__module__)
```

## Quick Start

```python
import pandas as pd
import torch
from UR2CUTE import UR2CUTE

data = pd.DataFrame(
    {
        "date": pd.date_range("2023-01-01", periods=50, freq="W"),
        "target": [0, 5, 0, 0, 12, 0, 0, 0, 7, 0] * 5,
        "promo": [0, 1, 0, 0, 1, 0, 0, 1, 0, 0] * 5,
        "price": [10.0, 9.5, 9.5, 9.5, 10.0, 10.0, 10.0, 9.8, 9.8, 9.8] * 5,
    }
)

device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
print(f"Using device: {device}")

model = UR2CUTE(
    n_steps_lag=12,
    forecast_horizon=4,
    external_features=["promo", "price"],
    threshold="auto",
)
model.fit(data, target_col="target")
print(model.predict(data))
```

## Parameters

| Parameter | Description | Default |
| --- | --- | --- |
| `n_steps_lag` | Length of the lookback window (past time steps each CNN sees). | 12 |
| `forecast_horizon` | Number of future periods predicted per call. | 8 |
| `external_features` | Optional list of column names used as exogenous inputs. | `None` |
| `epochs` | Training epochs for both CNN models. | 100 |
| `batch_size` | Training batch size. | 32 |
| `threshold` | Manual probability threshold or `"auto"` to derive from training data. | 0.5 |
| `patience` | Early stopping patience (epochs). | 10 |
| `random_seed` | Global random seed applied to NumPy, Python, and PyTorch. | 42 |
| `classification_lr` | Learning rate for the classifier. | 0.0021 |
| `regression_lr` | Learning rate for the regressor. | 0.0021 |
| `dropout_classification` | Dropout applied inside the classifier. | 0.4 |
| `dropout_regression` | Dropout applied inside the regressor. | 0.2 |
| `regressor_nonzero_only` | When `True`, the regressor is trained only on sequences where the forecast horizon contains at least one non-zero value. Set to `False` to train the regressor on all sequences. | `True` |
| `verbose` | Enables progress output and early-stopping logs. | `True` |

## Usage Patterns

### Auto Threshold

```python
model = UR2CUTE(threshold="auto")
model.fit(df, "target")
print(model.threshold_)
```

### External Features

```python
covariates = ["promotion", "price", "weekday"]
model = UR2CUTE(external_features=covariates)
model.fit(df, "target")
```

### Silent Training

```python
model = UR2CUTE(verbose=False)
model.fit(df, "target")
```

### Model Persistence

```python
trained = UR2CUTE().fit(train_df, "target")
trained.save_model("production_model.pkl")

loaded = UR2CUTE.load_model("production_model.pkl")
preds = loaded.predict(new_df)
```

## How It Works

1. **Preprocessing** – validates the input frame, builds the multichannel feature matrix (target + covariates + engineered intermittency channels), slides it into multi-step temporal windows, and splits chronologically into train and validation partitions.
2. **Scaling** – fits per-channel min-max scaling on the training windows only, and applies a `log1p` transform to non-negative targets to tame spikes before scaling, preventing validation leakage.
3. **Classification Stage** – trains a dilated-causal CNN with `BCEWithLogitsLoss` and per-step `pos_weight` to estimate the probability of demand for each future horizon step under heavy zero-class imbalance.
4. **Regression Stage** – trains a dilated-causal CNN regressor with a Huber (SmoothL1) loss, robust to demand spikes. By default (`regressor_nonzero_only=True`) only sequences where the horizon contains at least one non-zero value are used, keeping the regressor focused on demand magnitude; if no such sequences exist it falls back to the full dataset. Set `regressor_nonzero_only=False` to train on all sequences instead.
5. **Inference** – transforms the latest observed window, runs both networks, rescales quantities, and zeros out forecasts whose occurrence probability falls below the stored threshold.

## Performance

Internal benchmarks show UR2CUTE outperforming Croston, AutoARIMA, Prophet, gradient boosted trees, and random forests on sparse demand series, especially in MAE% and RMSE%. Improvements stem from the dedicated occurrence model, the multichannel temporal window with engineered intermittency signals, and the dilated causal filters tuned to each dataset.

## Citation

```
@article{mirshahi2024intermittent,
  title={Intermittent Time Series Demand Forecasting Using Dual Convolutional Neural Networks},
  author={Mirshahi, Sina and Brandtner, Patrick and Kominkova Oplatkova, Zuzana},
  journal={MENDEL -- Soft Computing Journal},
  volume={30},
  number={1},
  year={2024},
  publisher={MENDEL Journal}
}
```

## License

UR2CUTE is released under the MIT License. See `LICENSE` for the full text.

## Contributors

- Sina Mirshahi
- Patrick Brandtner
- Zuzana Kominkova Oplatkova
- Taha Falatouri
- Mehran Naseri
- Farzaneh Darbanian

## Acknowledgments

This work was carried out at:

- Department of Informatics and Artificial Intelligence, Tomas Bata University
- Department for Logistics, University of Applied Sciences Upper Austria, Steyr
- Josef Ressel-Centre for Predictive Value Network Intelligence, Steyr
