Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for python 3.10 & 3.11 #8

Merged
merged 6 commits into from
Sep 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
python-version: ['3.6', '3.7', '3.8', '3.9']
os: [ubuntu-20.04]
python-version: ['3.7', '3.8', '3.9', '3.10', '3.11']
os: [ubuntu-latest]
steps:
- uses: actions/checkout@v1
- name: Set up Python ${{ matrix.python-version }}
Expand All @@ -50,8 +50,8 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
python-version: ['3.6', '3.7', '3.8', '3.9']
os: [ubuntu-20.04, macos-latest]
python-version: ['3.7', '3.8', '3.9', '3.10', '3.11']
os: [ubuntu-latest, macos-latest]
steps:
- uses: actions/checkout@v1
- name: Set up Python ${{ matrix.python-version }}
Expand All @@ -68,8 +68,8 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
python-version: ['3.6', '3.7', '3.8', '3.9']
os: [ubuntu-20.04, macos-latest, windows-latest]
python-version: ['3.7', '3.8', '3.9', '3.10', '3.11']
os: [ubuntu-latest, macos-latest, windows-latest]
steps:
- uses: actions/checkout@v1
- name: Set up Python ${{ matrix.python-version }}
Expand Down
13 changes: 9 additions & 4 deletions mlstars/adapters/statsmodels.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import numpy as np
from statsmodels.tsa import arima_model
from statsmodels.tsa.arima import model


class ARIMA(object):
"""A Wrapper for the statsmodels.tsa.arima_model.ARIMA class."""

def __init__(self, p, d, q, steps):
def __init__(self, p, d, q, trend, steps):
"""Initialize the ARIMA object.

Args:
Expand All @@ -15,12 +15,17 @@ def __init__(self, p, d, q, steps):
Integer denoting the degree of differencing.
q (int):
Integer denoting the order of the moving-average model.
trend (str):
Parameter controlling the deterministic trend. Can be specified
as a string where 'c' indicates a constant term, 't' indicates
a linear trend in time, and 'ct' includes both.
steps (int):
Integer denoting the number of time steps to predict ahead.
"""
self.p = p
self.d = d
self.q = q
self.trend = trend
self.steps = steps

def predict(self, X):
Expand All @@ -45,8 +50,8 @@ def predict(self, X):

num_sequences = len(X)
for sequence in range(num_sequences):
arima = arima_model.ARIMA(X[sequence], order=(self.p, self.d, self.q))
arima_fit = arima.fit(disp=0)
arima = model.ARIMA(X[sequence], order=(self.p, self.d, self.q), trend=self.trend)
arima_fit = arima.fit()
arima_results.append(arima_fit.forecast(self.steps)[0])

arima_results = np.asarray(arima_results)
Expand Down
53 changes: 5 additions & 48 deletions mlstars/custom/timeseries_preprocessing.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,53 +111,6 @@ def rolling_window_sequences(X, index, window_size, target_size, step_size, targ
return np.asarray(out_X), np.asarray(out_y), np.asarray(X_index), np.asarray(y_index)


_TIME_SEGMENTS_AVERAGE_DEPRECATION_WARNING = (
"mlstars.custom.timeseries_preprocessing.time_segments_average "
"is deprecated and will be removed in a future version. Please use "
"mlstars.custom.timeseries_preprocessing.time_segments_aggregate instead."
)


def time_segments_average(X, interval, time_column):
"""Compute average of values over given time span.

Args:
X (ndarray or pandas.DataFrame):
N-dimensional sequence of values.
interval (int):
Integer denoting time span to compute average of.
time_column (int):
Column of X that contains time values.

Returns:
ndarray, ndarray:
* Sequence of averaged values.
* Sequence of index values (first index of each averaged segment).
"""
warnings.warn(_TIME_SEGMENTS_AVERAGE_DEPRECATION_WARNING, DeprecationWarning)

if isinstance(X, np.ndarray):
X = pd.DataFrame(X)

X = X.sort_values(time_column).set_index(time_column)

start_ts = X.index.values[0]
max_ts = X.index.values[-1]

values = list()
index = list()

while start_ts <= max_ts:
end_ts = start_ts + interval
subset = X.loc[start_ts:end_ts - 1]
means = subset.mean(skipna=True).values
values.append(means)
index.append(start_ts)
start_ts = end_ts

return np.asarray(values), np.asarray(index)


def time_segments_aggregate(X, interval, time_column, method=['mean']):
"""Aggregate values over given time span.

Expand Down Expand Up @@ -269,4 +222,8 @@ def cutoff_window_sequences(X, timeseries, window_size, cutoff_time=None, time_i

output.append(selected.values)

return np.array(output)
output = np.array(output, dtype=object)
if output.ndim >= 2:
output = output.astype(float)

return output
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
{
"name": "statsmodels.tsa.arima_model.Arima",
"name": "statsmodels.tsa.arima.model.ARIMA",
"contributors": [
"Alexander Geiger <[email protected]>"
"Alexander Geiger <[email protected]>",
"Sarah Alnegheimish <[email protected]>"
],
"description": "ARIMA Model",
"classifiers": {
Expand Down Expand Up @@ -59,4 +60,4 @@
}
}
}
}
}
20 changes: 10 additions & 10 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@

install_requires = [
'Keras>=2.4,<2.13',
'mlblocks>=0.6',
'numpy<1.21.0,>=1.16.0',
'pandas>=1,<2',
'mlblocks>=0.6.1',
'numpy>=1.17.4,<2',
'pandas>=1,<3',
'scikit-learn>=0.21,<1.2',
'scipy>=1.1.0,<2',
'statsmodels>=0.9.0,<0.13',
'statsmodels>=0.12.0,<0.15',
'tensorflow>=2,<2.13',
'xgboost>=0.72.1,<1',
'xgboost>=0.72.1,<2',

# fix google/protobuf/descriptor
'protobuf<4',
Expand Down Expand Up @@ -46,10 +46,8 @@
'nbsphinx>=0.5.0,<0.7',
'Sphinx>=3,<3.3',
'pydata-sphinx-theme<0.5',
'autodocsumm>=0.1.10,<1',
'markupsafe<2.1.0',
'ipython>=6.5,<7.5',
'mistune>=0.7,<2',
'ipython>=6.5,<9',
'Jinja2>=2,<3',

# style check
Expand All @@ -68,6 +66,7 @@
# Advanced testing
'coverage>=4.5.1',
'tox>=2.9.1',
'invoke',
]

setup(
Expand All @@ -79,10 +78,11 @@
'License :: OSI Approved :: MIT License',
'Natural Language :: English',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Programming Language :: Python :: 3.9',
'Programming Language :: Python :: 3.10',
'Programming Language :: Python :: 3.11',
],
description='Primitives and Pipelines for Time Series Data.',
entry_points={
Expand All @@ -104,7 +104,7 @@
keywords='mlstars',
name='ml-stars',
packages=find_packages(include=['mlstars', 'mlstars.*']),
python_requires='>=3.6,<3.10',
python_requires='>=3.7,<3.12',
setup_requires=setup_requires,
test_suite='tests',
tests_require=tests_require,
Expand Down
2 changes: 1 addition & 1 deletion tests/adapters/test_pandas.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

import numpy as np
import pandas as pd
from pandas.util.testing import assert_frame_equal
from pandas.testing import assert_frame_equal

from mlstars.adapters.pandas import resample

Expand Down
33 changes: 21 additions & 12 deletions tests/adapters/test_statsmodels.py
Original file line number Diff line number Diff line change
@@ -1,25 +1,26 @@
from unittest.mock import patch

import numpy as np
import pytest
from numpy.testing import assert_allclose

from mlstars.adapters.statsmodels import ARIMA


@patch('statsmodels.tsa.arima_model.ARIMA')
@patch('statsmodels.tsa.arima.model.ARIMA')
def test_arima_1d(arima_mock):
arima = ARIMA(1, 0, 0, 3)
arima = ARIMA(1, 0, 0, 't', 3)
X = np.array([1, 2, 3, 4, 5])
arima.predict(X)
assert_allclose(arima_mock.call_args[0][0], [1, 2, 3, 4, 5])
assert arima_mock.call_args[1] == {'order': (1, 0, 0)}
assert arima_mock.call_args[1] == {'order': (1, 0, 0), 'trend': 't'}


@patch('statsmodels.tsa.arima_model.ARMAResults.forecast')
@patch('statsmodels.tsa.arima.model.ARIMAResultsWrapper.forecast')
def test_predict_1d(arima_mock):
arima_mock.return_value = [[1, 2, 3]]

arima = ARIMA(1, 0, 0, 3)
arima = ARIMA(1, 0, 0, 't', 3)

X = np.array([1, 2, 3, 4, 5])
result = arima.predict(X)
Expand All @@ -29,9 +30,9 @@ def test_predict_1d(arima_mock):
arima_mock.assert_called_once_with(3)


@patch('statsmodels.tsa.arima_model.ARIMA')
@patch('statsmodels.tsa.arima.model.ARIMA')
def test_arima_2d(arima_mock):
arima = ARIMA(1, 0, 0, 3)
arima = ARIMA(1, 0, 0, 't', 3)
X = np.array([
[1, 2, 3, 4, 5],
[6, 7, 8, 9, 10],
Expand All @@ -41,19 +42,19 @@ def test_arima_2d(arima_mock):
assert_allclose(arima_mock.call_args_list[0][0], [[1, 2, 3, 4, 5]])
assert_allclose(arima_mock.call_args_list[1][0], [[6, 7, 8, 9, 10]])
assert_allclose(arima_mock.call_args_list[2][0], [[11, 12, 13, 14, 15]])
assert arima_mock.call_args_list[0][1] == {'order': (1, 0, 0)}
assert arima_mock.call_args_list[1][1] == {'order': (1, 0, 0)}
assert arima_mock.call_args_list[2][1] == {'order': (1, 0, 0)}
assert arima_mock.call_args_list[0][1] == {'order': (1, 0, 0), 'trend': 't'}
assert arima_mock.call_args_list[1][1] == {'order': (1, 0, 0), 'trend': 't'}
assert arima_mock.call_args_list[2][1] == {'order': (1, 0, 0), 'trend': 't'}


@patch('statsmodels.tsa.arima_model.ARMAResults.forecast')
@patch('statsmodels.tsa.arima.model.ARIMAResultsWrapper.forecast')
def test_predict_2d(arima_mock):
arima_mock.side_effect = [
[[1, 2, 3]],
[[4, 5, 6]],
[[7, 8, 9]],
]
arima = ARIMA(1, 0, 0, 3)
arima = ARIMA(1, 0, 0, 't', 3)

X = np.array([
[1, 2, 3, 4, 5],
Expand All @@ -69,3 +70,11 @@ def test_predict_2d(arima_mock):
])
assert_allclose(result, expected)
arima_mock.assert_called_with(3)


@patch('statsmodels.tsa.arima.model.ARIMA')
def test_arima_3d(arima_mock):
arima = ARIMA(1, 0, 0, 'ct', 3)
X = np.ones(shape=(3, 2, 1))
with pytest.raises(ValueError):
arima.predict(X)
33 changes: 2 additions & 31 deletions tests/custom/test_timeseries_preprocessing.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@
from numpy.testing import assert_allclose

from mlstars.custom.timeseries_preprocessing import (
cutoff_window_sequences, intervals_to_mask, rolling_window_sequences, time_segments_aggregate,
time_segments_average,)
cutoff_window_sequences, intervals_to_mask, rolling_window_sequences, time_segments_aggregate,)


class IntervalsToMaskTest(TestCase):
Expand Down Expand Up @@ -178,34 +177,6 @@ def test_drop_bool(self):
drop=drop, drop_windows=True)


class TimeSegmentsAverageTest(TestCase):

def _run(self, X, interval, expected_values, expected_index, time_column):
values, index = time_segments_average(X, interval, time_column)

assert_allclose(values, expected_values)
assert_allclose(index, expected_index)

def test_array(self):
X = np.array([[1, 1], [2, 3], [3, 1], [4, 3]])
interval = 2
expected_values = np.array([[2], [2]])
expected_index = np.array([1, 3])
self._run(X, interval, expected_values, expected_index, time_column=0)

def test_pandas_dataframe(self):
X = pd.DataFrame([
[1, 1],
[2, 3],
[3, 1],
[4, 3]
], columns=['timestamp', 'value'])
interval = 2
expected_values = np.array([[2], [2]])
expected_index = np.array([1, 3])
self._run(X, interval, expected_values, expected_index, time_column="timestamp")


class TimeSegmentsAggregateTest(TestCase):

def _run(self, X, interval, expected_values, expected_index, time_column, method=['mean']):
Expand Down Expand Up @@ -417,7 +388,7 @@ def test_not_enough_data(self):
[15, 35],
[16, 36]
])
])
], dtype=object)

assert_allclose(
array[0],
Expand Down
4 changes: 2 additions & 2 deletions tox.ini
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[tox]
envlist = lint, docs, py3{6,7}-{readme,pytest,minimum,tutorials}
envlist = lint, docs, py3{7, 8, 9, 10, 11}-{readme,pytest,minimum,tutorials}

[testenv]
skipsdist = false
Expand All @@ -20,4 +20,4 @@ commands =
pytest: invoke pytest
minimum: invoke minimum
tutorials: invoke tutorials
invoke rmdir --path {envdir}
invoke rmdir --path {envdir}
Loading