diff --git a/.github/workflows/periodic_tests.yml b/.github/workflows/periodic_tests.yml index 8c5eeca564..ac81989b27 100644 --- a/.github/workflows/periodic_tests.yml +++ b/.github/workflows/periodic_tests.yml @@ -83,6 +83,31 @@ jobs: # Save cache with the current date (ENV set in numba_cache action) key: numba-run-notebook-examples-${{ runner.os }}-3.10-${{ env.CURRENT_DATE }} + test-core-imports: + runs-on: ubuntu-22.04 + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Python 3.10 + uses: actions/setup-python@v5 + with: + python-version: "3.10" + + - name: Install aeon and dependencies + uses: nick-fields/retry@v3 + with: + timeout_minutes: 30 + max_attempts: 3 + command: python -m pip install . + + - name: Show dependencies + run: python -m pip list + + - name: Run import test + run: python aeon/testing/tests/test_core_imports.py + test-no-soft-deps: runs-on: ubuntu-22.04 diff --git a/.github/workflows/pr_core_dep_import.yml b/.github/workflows/pr_core_dep_import.yml new file mode 100644 index 0000000000..19fb56e294 --- /dev/null +++ b/.github/workflows/pr_core_dep_import.yml @@ -0,0 +1,43 @@ +name: PR module imports + +on: + push: + branches: + - main + pull_request: + branches: + - main + paths: + - "aeon/**" + - ".github/workflows/**" + - "pyproject.toml" + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.ref }} + cancel-in-progress: true + +jobs: + test-core-imports: + runs-on: ubuntu-22.04 + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Python 3.10 + uses: actions/setup-python@v5 + with: + python-version: "3.10" + + - name: Install aeon and dependencies + uses: nick-fields/retry@v3 + with: + timeout_minutes: 30 + max_attempts: 3 + command: python -m pip install . + + - name: Show dependencies + run: python -m pip list + + - name: Run import test + run: python aeon/testing/tests/test_core_imports.py diff --git a/.github/workflows/pr_pytest.yml b/.github/workflows/pr_pytest.yml index 0a5ed4c673..abbb0f596f 100644 --- a/.github/workflows/pr_pytest.yml +++ b/.github/workflows/pr_pytest.yml @@ -48,7 +48,7 @@ jobs: run: python -m pip list - name: Run tests - run: python -m pytest -n logical -k 'not TestAll' + run: python -m pytest -n logical pytest: runs-on: ${{ matrix.os }} diff --git a/.readthedocs.yml b/.readthedocs.yml index c031c0d25b..1b016c167c 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -11,7 +11,7 @@ python: - docs build: - os: ubuntu-20.04 + os: ubuntu-22.04 tools: python: "3.10" diff --git a/README.md b/README.md index f51a79291a..0763b2f5de 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,7 @@ The following modules are still considered experimental, and the [deprecation po does not apply: - `anomaly_detection` +- `forecasting` - `segmentation` - `similarity_search` - `visualisation` diff --git a/aeon/base/tests/test_base_collection.py b/aeon/base/tests/test_base_collection.py index 97e2232c66..fff1f75f38 100644 --- a/aeon/base/tests/test_base_collection.py +++ b/aeon/base/tests/test_base_collection.py @@ -14,7 +14,7 @@ UNEQUAL_LENGTH_MULTIVARIATE_CLASSIFICATION, UNEQUAL_LENGTH_UNIVARIATE_CLASSIFICATION, ) -from aeon.utils import COLLECTIONS_DATA_TYPES +from aeon.utils.data_types import COLLECTIONS_DATA_TYPES from aeon.utils.validation import get_type diff --git a/aeon/classification/tests/test_base.py b/aeon/classification/tests/test_base.py index e59baa1bf4..49782cab85 100644 --- a/aeon/classification/tests/test_base.py +++ b/aeon/classification/tests/test_base.py @@ -15,7 +15,7 @@ EQUAL_LENGTH_UNIVARIATE_CLASSIFICATION, UNEQUAL_LENGTH_UNIVARIATE_CLASSIFICATION, ) -from aeon.utils import COLLECTIONS_DATA_TYPES +from aeon.utils.data_types import COLLECTIONS_DATA_TYPES __maintainer__ = [] diff --git a/aeon/pipeline/__init__.py b/aeon/pipeline/__init__.py index 732dae0187..a0b15f190f 100644 --- a/aeon/pipeline/__init__.py +++ b/aeon/pipeline/__init__.py @@ -1,6 +1,9 @@ """Pipeline maker utility.""" -__all__ = ["make_pipeline", "sklearn_to_aeon"] +__all__ = [ + "make_pipeline", + "sklearn_to_aeon", +] from aeon.pipeline._make_pipeline import make_pipeline from aeon.pipeline._sklearn_to_aeon import sklearn_to_aeon diff --git a/aeon/regression/compose/tests/test_ensemble.py b/aeon/regression/compose/tests/test_ensemble.py index 447afda327..4d5b288de7 100644 --- a/aeon/regression/compose/tests/test_ensemble.py +++ b/aeon/regression/compose/tests/test_ensemble.py @@ -14,7 +14,7 @@ make_example_3d_numpy, make_example_3d_numpy_list, ) -from aeon.testing.mock_estimators import MockHandlesAllInput, MockRegressor +from aeon.testing.mock_estimators import MockRegressor, MockRegressorFullTags mixed_ensemble = [ DummyRegressor(), @@ -114,7 +114,7 @@ def test_unequal_tag_inference(): n_cases=10, min_n_timepoints=8, max_n_timepoints=12, regression_target=True ) - r1 = MockHandlesAllInput() + r1 = MockRegressorFullTags() r2 = MockRegressor() assert r1.get_tag("capability:unequal_length") @@ -144,7 +144,7 @@ def test_missing_tag_inference(): X, y = make_example_3d_numpy(n_cases=10, n_timepoints=12, regression_target=True) X[5, 0, 4] = np.nan - r1 = MockHandlesAllInput() + r1 = MockRegressorFullTags() r2 = MockRegressor() assert r1.get_tag("capability:missing_values") @@ -175,7 +175,7 @@ def test_multivariate_tag_inference(): n_cases=10, n_channels=2, n_timepoints=12, regression_target=True ) - r1 = MockHandlesAllInput() + r1 = MockRegressorFullTags() r2 = MockRegressor() assert r1.get_tag("capability:multivariate") diff --git a/aeon/regression/tests/test_base.py b/aeon/regression/tests/test_base.py index 30302de8c7..d04469db8b 100644 --- a/aeon/regression/tests/test_base.py +++ b/aeon/regression/tests/test_base.py @@ -12,7 +12,7 @@ EQUAL_LENGTH_UNIVARIATE_REGRESSION, UNEQUAL_LENGTH_UNIVARIATE_REGRESSION, ) -from aeon.utils import COLLECTIONS_DATA_TYPES +from aeon.utils.data_types import COLLECTIONS_DATA_TYPES class _TestRegressor(BaseRegressor): diff --git a/aeon/segmentation/tests/test_base.py b/aeon/segmentation/tests/test_base.py index 013e4ecdad..870fbdb7e5 100644 --- a/aeon/segmentation/tests/test_base.py +++ b/aeon/segmentation/tests/test_base.py @@ -5,7 +5,7 @@ import pytest from aeon.segmentation.base import BaseSegmenter -from aeon.testing.mock_estimators import MockSegmenter, SupervisedMockSegmenter +from aeon.testing.mock_estimators import MockSegmenter, MockSegmenterRequiresY def test_fit_predict_correct(): @@ -25,7 +25,7 @@ def test_fit_predict_correct(): assert res.is_fitted res = seg.fit_predict(x_correct) assert isinstance(res, np.ndarray) - seg = SupervisedMockSegmenter() + seg = MockSegmenterRequiresY() res = seg.fit(x_correct, y=x_correct) assert res.is_fitted with pytest.raises( diff --git a/aeon/testing/estimator_checking/_estimator_checking.py b/aeon/testing/estimator_checking/_estimator_checking.py index c07815ea89..97eed5a0e9 100644 --- a/aeon/testing/estimator_checking/_estimator_checking.py +++ b/aeon/testing/estimator_checking/_estimator_checking.py @@ -193,6 +193,7 @@ class is passed. {'check_get_params(estimator=MockClassifier())': 'PASSED'} """ # check if estimator has soft dependencies installed + _check_soft_dependencies("pytest") _check_estimator_deps(estimator) checks = [] diff --git a/aeon/testing/estimator_checking/_yield_anomaly_detection_checks.py b/aeon/testing/estimator_checking/_yield_anomaly_detection_checks.py index 0d94fbc34f..5f2f05aaa9 100644 --- a/aeon/testing/estimator_checking/_yield_anomaly_detection_checks.py +++ b/aeon/testing/estimator_checking/_yield_anomaly_detection_checks.py @@ -3,7 +3,6 @@ from functools import partial import numpy as np -import pytest from aeon.base._base import _clone_estimator from aeon.base._base_series import VALID_SERIES_INNER_TYPES @@ -64,6 +63,8 @@ def check_anomaly_detector_overrides_and_tags(estimator_class): def check_anomaly_detector_univariate(estimator): """Test the anomaly detector on univariate data.""" + import pytest + estimator = _clone_estimator(estimator) if estimator.get_tag(tag_name="capability:univariate"): @@ -78,6 +79,8 @@ def check_anomaly_detector_univariate(estimator): def check_anomaly_detector_multivariate(estimator): """Test the anomaly detector on multivariate data.""" + import pytest + estimator = _clone_estimator(estimator) if estimator.get_tag(tag_name="capability:multivariate"): diff --git a/aeon/testing/estimator_checking/_yield_classification_checks.py b/aeon/testing/estimator_checking/_yield_classification_checks.py index 00b82705de..09f15877be 100644 --- a/aeon/testing/estimator_checking/_yield_classification_checks.py +++ b/aeon/testing/estimator_checking/_yield_classification_checks.py @@ -24,7 +24,7 @@ _assert_predict_probabilities, _get_tag, ) -from aeon.utils import COLLECTIONS_DATA_TYPES +from aeon.utils.data_types import COLLECTIONS_DATA_TYPES from aeon.utils.validation import get_n_cases diff --git a/aeon/testing/estimator_checking/_yield_estimator_checks.py b/aeon/testing/estimator_checking/_yield_estimator_checks.py index b5fb60c1d3..70f714d4d9 100644 --- a/aeon/testing/estimator_checking/_yield_estimator_checks.py +++ b/aeon/testing/estimator_checking/_yield_estimator_checks.py @@ -9,7 +9,6 @@ import joblib import numpy as np -import pytest from numpy.testing import assert_array_almost_equal from sklearn.exceptions import NotFittedError @@ -596,6 +595,8 @@ def check_fit_updates_state_and_cloning(estimator, datatype): def check_raises_not_fitted_error(estimator, datatype): """Check exception raised for non-fit method calls to unfitted estimators.""" + import pytest + estimator = _clone_estimator(estimator) for method in NON_STATE_CHANGING_METHODS: diff --git a/aeon/testing/estimator_checking/_yield_regression_checks.py b/aeon/testing/estimator_checking/_yield_regression_checks.py index bf6d2cb568..52933e81f7 100644 --- a/aeon/testing/estimator_checking/_yield_regression_checks.py +++ b/aeon/testing/estimator_checking/_yield_regression_checks.py @@ -20,7 +20,7 @@ ) from aeon.testing.testing_data import FULL_TEST_DATA_DICT from aeon.testing.utils.estimator_checks import _assert_predict_labels, _get_tag -from aeon.utils import COLLECTIONS_DATA_TYPES +from aeon.utils.data_types import COLLECTIONS_DATA_TYPES def _yield_regression_checks(estimator_class, estimator_instances, datatypes): diff --git a/aeon/testing/estimator_checking/_yield_segmentation_checks.py b/aeon/testing/estimator_checking/_yield_segmentation_checks.py index 6c2c964f5a..054ca56bd4 100644 --- a/aeon/testing/estimator_checking/_yield_segmentation_checks.py +++ b/aeon/testing/estimator_checking/_yield_segmentation_checks.py @@ -3,7 +3,6 @@ from functools import partial import numpy as np -import pytest from aeon.base._base import _clone_estimator from aeon.base._base_series import VALID_SERIES_INNER_TYPES @@ -42,6 +41,8 @@ def check_segmenter_base_functionality(estimator_class): def check_segmenter_instance(estimator): """Test segmenters.""" + import pytest + estimator = _clone_estimator(estimator) def _assert_output(output, dense, length): diff --git a/aeon/testing/estimator_checking/_yield_soft_dependency_checks.py b/aeon/testing/estimator_checking/_yield_soft_dependency_checks.py index 83c6f96b83..ed5c9605b1 100644 --- a/aeon/testing/estimator_checking/_yield_soft_dependency_checks.py +++ b/aeon/testing/estimator_checking/_yield_soft_dependency_checks.py @@ -6,8 +6,6 @@ from functools import partial -import pytest - from aeon.utils.validation._dependencies import ( _check_python_version, _check_soft_dependencies, @@ -23,6 +21,8 @@ def _yield_soft_dependency_checks(estimator_class, estimator_instances, datatype def check_python_version_softdep(estimator_class): """Test that estimators raise error if python version is wrong.""" + import pytest + # if dependencies are incompatible skip softdeps = estimator_class.get_class_tag("python_dependencies", None) if softdeps is not None and not _check_soft_dependencies(softdeps, severity="none"): @@ -46,6 +46,8 @@ def check_python_version_softdep(estimator_class): def check_python_dependency_softdep(estimator_class): """Test that estimators raise error if required soft dependencies are missing.""" + import pytest + # if python version is incompatible skip if not _check_python_version(estimator_class, severity="none"): return diff --git a/aeon/testing/estimator_checking/_yield_transformation_checks.py b/aeon/testing/estimator_checking/_yield_transformation_checks.py index 507c8c1e08..4a8c51f795 100644 --- a/aeon/testing/estimator_checking/_yield_transformation_checks.py +++ b/aeon/testing/estimator_checking/_yield_transformation_checks.py @@ -20,7 +20,7 @@ from aeon.testing.utils.estimator_checks import _run_estimator_method from aeon.transformations.collection.channel_selection.base import BaseChannelSelector from aeon.transformations.series import BaseSeriesTransformer -from aeon.utils import COLLECTIONS_DATA_TYPES +from aeon.utils.data_types import COLLECTIONS_DATA_TYPES def _yield_transformation_checks(estimator_class, estimator_instances, datatypes): diff --git a/aeon/testing/mock_estimators/__init__.py b/aeon/testing/mock_estimators/__init__.py index 32d947cb7d..219fc3e987 100644 --- a/aeon/testing/mock_estimators/__init__.py +++ b/aeon/testing/mock_estimators/__init__.py @@ -1,26 +1,46 @@ """Mock estimators for testing and debugging.""" __all__ = [ - "make_mock_estimator", + # anomaly detection + "MockAnomalyDetector", + "MockAnomalyDetectorRequiresFit", + "MockAnomalyDetectorRequiresY", + # classification "MockClassifier", "MockClassifierPredictProba", "MockClassifierFullTags", "MockClassifierParams", + "MockClassifierComposite", + # clustering "MockCluster", "MockDeepClusterer", - "MockSegmenter", - "SupervisedMockSegmenter", - "MockHandlesAllInput", + # collection transformation + "MockCollectionTransformer", + # forecasting + "MockForecaster", + # regression "MockRegressor", + "MockRegressorFullTags", + # segmentation + "MockSegmenter", + "MockSegmenterRequiresY", + # series transformation + "MockSeriesTransformer", + "MockUnivariateSeriesTransformer", "MockMultivariateSeriesTransformer", "MockSeriesTransformerNoFit", - "MockUnivariateSeriesTransformer", - "MockCollectionTransformer", - "MockSeriesTransformer", + # similarity search + "MockSimilaritySearch", ] +from aeon.testing.mock_estimators._mock_anomaly_detectors import ( + MockAnomalyDetector, + MockAnomalyDetectorRequiresFit, + MockAnomalyDetectorRequiresY, +) from aeon.testing.mock_estimators._mock_classifiers import ( MockClassifier, + MockClassifierComposite, MockClassifierFullTags, MockClassifierParams, MockClassifierPredictProba, @@ -29,13 +49,14 @@ from aeon.testing.mock_estimators._mock_collection_transformers import ( MockCollectionTransformer, ) +from aeon.testing.mock_estimators._mock_forecasters import MockForecaster from aeon.testing.mock_estimators._mock_regressors import ( - MockHandlesAllInput, MockRegressor, + MockRegressorFullTags, ) from aeon.testing.mock_estimators._mock_segmenters import ( MockSegmenter, - SupervisedMockSegmenter, + MockSegmenterRequiresY, ) from aeon.testing.mock_estimators._mock_series_transformers import ( MockMultivariateSeriesTransformer, @@ -43,3 +64,4 @@ MockSeriesTransformerNoFit, MockUnivariateSeriesTransformer, ) +from aeon.testing.mock_estimators._mock_similarity_search import MockSimilaritySearch diff --git a/aeon/testing/mock_estimators/_mock_anomaly_detectors.py b/aeon/testing/mock_estimators/_mock_anomaly_detectors.py index 78ddfe76f1..4ec14d35fa 100644 --- a/aeon/testing/mock_estimators/_mock_anomaly_detectors.py +++ b/aeon/testing/mock_estimators/_mock_anomaly_detectors.py @@ -1,4 +1,4 @@ -"""Mock anomaly detectors for testing.""" +"""Mock anomaly detectorsuseful for testing and debugging.""" __maintainer__ = ["MatthewMiddlehurst"] __all__ = [ diff --git a/aeon/testing/mock_estimators/_mock_classifiers.py b/aeon/testing/mock_estimators/_mock_classifiers.py index bcfcb8162e..1bf9357d60 100644 --- a/aeon/testing/mock_estimators/_mock_classifiers.py +++ b/aeon/testing/mock_estimators/_mock_classifiers.py @@ -1,7 +1,13 @@ -"""Mock classifiers useful for testing and debugging. - -Used in tests for the classifier base class. -""" +"""Mock classifiers useful for testing and debugging.""" + +__maintainer__ = ["MatthewMiddlehurst"] +__all__ = [ + "MockClassifier", + "MockClassifierPredictProba", + "MockClassifierFullTags", + "MockClassifierParams", + "MockClassifierComposite", +] import numpy as np diff --git a/aeon/testing/mock_estimators/_mock_clusterers.py b/aeon/testing/mock_estimators/_mock_clusterers.py index b920b83c30..53b1014290 100644 --- a/aeon/testing/mock_estimators/_mock_clusterers.py +++ b/aeon/testing/mock_estimators/_mock_clusterers.py @@ -1,3 +1,11 @@ +"""Mock clusterers useful for testing and debugging.""" + +__maintainer__ = [] +__all__ = [ + "MockCluster", + "MockDeepClusterer", +] + import numpy as np from aeon.clustering.base import BaseClusterer diff --git a/aeon/testing/mock_estimators/_mock_collection_transformers.py b/aeon/testing/mock_estimators/_mock_collection_transformers.py index bc59069283..7feb8d46a9 100644 --- a/aeon/testing/mock_estimators/_mock_collection_transformers.py +++ b/aeon/testing/mock_estimators/_mock_collection_transformers.py @@ -1,4 +1,9 @@ -"""Mock collection transformers.""" +"""Mock collection transformers useful for testing and debugging.""" + +__maintainer__ = [] +__all__ = [ + "MockCollectionTransformer", +] from aeon.transformations.collection import BaseCollectionTransformer diff --git a/aeon/testing/mock_estimators/_mock_forecasters.py b/aeon/testing/mock_estimators/_mock_forecasters.py index f5bb86d249..8eb2ba2635 100644 --- a/aeon/testing/mock_estimators/_mock_forecasters.py +++ b/aeon/testing/mock_estimators/_mock_forecasters.py @@ -1,7 +1,10 @@ -"""Mock forecasters useful for testing and debugging. +"""Mock forecasters useful for testing and debugging.""" + +__maintainer__ = ["TonyBagnall"] +__all__ = [ + "MockForecaster", +] -Used in tests for the forecasting base class. -""" from aeon.forecasting.base import BaseForecaster diff --git a/aeon/testing/mock_estimators/_mock_regressors.py b/aeon/testing/mock_estimators/_mock_regressors.py index 355534abac..5258019aab 100644 --- a/aeon/testing/mock_estimators/_mock_regressors.py +++ b/aeon/testing/mock_estimators/_mock_regressors.py @@ -1,3 +1,11 @@ +"""Mock regressors useful for testing and debugging.""" + +__maintainer__ = ["MatthewMiddlehurst"] +__all__ = [ + "MockRegressor", + "MockRegressorFullTags", +] + from sklearn.utils import check_random_state from aeon.regression.base import BaseRegressor @@ -20,7 +28,7 @@ def _predict(self, X): return rng.random(size=(len(X))) -class MockHandlesAllInput(BaseRegressor): +class MockRegressorFullTags(BaseRegressor): """Dummy regressor for testing base class fit/predict/predict_proba.""" _tags = { diff --git a/aeon/testing/mock_estimators/_mock_segmenters.py b/aeon/testing/mock_estimators/_mock_segmenters.py index 82ff6a81f6..45b7a524aa 100644 --- a/aeon/testing/mock_estimators/_mock_segmenters.py +++ b/aeon/testing/mock_estimators/_mock_segmenters.py @@ -1,4 +1,10 @@ -"""Mock segmenters for testing.""" +"""Mock segmenters useful for testing and debugging.""" + +__maintainer__ = [] +__all__ = [ + "MockSegmenter", + "MockSegmenterRequiresY", +] import numpy as np @@ -42,7 +48,7 @@ def _get_test_params(cls, parameter_set="default"): return {} -class SupervisedMockSegmenter(MockSegmenter): +class MockSegmenterRequiresY(MockSegmenter): """Mock segmenter for testing.""" _tags = { diff --git a/aeon/testing/mock_estimators/_mock_series_transformers.py b/aeon/testing/mock_estimators/_mock_series_transformers.py index 937f4a6325..66d62ef687 100644 --- a/aeon/testing/mock_estimators/_mock_series_transformers.py +++ b/aeon/testing/mock_estimators/_mock_series_transformers.py @@ -1,4 +1,12 @@ -"""Mock series transformers.""" +"""Mock series transformers useful for testing and debugging.""" + +__maintainer__ = [] +__all__ = [ + "MockSeriesTransformer", + "MockUnivariateSeriesTransformer", + "MockMultivariateSeriesTransformer", + "MockSeriesTransformerNoFit", +] import numpy as np diff --git a/aeon/testing/mock_estimators/_mock_similarity_search.py b/aeon/testing/mock_estimators/_mock_similarity_search.py index 8542b81a1b..55c9c435c7 100644 --- a/aeon/testing/mock_estimators/_mock_similarity_search.py +++ b/aeon/testing/mock_estimators/_mock_similarity_search.py @@ -1,12 +1,14 @@ -"""Mock similarity search useful for testing and debugging. +"""Mock similarity searchers useful for testing and debugging.""" -Used in tests for the query search base class. -""" +__maintainer__ = ["baraline"] +__all__ = [ + "MockSimilaritySearch", +] from aeon.similarity_search.base import BaseSimilaritySearch -class MocksimilaritySearch(BaseSimilaritySearch): +class MockSimilaritySearch(BaseSimilaritySearch): """Mock similarity search for testing base class predict.""" def _fit(self, X, y=None): diff --git a/aeon/testing/tests/__init__.py b/aeon/testing/tests/__init__.py index 69d1ff2d83..aaeacff24d 100644 --- a/aeon/testing/tests/__init__.py +++ b/aeon/testing/tests/__init__.py @@ -1 +1,13 @@ -"""Tests for the aeon package and testing module utiltiies.""" +"""Tests for the aeon package and testing module utilties.""" + +import pkgutil + +import aeon + +# collect all modules +ALL_AEON_MODULES = pkgutil.walk_packages(aeon.__path__, aeon.__name__ + ".") +ALL_AEON_MODULES = [x[1] for x in ALL_AEON_MODULES] + +ALL_AEON_MODULES_NO_TESTS = [ + x for x in ALL_AEON_MODULES if not any(part == "tests" for part in x.split(".")) +] diff --git a/aeon/testing/tests/test_core_imports.py b/aeon/testing/tests/test_core_imports.py new file mode 100644 index 0000000000..f13740c08e --- /dev/null +++ b/aeon/testing/tests/test_core_imports.py @@ -0,0 +1,26 @@ +"""Tests that non-core dependencies are handled correctly in modules.""" + +import re +from importlib import import_module + +from aeon.testing.tests import ALL_AEON_MODULES_NO_TESTS + +if __name__ == "__main__": + """Test imports in aeon modules with core dependencies only. + + Imports all modules and catch exceptions due to missing dependencies. + """ + for module in ALL_AEON_MODULES_NO_TESTS: + try: + import_module(module) + except ModuleNotFoundError as e: # pragma: no cover + dependency = "unknown" + match = re.search(r"\'(.+?)\'", str(e)) + if match: + dependency = match.group(1) + + raise ModuleNotFoundError( + f"The module: {module} should not require any non-core dependencies, " + f"but tried importing: '{dependency}'. Make sure non-core dependencies " + f"are properly isolated outside of tests/ directories." + ) from e diff --git a/aeon/testing/tests/test_softdeps.py b/aeon/testing/tests/test_softdeps.py index 830d0e80f0..2271d21497 100644 --- a/aeon/testing/tests/test_softdeps.py +++ b/aeon/testing/tests/test_softdeps.py @@ -1,23 +1,14 @@ """Tests that soft dependencies are handled correctly in modules.""" -__maintainer__ = [] - -import pkgutil import re from importlib import import_module import pytest -import aeon from aeon.testing.testing_config import PR_TESTING +from aeon.testing.tests import ALL_AEON_MODULES, ALL_AEON_MODULES_NO_TESTS -# collect all modules -modules = pkgutil.walk_packages(aeon.__path__, aeon.__name__ + ".") -modules = [x[1] for x in modules] - -if PR_TESTING: # pragma: no cover - # exclude test modules - modules = [x for x in modules if not any(part == "tests" for part in x.split("."))] +modules = ALL_AEON_MODULES_NO_TESTS if PR_TESTING else ALL_AEON_MODULES def test_module_crawl(): diff --git a/aeon/testing/tests/test_testing_data.py b/aeon/testing/tests/test_testing_data.py index 505cb474a8..f9afe264dd 100644 --- a/aeon/testing/tests/test_testing_data.py +++ b/aeon/testing/tests/test_testing_data.py @@ -20,7 +20,7 @@ UNEQUAL_LENGTH_UNIVARIATE_REGRESSION, UNEQUAL_LENGTH_UNIVARIATE_SIMILARITY_SEARCH, ) -from aeon.utils import COLLECTIONS_DATA_TYPES +from aeon.utils.data_types import COLLECTIONS_DATA_TYPES from aeon.utils.validation import ( has_missing, is_collection, diff --git a/aeon/testing/utils/deep_equals.py b/aeon/testing/utils/deep_equals.py index 86c6c5cd96..81f6d91534 100644 --- a/aeon/testing/utils/deep_equals.py +++ b/aeon/testing/utils/deep_equals.py @@ -1,6 +1,6 @@ """Testing utility to compare equality in value for nested objects.""" -__maintainer__ = [] +__maintainer__ = ["MatthewMiddlehurst"] __all__ = ["deep_equals"] from inspect import isclass diff --git a/aeon/testing/utils/output_supression.py b/aeon/testing/utils/output_suppression.py similarity index 100% rename from aeon/testing/utils/output_supression.py rename to aeon/testing/utils/output_suppression.py diff --git a/aeon/testing/utils/tests/test_output_supression.py b/aeon/testing/utils/tests/test_output_supression.py index 8e8b0a4862..56f7b18ec5 100644 --- a/aeon/testing/utils/tests/test_output_supression.py +++ b/aeon/testing/utils/tests/test_output_supression.py @@ -2,7 +2,7 @@ import sys -from aeon.testing.utils.output_supression import suppress_output +from aeon.testing.utils.output_suppression import suppress_output @suppress_output() diff --git a/aeon/transformations/collection/_hog1d.py b/aeon/transformations/collection/_hog1d.py index 3deddf5931..a3cc18d8aa 100644 --- a/aeon/transformations/collection/_hog1d.py +++ b/aeon/transformations/collection/_hog1d.py @@ -6,7 +6,7 @@ import numpy as np from aeon.transformations.collection.base import BaseCollectionTransformer -from aeon.utils import split_series +from aeon.utils.split import split_series class HOG1DTransformer(BaseCollectionTransformer): diff --git a/aeon/transformations/collection/_slope.py b/aeon/transformations/collection/_slope.py index 7a11cbcdb6..cf9d860478 100644 --- a/aeon/transformations/collection/_slope.py +++ b/aeon/transformations/collection/_slope.py @@ -8,7 +8,7 @@ import numpy as np from aeon.transformations.collection.base import BaseCollectionTransformer -from aeon.utils import split_series +from aeon.utils.split import split_series class SlopeTransformer(BaseCollectionTransformer): diff --git a/aeon/transformations/collection/compose/_identity.py b/aeon/transformations/collection/compose/_identity.py index 20c6674b6b..a359255242 100644 --- a/aeon/transformations/collection/compose/_identity.py +++ b/aeon/transformations/collection/compose/_identity.py @@ -1,7 +1,7 @@ """Identity transformer.""" from aeon.transformations.collection import BaseCollectionTransformer -from aeon.utils import COLLECTIONS_DATA_TYPES +from aeon.utils.data_types import COLLECTIONS_DATA_TYPES class CollectionId(BaseCollectionTransformer): diff --git a/aeon/utils/__init__.py b/aeon/utils/__init__.py index 8f16b7102d..e198bb676e 100644 --- a/aeon/utils/__init__.py +++ b/aeon/utils/__init__.py @@ -1,20 +1,7 @@ """Utility functionality.""" __all__ = [ - "split_series", - "ALL_TIME_SERIES_TYPES", - "COLLECTIONS_DATA_TYPES", - "SERIES_DATA_TYPES", - "HIERARCHICAL_DATA_TYPES", - # github debug util - "show_versions", + "show_versions", # github debug util ] -from aeon.utils._data_types import ( - ALL_TIME_SERIES_TYPES, - COLLECTIONS_DATA_TYPES, - HIERARCHICAL_DATA_TYPES, - SERIES_DATA_TYPES, -) -from aeon.utils._split import split_series from aeon.utils.show_versions import show_versions diff --git a/aeon/utils/conversion/_convert_collection.py b/aeon/utils/conversion/_convert_collection.py index e41ed0c8a2..0e3e28f1af 100644 --- a/aeon/utils/conversion/_convert_collection.py +++ b/aeon/utils/conversion/_convert_collection.py @@ -22,7 +22,7 @@ import pandas as pd from numba.typed import List as NumbaList -from aeon.utils._data_types import COLLECTIONS_DATA_TYPES +from aeon.utils.data_types import COLLECTIONS_DATA_TYPES from aeon.utils.validation.collection import _equal_length, get_type diff --git a/aeon/utils/conversion/tests/test_convert_collection.py b/aeon/utils/conversion/tests/test_convert_collection.py index e9940aa673..3776dc7f4f 100644 --- a/aeon/utils/conversion/tests/test_convert_collection.py +++ b/aeon/utils/conversion/tests/test_convert_collection.py @@ -8,7 +8,6 @@ EQUAL_LENGTH_UNIVARIATE_CLASSIFICATION, UNEQUAL_LENGTH_UNIVARIATE_CLASSIFICATION, ) -from aeon.utils import COLLECTIONS_DATA_TYPES from aeon.utils.conversion._convert_collection import ( _from_numpy2d_to_df_list, _from_numpy2d_to_np_list, @@ -24,6 +23,7 @@ resolve_equal_length_inner_type, resolve_unequal_length_inner_type, ) +from aeon.utils.data_types import COLLECTIONS_DATA_TYPES from aeon.utils.validation.collection import ( _equal_length, get_n_cases, diff --git a/aeon/utils/_data_types.py b/aeon/utils/data_types.py similarity index 100% rename from aeon/utils/_data_types.py rename to aeon/utils/data_types.py diff --git a/aeon/utils/networks/weight_norm.py b/aeon/utils/networks/weight_norm.py index 1a613f9b64..459cfd7104 100644 --- a/aeon/utils/networks/weight_norm.py +++ b/aeon/utils/networks/weight_norm.py @@ -5,7 +5,7 @@ if _check_soft_dependencies(["tensorflow"], severity="none"): import tensorflow as tf - class WeightNormalization(tf.keras.layers.Wrapper): + class _WeightNormalization(tf.keras.layers.Wrapper): """Apply weight normalization to a Keras layer.""" def __init__(self, layer, **kwargs): diff --git a/aeon/utils/sklearn.py b/aeon/utils/sklearn.py index 1f7d45a6fc..8ee26cf311 100644 --- a/aeon/utils/sklearn.py +++ b/aeon/utils/sklearn.py @@ -1,5 +1,15 @@ """Sklearn related typing and inheritance checking utility.""" +__maintainer__ = [] +__all__ = [ + "is_sklearn_estimator", + "sklearn_estimator_identifier", + "is_sklearn_transformer", + "is_sklearn_classifier", + "is_sklearn_regressor", + "is_sklearn_clusterer", +] + from inspect import isclass from sklearn.base import ( @@ -12,8 +22,6 @@ from sklearn.model_selection import GridSearchCV, RandomizedSearchCV from sklearn.pipeline import Pipeline -__maintainer__ = [] - from aeon.base import BaseAeonEstimator diff --git a/aeon/utils/_split.py b/aeon/utils/split.py similarity index 100% rename from aeon/utils/_split.py rename to aeon/utils/split.py diff --git a/aeon/utils/tags/_tags.py b/aeon/utils/tags/_tags.py index 554584115e..e1bacdd5ad 100644 --- a/aeon/utils/tags/_tags.py +++ b/aeon/utils/tags/_tags.py @@ -17,7 +17,7 @@ class : identifier for the base class of objects this tag applies to __maintainer__ = ["MatthewMiddlehurst"] __all__ = ["ESTIMATOR_TAGS"] -from aeon.utils import COLLECTIONS_DATA_TYPES, SERIES_DATA_TYPES +from aeon.utils.data_types import COLLECTIONS_DATA_TYPES, SERIES_DATA_TYPES ESTIMATOR_TAGS = { # all estimators diff --git a/aeon/utils/tests/test_show_versions.py b/aeon/utils/tests/test_show_versions.py index 866692a7d6..b47810ed98 100644 --- a/aeon/utils/tests/test_show_versions.py +++ b/aeon/utils/tests/test_show_versions.py @@ -1,6 +1,6 @@ """Test the show versions function.""" -from aeon.testing.utils.output_supression import suppress_output +from aeon.testing.utils.output_suppression import suppress_output from aeon.utils.show_versions import show_versions diff --git a/aeon/utils/tests/test_split.py b/aeon/utils/tests/test_split.py index 3c4f8df751..4e655f3aa2 100644 --- a/aeon/utils/tests/test_split.py +++ b/aeon/utils/tests/test_split.py @@ -3,7 +3,7 @@ import numpy as np import pytest -from aeon.utils import split_series +from aeon.utils.split import split_series X = np.arange(10) testdata = [ diff --git a/aeon/utils/tests/test_weighted_metrics.py b/aeon/utils/tests/test_weighted_metrics.py deleted file mode 100644 index c8a0b09135..0000000000 --- a/aeon/utils/tests/test_weighted_metrics.py +++ /dev/null @@ -1,25 +0,0 @@ -"""Test weighted metric.""" - -import numpy as np -import pytest - -from aeon.utils.weighted_metrics import weighted_geometric_mean - - -def test_weighted_geometric_mean(): - """Test weighted_geometric_mean.""" - y = np.array([1.0, 2.0, 3.0]) - w = np.array([0.1, 0.8, 0.1]) - w2 = np.array([[0.1, 0.8, 0.1]]).T - res = weighted_geometric_mean(y, w) - assert round(res, 5) == 1.94328 - res2 = weighted_geometric_mean(y, w, axis=0) - assert res == res2 - y2 = np.array([[1.0, 2.0, 3.0]]).T - with pytest.raises(ValueError, match="do not match"): - weighted_geometric_mean(y2, w, axis=1) - weighted_geometric_mean(y2, w2, axis=1) - with pytest.raises( - ValueError, match="Input data and weights have inconsistent shapes" - ): - weighted_geometric_mean(y, w2) diff --git a/aeon/utils/tests/test_weightnorm.py b/aeon/utils/tests/test_weightnorm.py index 43b20293d5..0642530b2c 100644 --- a/aeon/utils/tests/test_weightnorm.py +++ b/aeon/utils/tests/test_weightnorm.py @@ -16,11 +16,11 @@ def test_weight_norm(): import numpy as np import tensorflow as tf - from aeon.utils.networks.weight_norm import WeightNormalization + from aeon.utils.networks.weight_norm import _WeightNormalization X = np.random.random((10, 10, 5)) _input = tf.keras.layers.Input((10, 5)) - l1 = WeightNormalization( + l1 = _WeightNormalization( tf.keras.layers.Conv1D(filters=5, kernel_size=1, dilation_rate=4) )(_input) model = tf.keras.models.Model(inputs=_input, outputs=l1) @@ -42,7 +42,7 @@ def test_weight_norm(): model_path = "test_weight_norm_model.h5" model.save(model_path) loaded_model = tf.keras.models.load_model( - model_path, custom_objects={"WeightNormalization": WeightNormalization} + model_path, custom_objects={"_WeightNormalization": _WeightNormalization} ) assert loaded_model is not None loaded_output = loaded_model.predict(X) diff --git a/aeon/utils/validation/__init__.py b/aeon/utils/validation/__init__.py index 14a16853ad..7e86a79a13 100644 --- a/aeon/utils/validation/__init__.py +++ b/aeon/utils/validation/__init__.py @@ -12,7 +12,6 @@ "check_window_length", "get_n_cases", "get_type", - "equal_length", "is_equal_length", "has_missing", "is_univariate", diff --git a/aeon/utils/validation/tests/test_collection.py b/aeon/utils/validation/tests/test_collection.py index b1c27e4a64..4c53572b32 100644 --- a/aeon/utils/validation/tests/test_collection.py +++ b/aeon/utils/validation/tests/test_collection.py @@ -13,7 +13,7 @@ make_example_3d_numpy_list, ) from aeon.testing.testing_data import EQUAL_LENGTH_UNIVARIATE_CLASSIFICATION -from aeon.utils import COLLECTIONS_DATA_TYPES +from aeon.utils.data_types import COLLECTIONS_DATA_TYPES from aeon.utils.validation.collection import ( _is_numpy_list_multivariate, _is_pd_wide, diff --git a/aeon/utils/weighted_metrics.py b/aeon/utils/weighted_metrics.py deleted file mode 100644 index 84ec005d2f..0000000000 --- a/aeon/utils/weighted_metrics.py +++ /dev/null @@ -1,44 +0,0 @@ -"""Statistical functionality used throughout aeon.""" - -import numpy as np -from sklearn.utils.validation import check_consistent_length - -__maintainer__ = [] -__all__ = [ - "weighted_geometric_mean", -] - - -def weighted_geometric_mean(y, weights, axis=None): - """Calculate weighted version of geometric mean. - - Parameters - ---------- - y : np.ndarray - Values to take the weighted geometric mean of. - weights: np.ndarray - Weights for each value in `array`. Must be same shape as `array` or - of shape `(array.shape[0],)` if axis=0 or `(array.shape[1], ) if axis=1. - axis : int - The axis of `y` to apply the weights to. - - Returns - ------- - geometric_mean : float - Weighted geometric mean - """ - if weights.ndim == 1: - if axis == 0: - check_consistent_length(y, weights) - elif axis == 1: - if y.shape[1] != len(weights): - raise ValueError( - f"Input features ({y.shape[1]}) do not match " - f"number of `weights` ({len(weights)})." - ) - weight_sums = np.sum(weights) - else: - if y.shape != weights.shape: - raise ValueError("Input data and weights have inconsistent shapes.") - weight_sums = np.sum(weights, axis=axis) - return np.exp(np.sum(weights * np.log(y), axis=axis) / weight_sums) diff --git a/docs/api_reference.md b/docs/api_reference.md index 34a580ba74..d0c6335ca7 100644 --- a/docs/api_reference.md +++ b/docs/api_reference.md @@ -19,6 +19,7 @@ api_reference/clustering api_reference/data_format api_reference/datasets api_reference/distances +api_reference/forecasting api_reference/networks api_reference/regression api_reference/segmentation diff --git a/docs/api_reference/forecasting.md b/docs/api_reference/forecasting.md new file mode 100644 index 0000000000..131fb8be86 --- /dev/null +++ b/docs/api_reference/forecasting.md @@ -0,0 +1,14 @@ +# Forecasting + +```{eval-rst} +.. currentmodule:: aeon.datasets + +.. autosummary:: + :toctree: auto_generated/ + :template: class.rst + + DummyForecaster + BaseForecaster + RegressionForecaster + ETSForecaster +``` diff --git a/docs/api_reference/utils.rst b/docs/api_reference/utils.rst index adaacdf0f2..40dea9f67c 100644 --- a/docs/api_reference/utils.rst +++ b/docs/api_reference/utils.rst @@ -5,18 +5,13 @@ Utility functions ``aeon`` has a number of modules dedicated to utilities: -* :mod:`aeon.pipeline`, which contains generics for pipeline construction. +* :mod:`aeon.pipeline`, which contains functions for pipeline construction. +* :mod:`aeon.testing`, which contains functions for estimator testing and data generation. * :mod:`aeon.utils`, which contains generic utility functions. -Pipeline construction ---------------------- - -:mod:`aeon.pipeline` - -.. automodule:: aeon.pipeline - :no-members: - :no-inherited-members: +Pipeline +-------- .. currentmodule:: aeon.pipeline @@ -26,3 +21,274 @@ Pipeline construction make_pipeline sklearn_to_aeon + +Testing +------- + +Data Generation +^^^^^^^^^^^^^^^ + +.. currentmodule:: aeon.testing.data_generation + +.. autosummary:: + :toctree: auto_generated/ + :template: function.rst + + make_example_3d_numpy + make_example_2d_numpy_collection + make_example_3d_numpy_list + make_example_2d_numpy_list + make_example_dataframe_list + make_example_2d_dataframe_collection + make_example_multi_index_dataframe + make_example_1d_numpy + make_example_2d_numpy_series + make_example_pandas_series + make_example_dataframe_series + +Estimator Checking +^^^^^^^^^^^^^^^^^^ + +.. currentmodule:: aeon.testing.estimator_checking + +.. autosummary:: + :toctree: auto_generated/ + :template: function.rst + + check_estimator + parametrize_with_checks + +Mock Estimators +^^^^^^^^^^^^^^^ + +.. currentmodule:: aeon.testing.mock_estimators + +.. autosummary:: + :toctree: auto_generated/ + :template: class.rst + + MockAnomalyDetector + MockAnomalyDetectorRequiresFit + MockAnomalyDetectorRequiresY + MockClassifier + MockClassifierPredictProba + MockClassifierFullTags + MockClassifierParams + MockClassifierComposite + MockCluster + MockDeepClusterer + MockCollectionTransformer + MockForecaster + MockRegressor + MockRegressorFullTags + MockSegmenter + MockSegmenterRequiresY + MockSeriesTransformer + MockUnivariateSeriesTransformer + MockMultivariateSeriesTransformer + MockSeriesTransformerNoFit + MockSimilaritySearch + +Utilities +^^^^^^^^^ + +.. currentmodule:: aeon.testing.utils.deep_equals + +.. autosummary:: + :toctree: auto_generated/ + :template: function.rst + + deep_equals + +.. currentmodule:: aeon.testing.utils.output_suppression + +.. autosummary:: + :toctree: auto_generated/ + :template: function.rst + + suppress_output + +Utils +----- + +Estimator Discovery & Tags +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. currentmodule:: aeon.utils.base + +.. autosummary:: + :toctree: auto_generated/ + :template: function.rst + + get_identifier + +.. currentmodule:: aeon.utils.discovery + +.. autosummary:: + :toctree: auto_generated/ + :template: function.rst + + all_estimators + +.. currentmodule:: aeon.utils.tags + +.. autosummary:: + :toctree: auto_generated/ + :template: function.rst + + check_valid_tags + all_tags_for_estimator + + +Data Conversion & Validation +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. currentmodule:: aeon.utils.conversion + +.. autosummary:: + :toctree: auto_generated/ + :template: function.rst + + resolve_equal_length_inner_type + resolve_unequal_length_inner_type + convert_collection + convert_series + +.. currentmodule:: aeon.utils.validation + +.. autosummary:: + :toctree: auto_generated/ + :template: function.rst + + is_int + is_float + is_timedelta + is_date_offset + is_timedelta_or_date_offset + check_n_jobs + check_window_length + get_n_cases + get_type + is_equal_length + has_missing + is_univariate + is_univariate_series + is_single_series + is_collection + is_tabular + is_hierarchical + +Numba +^^^^^ + +.. currentmodule:: aeon.utils.numba.general + +.. autosummary:: + :toctree: auto_generated/ + :template: function.rst + + unique_count + first_order_differences + first_order_differences_2d + first_order_differences_3d + z_normalise_series_with_mean + z_normalise_series + z_normalise_series_2d + z_normalise_series_3d + set_numba_random_seed + choice_log + get_subsequence + get_subsequence_with_mean_std + sliding_mean_std_one_series + combinations_1d + slope_derivative + slope_derivative_2d + slope_derivative_3d + generate_combinations + +.. currentmodule:: aeon.utils.numba.stats + +.. autosummary:: + :toctree: auto_generated/ + :template: function.rst + + mean + row_mean + count_mean_crossing + row_count_mean_crossing + count_above_mean + row_count_above_mean + quantile + row_quantile + median + row_median + quantile25 + row_quantile25 + quantile75 + row_quantile75 + std + std2 + row_std + numba_min + row_numba_min + numba_max + row_numba_max + slope + row_slope + iqr + row_iqr + ppv + row_ppv + fisher_score + prime_up_to + is_prime + +.. currentmodule:: aeon.utils.numba.wavelets + +.. autosummary:: + :toctree: auto_generated/ + :template: function.rst + + haar_transform + multilevel_haar_transform + +Other +^^^^^ + +.. currentmodule:: aeon.utils + +.. autosummary:: + :toctree: auto_generated/ + :template: function.rst + + show_versions + +.. currentmodule:: aeon.utils.sklearn + +.. autosummary:: + :toctree: auto_generated/ + :template: function.rst + + is_sklearn_estimator + sklearn_estimator_identifier + is_sklearn_transformer + is_sklearn_classifier + is_sklearn_regressor + is_sklearn_clusterer + +.. currentmodule:: aeon.utils.split + +.. autosummary:: + :toctree: auto_generated/ + :template: function.rst + + split_series + +.. currentmodule:: aeon.utils.windowing + +.. autosummary:: + :toctree: auto_generated/ + :template: function.rst + + sliding_windows + reverse_windowing diff --git a/docs/developer_guide/deprecation.md b/docs/developer_guide/deprecation.md index a4b294b86a..4b10d81cb2 100644 --- a/docs/developer_guide/deprecation.md +++ b/docs/developer_guide/deprecation.md @@ -20,7 +20,6 @@ Note that the deprecation policy does not necessarily apply to modules we class experimental. Currently experimental modules are: - `anomaly_detection` -- `benchmarking` - `forecasting` - `segmentation` - `similarity_search` diff --git a/docs/getting_started.md b/docs/getting_started.md index 3a4ef8dbc0..36f18583cb 100644 --- a/docs/getting_started.md +++ b/docs/getting_started.md @@ -26,6 +26,9 @@ classical techniques for the following learning tasks: ([more details](examples/similarity_search/similarity_search.ipynb)). - [**Anomaly detection**](api_reference/anomaly_detection), where the goal is to find values or areas of a single time series that are not representative of the whole series. +- [**Forecasting**](api_reference/forecasting), where the goal is to predict future values + of a single time series + ([more details](examples/forecasting/forecasting.ipynb)). - [**Segmentation**](api_reference/segmentation), where the goal is to split a single time series into regions where the series are sofind areas of a time series that are not representative of the whole series @@ -37,8 +40,8 @@ classical techniques for the following learning tasks: transformed into a different representation or domain. ([more details](examples/transformations/transformations.ipynb)). - [**Distances**](api_reference/distances), which measure the dissimilarity between two time series or collections of series and include functions to align series ([more details](examples/distances/distances.ipynb)). -- [**Networks**](api_reference/networks), provides core models for deep learning for all time series tasks ([more - details](examples/networks/deep_learning.ipynb)). +- [**Networks**](api_reference/networks), provides core models for deep learning for all time series tasks +- ([more details](examples/networks/deep_learning.ipynb)). There are dedicated notebooks going into more detail for each of these modules. This guide is meant to give you the briefest of introductions to the main concepts and @@ -99,9 +102,9 @@ structures, see our [datasets](examples/datasets/datasets.ipynb) notebooks. ## Single Series Modules Different `aeon` modules work with individual series or collections of series. -Estimators in the `anomaly detection` and `segmentation` modules use single -series input (they inherit from `BaseSeriesEstimator`). The functions in `distances` -take two series as arguments. +Estimators in the `anomaly detection`, `forecasting` and `segmentation` modules use +single series input (they inherit from `BaseSeriesEstimator`). The functions in +`distances` take two series as arguments. ### Anomaly Detection diff --git a/docs/index.md b/docs/index.md index a1b8f0cba7..83fc6bb049 100644 --- a/docs/index.md +++ b/docs/index.md @@ -110,6 +110,25 @@ Anomaly Detection ::: +:::{grid-item-card} +:img-top: examples/forecasting/img/forecasting.png +:class-img-top: aeon-card-image +:text-align: center + +Get started with forecasting + ++++ + +```{button-ref} /examples/forecasting/forecasting.ipynb +:color: primary +:click-parent: +:expand: + +Forecasting +``` + +::: + :::{grid-item-card} :img-top: examples/segmentation/img/segmentation.png :class-img-top: aeon-card-image @@ -253,6 +272,7 @@ is relaxed, so it is suggested that you integrate these modules with care. The c experimental modules are: - `anomaly_detection` +- `forecasting` - `segmentation` - `similarity_search` - `visualisation` diff --git a/examples/forecasting/forecasting.ipynb b/examples/forecasting/forecasting.ipynb index e17b6667dc..0e0b4ac72f 100644 --- a/examples/forecasting/forecasting.ipynb +++ b/examples/forecasting/forecasting.ipynb @@ -109,7 +109,7 @@ { "cell_type": "code", "source": [ - "from aeon.utils import SERIES_DATA_TYPES\n", + "from aeon.utils.data_types import SERIES_DATA_TYPES\n", "\n", "print(\" Possible data structures for input to forecaster \", SERIES_DATA_TYPES)\n", "print(\"\\n Tags for BaseForecaster: \", BaseForecaster.get_class_tags())" diff --git a/examples/forecasting/img/forecasting.png b/examples/forecasting/img/forecasting.png new file mode 100644 index 0000000000..c9316dbe5a Binary files /dev/null and b/examples/forecasting/img/forecasting.png differ