Skip to content

Commit

Permalink
Release - 0.2.0 Version (#13)
Browse files Browse the repository at this point in the history
* Initial 0.2.0 version development commit

* Updated dependencies

* Feature - Fourier Period Finder (#10)

* Preliminary implementation of `FourierPeriodFinder`

TODO: Clean the copy pasta of comments and documentation that came from
`AutoPeriodFinder`

* Added tests for `FourierPeriodFinder`

* Updated FourierPeriodFinder Documentation

* Rearrange imports

* Update README.md

Add a short description of the Fourier transform-based seasonality
period detection

* Minor documentation tweak

* Add more unit tests

* Rename a couple of unit tests

* Feature - Add a standard `AutocorrelationPeriodFinder` (#11)

* Preliminary implementation to the simple ACF Period Finder

* Argsort the resulting seasonality periods efficiently

* Refactor code and restructure project

* Restructure tests folder

* Refactor removing kwargs into a generic function in tools package

* Reinstate __init__.py in tests folder

* Re-organize imports and address flake8 warnings

* Re-organize imports in the main __init__.py file

* Configure VS Code to use Black as the default Python formatter for this project

* Ignore E203 when linting with flake8

* Moved flake8 conifgurations to .flake8 file

* Removed an unnecessary comma from .vscode/settings.json

* Fix Flake8 linting errors

* Add new tool functions

Add the functions:
- 'acf': Calculate the autocorrelation function of a given data array.
- 'apply_window': Apply window function on a given data array. To
replace 'apply_window_fun'.
- 'detrend': Detrend a given data array.

* Improve Fourier based detector

Improve Fourier Transform based period detector by eleminating the
Pandas depedency, using the new apply_window tool function and adding
detrend tool function option.

* Remove deprecated tool function 'apply_window_fun'

* Improve ACF period finder

Simplify ACF period finder by removing seasonal decomposition options,
adding detrending and window application options, adding other possible
correlation funcions, and adding more unit tests

* Tweak the ACF periodicity detector

* Replace the legacy ACF based seasonality periods detector with Autoperiod

* Clear pandas usage from the package code completely

* Update project dependencies

* Fix the CI build

* Improve and clean period hints verification code

* Set default percentile and k values to the default values in the paper and add some documentation

* Revert percentile argument back to 95

* Update project dependencies and requirements

* Finalize the docstrings documentation in finder_autoperiod.py

* Update docstring in finder_acf.py

* Refator - Rename Package (#12)

* Initial refactoring and renaming of the package

* TestPyPI release commit of the new package

* Bump up release candidate version

* Fix a typo in a comment in pre-release.yml

* Refactor and rename files all over the place

* Improve docstrings for Autoperiod

* Update README

* Update pyproject.toml

* Update docstrings

* Update README

* Delete unused images

* Set 0.2.0 version for release

* Update project dependencies
  • Loading branch information
iskandergaba authored Sep 15, 2024
1 parent 9de78b4 commit a35b621
Show file tree
Hide file tree
Showing 25 changed files with 1,495 additions and 733 deletions.
8 changes: 8 additions & 0 deletions .flake8
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[flake8]
# Default line length in Black formatter is 88
max-line-length = 88
extend-ignore =
# No whitespace before ':' in [x : y]
E203,
# Line break before binary operator
W503
6 changes: 3 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,13 @@ jobs:
run: |
python -m pip install --upgrade pip
python -m pip install flake8 pytest
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
if [ -f requirements-dev.txt ]; then pip install -r requirements-dev.txt; fi
- name: Lint with flake8
run: |
# stop the build if there are Python syntax errors or undefined names
flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
# exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
# exit-zero treats all errors as warnings.
flake8 . --count --exit-zero --statistics
- name: Test with pytest
run: |
pytest
2 changes: 1 addition & 1 deletion .github/workflows/pre-release.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# This workflow will install Poetry, resolve Python dependencies, run tests,
# build and publish release candidate package versions to TestPyPI upon pushing
# tags of the form "*.*.*rc*".
# tags of the form "*.*.*".

name: Publish to TestPyPI
on:
Expand Down
5 changes: 4 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
{
"[python]": {
"editor.defaultFormatter": "ms-python.black-formatter"
},
"python.testing.pytestArgs": [
"tests"
],
"python.testing.unittestEnabled": false,
"python.testing.pytestEnabled": true
}
}
91 changes: 41 additions & 50 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,95 +1,86 @@
# `auto-period-finder`
[![PyPI Version](https://img.shields.io/pypi/v/auto-period-finder.svg?label=PyPI)](https://pypi.org/project/auto-period-finder/)
![PyPI - Python Version](https://img.shields.io/pypi/pyversions/auto-period-finder?label=Python)
![GitHub License](https://img.shields.io/github/license/iskandergaba/auto-period-finder?label=License)
<div align="center">
<h1>Pyriodicity</h1>

## About `auto-period-finder`
`auto-period-finder` is an autocorrelation function (ACF) based seasonality periods automatic finder for univariate time series.
[![PyPI Version](https://img.shields.io/pypi/v/pyriodicity.svg?label=PyPI)](https://pypi.org/project/pyriodicity/)
![PyPI - Python Version](https://img.shields.io/pypi/pyversions/pyriodicity?label=Python)
![GitHub License](https://img.shields.io/github/license/iskandergaba/pyriodicity?label=License)

</div>


## About Pyriodicity
Pyriodicity provides intuitive and easy-to-use Python implementation for periodicity (seasonality) detection in univariate time series. Pyriodicity supports the following detection methods:
- [Autocorrelation Function (ACF)](https://otexts.com/fpp3/acf.html)
- [Autoperiod]( https://doi.org/10.1137/1.9781611972757.40)
- [Fast Fourier Transform (FFT)](https://otexts.com/fpp3/useful-predictors.html#fourier-series)

## Installation
To install the latest version of `auto-period-finder`, simply run:
To install the latest version of `pyriodicity`, simply run:

```shell
pip install auto-period-finder
pip install pyriodicity
```

## Example
Start by loading a timeseries dataset with a frequency. We can use `co2` emissions sample dataset from `statsmodels`
Start by loading a the `co2` timeseries emissions sample data from [`statsmodels`](https://www.statsmodels.org)
```python
from statsmodels.datasets import co2
data = co2.load().data
```

You can resample the data to whatever frequency you want.

You can then resample the data to whatever frequency you want. In this example, we downsample the data to a monthly frequency
```python
data = data.resample("ME").mean().ffill()
```

Use `AutoPeriodFinder` to find the list of seasonality periods based on ACF.
Use `Autoperiod` to find the list of periods based in this data (if any).
```python
from auto_period_finder import AutoPeriodFinder
period_finder = AutoPeriodFinder(data)
periods = period_finder.fit()
from pyriodicity import Autoperiod
autoperiod = Autoperiod(data)
periods = autoperiod.fit()
```

You can also find the most prominent period either ACF-wise:
There are multiple parameters you can play with should you wish to. For example, you can specify a lower percentile value for a more lenient detection
```python
strongest_period_acf = period_finder.fit_find_strongest_acf()
autoperiod.fit(percentile=90)
```

or variance-wise:
Or increase the number of random data permutations for a better power threshold estimation
```python
strongest_period_var = period_finder.fit_find_strongest_var()
autoperiod.fit(k=300)
```
You can learn more about calculating seasonality component through variance from [here](OTexts.com/fpp3/stlfeatures.html).

Alternatively, you can use other periodicity detection methods such as `ACFPeriodicityDetector` and `FFTPeriodicityDetector` and compare results and performances.

## How to Get Started
This project is built and published using [Poetry](https://python-poetry.org). To setup development environment for this project you can follow these steps:
## Development Environment Setup
This project is built and published using [Poetry](https://python-poetry.org). To setup a development environment for this project you can follow these steps:

1. First, you need to install [Python](https://www.python.org) of one of the compatible versions indicated above.
2. Install Poetry. You can follow this [guide](https://python-poetry.org/docs/#installing-with-the-official-installer) and use their official installer.
1. Install one of the compatible [Python](https://www.python.org) versions indicated above.
2. Install [Poetry](https://python-poetry.org/docs/#installing-with-pipx).
3. Navigate to the root folder and install dependencies in a virtual environment:
```shell
poetry install
```
4. If everything worked properly, you should have `auto-period-finder-geinoPPi-py3.10` environment activated. You can verify this by running:
4. If everything worked properly, you should have an environment under the name `pyriodicity-py3.*` activated. You can verify this by running:
```shell
poetry env list
```
5. You can run tests using the command:
```shell
poetry run pytest
```
6. To export the list detailed list of dependencies, run the following command:
6. To export the detailed dependency list, consider running the following:
```shell
# Add poetry-plugin-export plugin to poetry
poetry self add poetry-plugin-export
poetry export --output requirements.txt
```

## ACF-Based Seasonality Period Detection Explained
An easy and quick way to find seasonality periods of a univariate time series is to check its autocorrelation function (ACF) and look for specific charecteristics in lag values that we will detail in a second. You can read more information about time series ACF [here](https://otexts.com/fpp3/acf.html), but intuitively, An autocorrelation coefficient $r_k$ measures the the linear relationship between $k$-lagged values of a given time series. In simpler terms, $r_k$ measures how similar/dissimilar time series values that $k$-length apart from each other. The set of $r_k$ values for each lag $k$ makes ACF. Equipped with this information, I developed a package for finding time series seasonality periods automatically using ACF information.

Simply put, given a univariate time series $T$, the algorithm finds, iteratively, lag values $k$ such that:
1. $1 \lt k \leq \frac{\lvert T \rvert}{2}$
2. Autocorrelation coefficients $r_q$ are local maxima where $q \in \{k, 2k, 3k, ...\}$
3. $\forall p \in P, \forall n \in \mathbb{N}, k \neq n \times p$, where $P$ is the list of already found periods.

The list of such $k$ values constitute the set of found seasonality periods $P$. To understand this further, consider this hypothetical time series of hourly frequency that has clear weekly seasonality below

[![Time series with a weekly seasonality](https://raw.githubusercontent.com/iskandergaba/auto-period-finder/master/assets/images/timeseries.png)](https://raw.githubusercontent.com/iskandergaba/auto-period-finder/master/assets/images/timeseries.png)

Now let's look at the corresponding ACF for the time series above:

[![Autocorrelation function of a time series with a weekly seasonality](https://raw.githubusercontent.com/iskandergaba/auto-period-finder/master/assets/images/acf.png)](https://raw.githubusercontent.com/iskandergaba/auto-period-finder/master/assets/images/acf.png)

You can see that the autocorrelation coefficient for lag value 168 hours (i.e. one week) is a local maximum (red-border square). Similarly, autocorrelation coefficient for lag values that are multiples of 168 (gray-border squares). We can therefore conclude that this time series has a weekly seasonality period.
# Export the package dependencies to requirements.txt
poetry export --output requirements.txt

### Notes
- The first condition is needed because a seasonality period cannot neither be 1 (a trivial case), nor greater than half the length of the target time series (by definition, a seasonality has to manifest itself at least twice in a given time series).
- The third condition favors eliminating redundant seasonality periods that are multiples of each others. The algorithm does allow, however, finding seasonality periods that divide already found seasonality periods.
- The periods detection uses `argmax` on the ACF to select seasonality period candidates before checking they satisfy the conditions discussed above. Therefore, the list of seasonality periods are returned in the descending order of their corresponding ACF coefficients.
# If you wish to export all the dependencies, including those needed for testing, run the following command
poetry export --with test --output requirements-dev.txt
```

## References
- [1] Hyndman, R.J., & Athanasopoulos, G. (2021) Forecasting: principles and practice, 3rd edition, OTexts: Melbourne, Australia. [OTexts.com/fpp3](https://otexts.com/fpp3). Accessed on 12-25-2023.
- [1] Hyndman, R.J., & Athanasopoulos, G. (2021) Forecasting: principles and practice, 3rd edition, OTexts: Melbourne, Australia. [OTexts.com/fpp3](https://otexts.com/fpp3). Accessed on 09-15-2024.
- [2] Vlachos, M., Yu, P., & Castelli, V. (2005). On periodicity detection and Structural Periodic similarity. Proceedings of the 2005 SIAM International Conference on Data Mining. [doi.org/10.1137/1.9781611972757.40](https://doi.org/10.1137/1.9781611972757.40).
Binary file removed assets/images/acf.png
Binary file not shown.
Binary file removed assets/images/timeseries.png
Binary file not shown.
1 change: 0 additions & 1 deletion auto_period_finder/__init__.py

This file was deleted.

Loading

0 comments on commit a35b621

Please sign in to comment.