chap-core 0.0.8__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- chap_core-0.0.8/HISTORY.rst +8 -0
- chap_core-0.0.8/LICENSE +22 -0
- chap_core-0.0.8/MANIFEST.in +10 -0
- chap_core-0.0.8/PKG-INFO +55 -0
- chap_core-0.0.8/README.md +67 -0
- chap_core-0.0.8/chap_core/__init__.py +8 -0
- chap_core-0.0.8/chap_core/_legacy/__init__.py +0 -0
- chap_core-0.0.8/chap_core/_legacy/file_io.py +50 -0
- chap_core-0.0.8/chap_core/_legacy_dataset.py +101 -0
- chap_core-0.0.8/chap_core/adaptors/__init__.py +0 -0
- chap_core-0.0.8/chap_core/adaptors/gluonts.py +50 -0
- chap_core-0.0.8/chap_core/alarms.py +18 -0
- chap_core-0.0.8/chap_core/api.py +264 -0
- chap_core-0.0.8/chap_core/api_types.py +55 -0
- chap_core-0.0.8/chap_core/assessment/__init__.py +0 -0
- chap_core-0.0.8/chap_core/assessment/dataset_splitting.py +141 -0
- chap_core-0.0.8/chap_core/assessment/forecast.py +83 -0
- chap_core-0.0.8/chap_core/assessment/multi_location_evaluator.py +124 -0
- chap_core-0.0.8/chap_core/assessment/prediction_evaluator.py +353 -0
- chap_core-0.0.8/chap_core/chap_cli.py +133 -0
- chap_core-0.0.8/chap_core/cli.py +277 -0
- chap_core-0.0.8/chap_core/climate_data/__init__.py +14 -0
- chap_core-0.0.8/chap_core/climate_data/external.py +4 -0
- chap_core-0.0.8/chap_core/climate_data/gee_legacy.py +97 -0
- chap_core-0.0.8/chap_core/climate_data/gridded_data.py +45 -0
- chap_core-0.0.8/chap_core/climate_data/meteostat_wrapper.py +242 -0
- chap_core-0.0.8/chap_core/climate_data/seasonal_forecasts.py +42 -0
- chap_core-0.0.8/chap_core/climate_health.py +1 -0
- chap_core-0.0.8/chap_core/climate_predictor.py +84 -0
- chap_core-0.0.8/chap_core/data/__init__.py +4 -0
- chap_core-0.0.8/chap_core/data/adaptors.py +3 -0
- chap_core-0.0.8/chap_core/data/datasets.py +7 -0
- chap_core-0.0.8/chap_core/data/gluonts_adaptor/__init__.py +0 -0
- chap_core-0.0.8/chap_core/data/gluonts_adaptor/dataset.py +147 -0
- chap_core-0.0.8/chap_core/data/gluonts_adaptor/model.py +15 -0
- chap_core-0.0.8/chap_core/data_wrangling/__init__.py +0 -0
- chap_core-0.0.8/chap_core/data_wrangling/flows.py +132 -0
- chap_core-0.0.8/chap_core/data_wrangling/tasks.py +35 -0
- chap_core-0.0.8/chap_core/database/__init__.py +0 -0
- chap_core-0.0.8/chap_core/database/database.py +42 -0
- chap_core-0.0.8/chap_core/database/local_db_cache.py +49 -0
- chap_core-0.0.8/chap_core/dataset_protocols.py +73 -0
- chap_core-0.0.8/chap_core/datatypes.py +386 -0
- chap_core-0.0.8/chap_core/dhis2_interface/ChapProgram.py +126 -0
- chap_core-0.0.8/chap_core/dhis2_interface/__init__.py +0 -0
- chap_core-0.0.8/chap_core/dhis2_interface/json_parsing.py +120 -0
- chap_core-0.0.8/chap_core/dhis2_interface/periods.py +14 -0
- chap_core-0.0.8/chap_core/dhis2_interface/pydantic_to_spatiotemporal.py +23 -0
- chap_core-0.0.8/chap_core/dhis2_interface/src/Config.py +15 -0
- chap_core-0.0.8/chap_core/dhis2_interface/src/HttpRequest.py +11 -0
- chap_core-0.0.8/chap_core/dhis2_interface/src/PullAnalytics.py +36 -0
- chap_core-0.0.8/chap_core/dhis2_interface/src/PullClimateData.py +2 -0
- chap_core-0.0.8/chap_core/dhis2_interface/src/PushResult.py +49 -0
- chap_core-0.0.8/chap_core/dhis2_interface/src/__init__.py +0 -0
- chap_core-0.0.8/chap_core/dhis2_interface/src/create_data_element_if_not_exists.py +79 -0
- chap_core-0.0.8/chap_core/dhis2_interface/src/dhis_json_parser.py +0 -0
- chap_core-0.0.8/chap_core/docker_helper_functions.py +57 -0
- chap_core-0.0.8/chap_core/external/__init__.py +0 -0
- chap_core-0.0.8/chap_core/external/external_model.py +497 -0
- chap_core-0.0.8/chap_core/external/mlflow.py +259 -0
- chap_core-0.0.8/chap_core/external/python_model.py +40 -0
- chap_core-0.0.8/chap_core/external/r_description.py +32 -0
- chap_core-0.0.8/chap_core/external/r_model.py +60 -0
- chap_core-0.0.8/chap_core/external/r_models.py +16 -0
- chap_core-0.0.8/chap_core/external/spes.py +2 -0
- chap_core-0.0.8/chap_core/fetch/__init__.py +4 -0
- chap_core-0.0.8/chap_core/file_io/__init__.py +1 -0
- chap_core-0.0.8/chap_core/file_io/cleaners.py +62 -0
- chap_core-0.0.8/chap_core/file_io/example_data_set.py +59 -0
- chap_core-0.0.8/chap_core/file_io/external_file.py +17 -0
- chap_core-0.0.8/chap_core/file_io/file_paths.py +13 -0
- chap_core-0.0.8/chap_core/file_io/load.py +6 -0
- chap_core-0.0.8/chap_core/geo_coding/__init__.py +0 -0
- chap_core-0.0.8/chap_core/geo_coding/location_lookup.py +111 -0
- chap_core-0.0.8/chap_core/geojson.py +59 -0
- chap_core-0.0.8/chap_core/geometry.py +148 -0
- chap_core-0.0.8/chap_core/google_earth_engine/__init__.py +0 -0
- chap_core-0.0.8/chap_core/google_earth_engine/_refactor_gee_era5.py +140 -0
- chap_core-0.0.8/chap_core/google_earth_engine/gee_era5.py +246 -0
- chap_core-0.0.8/chap_core/google_earth_engine/gee_raw.py +131 -0
- chap_core-0.0.8/chap_core/internal_state.py +49 -0
- chap_core-0.0.8/chap_core/main.py +85 -0
- chap_core-0.0.8/chap_core/model_spec.py +97 -0
- chap_core-0.0.8/chap_core/omnipy_lib.py +29 -0
- chap_core-0.0.8/chap_core/pandas_adaptors.py +12 -0
- chap_core-0.0.8/chap_core/plotting/__init__.py +1 -0
- chap_core-0.0.8/chap_core/plotting/plotting.py +70 -0
- chap_core-0.0.8/chap_core/plotting/prediction_plot.py +179 -0
- chap_core-0.0.8/chap_core/predictor/__init__.py +29 -0
- chap_core-0.0.8/chap_core/predictor/feature_spec.py +30 -0
- chap_core-0.0.8/chap_core/predictor/naive_estimator.py +50 -0
- chap_core-0.0.8/chap_core/predictor/naive_predictor.py +131 -0
- chap_core-0.0.8/chap_core/predictor/poisson.py +24 -0
- chap_core-0.0.8/chap_core/predictor/protocol.py +50 -0
- chap_core-0.0.8/chap_core/reports/__init__.py +106 -0
- chap_core-0.0.8/chap_core/rest_api.py +169 -0
- chap_core-0.0.8/chap_core/rest_api_src/__init__.py +0 -0
- chap_core-0.0.8/chap_core/rest_api_src/_legacy.py +57 -0
- chap_core-0.0.8/chap_core/rest_api_src/data_models.py +27 -0
- chap_core-0.0.8/chap_core/rest_api_src/generate_rest_api.py +57 -0
- chap_core-0.0.8/chap_core/rest_api_src/worker_functions.py +139 -0
- chap_core-0.0.8/chap_core/runners/__init__.py +0 -0
- chap_core-0.0.8/chap_core/runners/command_line_runner.py +44 -0
- chap_core-0.0.8/chap_core/runners/conda_runner.py +17 -0
- chap_core-0.0.8/chap_core/runners/docker_runner.py +48 -0
- chap_core-0.0.8/chap_core/runners/runner.py +20 -0
- chap_core-0.0.8/chap_core/services/__init__.py +0 -0
- chap_core-0.0.8/chap_core/services/cache_manager.py +18 -0
- chap_core-0.0.8/chap_core/simulation/__init__.py +0 -0
- chap_core-0.0.8/chap_core/simulation/random_noise_simulator.py +22 -0
- chap_core-0.0.8/chap_core/simulation/seasonal_simulator.py +76 -0
- chap_core-0.0.8/chap_core/simulation/simulator.py +23 -0
- chap_core-0.0.8/chap_core/spatio_temporal_data/__init__.py +0 -0
- chap_core-0.0.8/chap_core/spatio_temporal_data/multi_country_dataset.py +88 -0
- chap_core-0.0.8/chap_core/spatio_temporal_data/omnipy_spatio_temporal_dataset.py +82 -0
- chap_core-0.0.8/chap_core/spatio_temporal_data/temporal_dataclass.py +400 -0
- chap_core-0.0.8/chap_core/testing/__init__.py +0 -0
- chap_core-0.0.8/chap_core/testing/estimators.py +18 -0
- chap_core-0.0.8/chap_core/testing/external_model.py +14 -0
- chap_core-0.0.8/chap_core/time_period/__init__.py +15 -0
- chap_core-0.0.8/chap_core/time_period/_legacy_implementation.py +90 -0
- chap_core-0.0.8/chap_core/time_period/dataclasses.py +78 -0
- chap_core-0.0.8/chap_core/time_period/date_util_wrapper.py +706 -0
- chap_core-0.0.8/chap_core/time_period/delta.py +10 -0
- chap_core-0.0.8/chap_core/time_period/multi_resolution.py +15 -0
- chap_core-0.0.8/chap_core/time_period/pandas_wrappers.py +9 -0
- chap_core-0.0.8/chap_core/time_period/period_range.py +65 -0
- chap_core-0.0.8/chap_core/time_period/protocols.py +42 -0
- chap_core-0.0.8/chap_core/time_period/relationships.py +12 -0
- chap_core-0.0.8/chap_core/training_control.py +48 -0
- chap_core-0.0.8/chap_core/transformations/__init__.py +0 -0
- chap_core-0.0.8/chap_core/transformations/covid_mask.py +26 -0
- chap_core-0.0.8/chap_core/util.py +39 -0
- chap_core-0.0.8/chap_core/worker/__init__.py +0 -0
- chap_core-0.0.8/chap_core/worker/background_tasks_worker.py +73 -0
- chap_core-0.0.8/chap_core/worker/interface.py +25 -0
- chap_core-0.0.8/chap_core/worker/rq_worker.py +76 -0
- chap_core-0.0.8/chap_core.egg-info/PKG-INFO +55 -0
- chap_core-0.0.8/chap_core.egg-info/SOURCES.txt +232 -0
- chap_core-0.0.8/chap_core.egg-info/dependency_links.txt +1 -0
- chap_core-0.0.8/chap_core.egg-info/entry_points.txt +3 -0
- chap_core-0.0.8/chap_core.egg-info/not-zip-safe +1 -0
- chap_core-0.0.8/chap_core.egg-info/requires.txt +36 -0
- chap_core-0.0.8/chap_core.egg-info/top_level.txt +1 -0
- chap_core-0.0.8/docs/diagrams/uml_use_case_exercise.png +0 -0
- chap_core-0.0.8/setup.cfg +22 -0
- chap_core-0.0.8/setup.py +85 -0
- chap_core-0.0.8/tests/__init__.py +7 -0
- chap_core-0.0.8/tests/api/test_json.py +18 -0
- chap_core-0.0.8/tests/categorical.py +22 -0
- chap_core-0.0.8/tests/climate_data/__init__.py +1 -0
- chap_core-0.0.8/tests/climate_data/dhis2/__init__.py +0 -0
- chap_core-0.0.8/tests/climate_data/dhis2/test_json_parsing.py +97 -0
- chap_core-0.0.8/tests/climate_data/fixtures/test_chapdata-bombali-jan2022-dec2022.zip +0 -0
- chap_core-0.0.8/tests/climate_data/test_gee_database.py +35 -0
- chap_core-0.0.8/tests/climate_data/test_gee_era5.py +356 -0
- chap_core-0.0.8/tests/climate_data/test_mocking.py +12 -0
- chap_core-0.0.8/tests/conftest.py +88 -0
- chap_core-0.0.8/tests/data_fixtures.py +90 -0
- chap_core-0.0.8/tests/data_wrangling/__init__.py +0 -0
- chap_core-0.0.8/tests/data_wrangling/test_standardize_data.py +143 -0
- chap_core-0.0.8/tests/data_wrangling/test_standardize_laos_data.py +110 -0
- chap_core-0.0.8/tests/external/__init__.py +0 -0
- chap_core-0.0.8/tests/external/command_line_model_predict.sh +1 -0
- chap_core-0.0.8/tests/external/command_line_model_train.sh +0 -0
- chap_core-0.0.8/tests/external/conftest.py +34 -0
- chap_core-0.0.8/tests/external/external_model_env.yml +6 -0
- chap_core-0.0.8/tests/external/test_docker.py +30 -0
- chap_core-0.0.8/tests/external/test_external_models.py +89 -0
- chap_core-0.0.8/tests/external/util.py +32 -0
- chap_core-0.0.8/tests/integration/rest_api/__init__.py +0 -0
- chap_core-0.0.8/tests/integration/rest_api/test_integration.py +106 -0
- chap_core-0.0.8/tests/integration/rest_api/testdata/traning_prediction_data.zip +0 -0
- chap_core-0.0.8/tests/mock_predictor_script.py +52 -0
- chap_core-0.0.8/tests/mock_predictor_script_future_climate.csv +240 -0
- chap_core-0.0.8/tests/mock_predictor_script_train.csv +240 -0
- chap_core-0.0.8/tests/mocks.py +25 -0
- chap_core-0.0.8/tests/plotting/__init__.py +0 -0
- chap_core-0.0.8/tests/plotting/test_plotting.py +94 -0
- chap_core-0.0.8/tests/predictor/__init__.py +0 -0
- chap_core-0.0.8/tests/predictor/test_multi_region_predictor.py +18 -0
- chap_core-0.0.8/tests/predictor/test_predictor.py +22 -0
- chap_core-0.0.8/tests/property_tests/test.py +2 -0
- chap_core-0.0.8/tests/runners/docker_example_image/Dockerfile +5 -0
- chap_core-0.0.8/tests/runners/test_runners.py +28 -0
- chap_core-0.0.8/tests/services/test_cache_manager.py +13 -0
- chap_core-0.0.8/tests/simulation/some_tests.py +0 -0
- chap_core-0.0.8/tests/simulation/test_random_noise_simulator.py +9 -0
- chap_core-0.0.8/tests/simulation/test_seasonal_simulator.py +13 -0
- chap_core-0.0.8/tests/simulation/test_simulation_integration.py +13 -0
- chap_core-0.0.8/tests/single_assessment/__init__.py +0 -0
- chap_core-0.0.8/tests/single_assessment/test.py +47 -0
- chap_core-0.0.8/tests/single_assessment/test_multi_location_evaluator.py +58 -0
- chap_core-0.0.8/tests/spatio_temporal_data/__init__.py +0 -0
- chap_core-0.0.8/tests/spatio_temporal_data/test_omnipy_spatio_temporal_dataset.py +146 -0
- chap_core-0.0.8/tests/test_api.py +52 -0
- chap_core-0.0.8/tests/test_background_tasks.py +41 -0
- chap_core-0.0.8/tests/test_chap_cli.py +43 -0
- chap_core-0.0.8/tests/test_cli.py +14 -0
- chap_core-0.0.8/tests/test_climate_health.py +21 -0
- chap_core-0.0.8/tests/test_climate_predictor.py +52 -0
- chap_core-0.0.8/tests/test_dataset.py +6 -0
- chap_core-0.0.8/tests/test_dataset_splitting.py +48 -0
- chap_core-0.0.8/tests/test_datatypes.py +75 -0
- chap_core-0.0.8/tests/test_dhis2_interface.py +55 -0
- chap_core-0.0.8/tests/test_external_file.py +18 -0
- chap_core-0.0.8/tests/test_external_model_evaluation_acceptance.py +116 -0
- chap_core-0.0.8/tests/test_forecast.py +53 -0
- chap_core-0.0.8/tests/test_geojson.py +28 -0
- chap_core-0.0.8/tests/test_geometry.py +7 -0
- chap_core-0.0.8/tests/test_gluonts_adaptor.py +87 -0
- chap_core-0.0.8/tests/test_gridded_data.py +23 -0
- chap_core-0.0.8/tests/test_integration.py +10 -0
- chap_core-0.0.8/tests/test_json_parsing.py +34 -0
- chap_core-0.0.8/tests/test_location_lookup.py +110 -0
- chap_core-0.0.8/tests/test_meteostat_wrapper.py +219 -0
- chap_core-0.0.8/tests/test_metrics.py +1 -0
- chap_core-0.0.8/tests/test_mock_predictor_script.py +14 -0
- chap_core-0.0.8/tests/test_model_building_acceptance.py +21 -0
- chap_core-0.0.8/tests/test_model_spec.py +28 -0
- chap_core-0.0.8/tests/test_multi_country_dataset.py +9 -0
- chap_core-0.0.8/tests/test_naive_estimator.py +7 -0
- chap_core-0.0.8/tests/test_r_description.py +8 -0
- chap_core-0.0.8/tests/test_report.py +56 -0
- chap_core-0.0.8/tests/test_seasonal_forecast.py +25 -0
- chap_core-0.0.8/tests/test_spatio_temporal_dict.py +70 -0
- chap_core-0.0.8/tests/test_temporal_dataclass.py +27 -0
- chap_core-0.0.8/tests/time_period/__init__.py +1 -0
- chap_core-0.0.8/tests/time_period/test_bnpdataclass.py +34 -0
- chap_core-0.0.8/tests/time_period/test_data_objects.py +37 -0
- chap_core-0.0.8/tests/time_period/test_dateutil_wrapper.py +242 -0
- chap_core-0.0.8/tests/time_period/test_multi_resolution.py +48 -0
- chap_core-0.0.8/tests/time_period/test_period_range.py +35 -0
chap_core-0.0.8/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024, Sandvelab
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
chap_core-0.0.8/PKG-INFO
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: chap_core
|
|
3
|
+
Version: 0.0.8
|
|
4
|
+
Summary: Main repository for joint programming project on climate health
|
|
5
|
+
Home-page: https://github.com/dhis2/chap-core
|
|
6
|
+
Author: Sandvelab
|
|
7
|
+
Author-email: knutdrand@gmail.com
|
|
8
|
+
License: MIT license
|
|
9
|
+
Keywords: chap_core
|
|
10
|
+
Classifier: Development Status :: 2 - Pre-Alpha
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
+
Classifier: Natural Language :: English
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Requires-Python: >=3.9
|
|
17
|
+
License-File: LICENSE
|
|
18
|
+
Requires-Dist: virtualenv
|
|
19
|
+
Requires-Dist: numpy<2.0
|
|
20
|
+
Requires-Dist: bionumpy
|
|
21
|
+
Requires-Dist: pandas
|
|
22
|
+
Requires-Dist: plotly
|
|
23
|
+
Requires-Dist: scikit-learn
|
|
24
|
+
Requires-Dist: matplotlib
|
|
25
|
+
Requires-Dist: diskcache
|
|
26
|
+
Requires-Dist: geopy
|
|
27
|
+
Requires-Dist: pooch
|
|
28
|
+
Requires-Dist: python-dateutil
|
|
29
|
+
Requires-Dist: meteostat
|
|
30
|
+
Requires-Dist: cyclopts
|
|
31
|
+
Requires-Dist: requests
|
|
32
|
+
Requires-Dist: fastapi
|
|
33
|
+
Requires-Dist: pydantic>=2.0
|
|
34
|
+
Requires-Dist: pyyaml
|
|
35
|
+
Requires-Dist: geopandas
|
|
36
|
+
Requires-Dist: libpysal
|
|
37
|
+
Requires-Dist: docker
|
|
38
|
+
Requires-Dist: scipy
|
|
39
|
+
Requires-Dist: gitpython
|
|
40
|
+
Requires-Dist: earthengine-api
|
|
41
|
+
Requires-Dist: python-dotenv
|
|
42
|
+
Requires-Dist: rq
|
|
43
|
+
Requires-Dist: python-multipart
|
|
44
|
+
Requires-Dist: uvicorn
|
|
45
|
+
Requires-Dist: pydantic-geojson
|
|
46
|
+
Requires-Dist: annotated_types
|
|
47
|
+
Requires-Dist: pycountry
|
|
48
|
+
Requires-Dist: unidecode
|
|
49
|
+
Requires-Dist: httpx
|
|
50
|
+
Requires-Dist: earthengine-api
|
|
51
|
+
Requires-Dist: mlflow
|
|
52
|
+
Requires-Dist: gluonts
|
|
53
|
+
Requires-Dist: xarray
|
|
54
|
+
|
|
55
|
+
Chap Core
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# Climate Health Analysis Platform (CHAP)
|
|
2
|
+
CHAP offers a platform for analysing the relationship between climate and health. The platform is designed to be modular and flexible, allowing for easy integration of new models and data sources. The platform is designed to be used by researchers and public health professionals to forecast and assess the impact of climate on health outcomes.
|
|
3
|
+
|
|
4
|
+
# Installation
|
|
5
|
+
|
|
6
|
+
Basic installation can be done using pip:
|
|
7
|
+
|
|
8
|
+
$ pip install git+https://github.com/dhis2/chap-core.git
|
|
9
|
+
|
|
10
|
+
If running models, you may also need to install:
|
|
11
|
+
|
|
12
|
+
- Docker, if running a model that runs through docker
|
|
13
|
+
- [pyenv](https://github.com/pyenv/pyenv?tab=readme-ov-file#installation), if running a model that uses Python virtual environments
|
|
14
|
+
|
|
15
|
+
# Documentation
|
|
16
|
+
|
|
17
|
+
The main documentation is located at [https://dhis2.github.io/chap-core/](https://dhis2.github.io/chap-core/).
|
|
18
|
+
|
|
19
|
+
# Usage
|
|
20
|
+
|
|
21
|
+
The following shows basic usage of the platform. Follow the link to the documentation above for more details.
|
|
22
|
+
|
|
23
|
+
## Evaluate a public model on public data
|
|
24
|
+
CHAP supports evaluating models that are defined using the MLflow specification for machine learning models (link coming). Such models can e.g. exist in Github repositories. CHAP also has some built-in example data that can be used to evaluate models. The following example shows how to evaluate an Ewars model located on Github ([https://github.com/sandvelab/chap_auto_ewars](https://github.com/sandvelab/chap_auto_ewars)) using the ISMIP dataset:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
chap evaluate --model-name https://github.com/sandvelab/chap_auto_ewars --dataset-name ISIMIP_dengue_harmonized --dataset-country brazil
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
The above example requires that you have installed chap with pip and also that you have Docker available.
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
## Fetching Polygon Data
|
|
34
|
+
Fetch polygons for regions of interest in a country (on admin1 level). The following example fetches polygons for two regions in Norway
|
|
35
|
+
|
|
36
|
+
```python
|
|
37
|
+
import chap_core.fetch
|
|
38
|
+
|
|
39
|
+
polygons = chap_core.fetch.get_area_polygons('Norway', ['Oslo', 'Akershus'])
|
|
40
|
+
assert [feature.id for feature in polygons.features] == ['Oslo', 'Akershus']
|
|
41
|
+
```
|
|
42
|
+
Region names that are not recognized are skipped:
|
|
43
|
+
|
|
44
|
+
```python
|
|
45
|
+
polygons = climate_health.fetch.get_area_polygons('Norway', ['Oslo', 'Akershus', 'Unknown'])
|
|
46
|
+
assert [feature.id for feature in polygons.features] == ['Oslo', 'Akershus']
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Fetching climate data
|
|
50
|
+
Fetching climate data through Google Earth Engine. The following example fetches temperature data from the ERA5 dataset for the regions of interest. You need to have an an account at gee, and pass the credentials to the method to make this work: https://developers.google.com/earth-engine/guides/auth
|
|
51
|
+
|
|
52
|
+
```python
|
|
53
|
+
|
|
54
|
+
import chap_core.fetch
|
|
55
|
+
|
|
56
|
+
credentials = dict(account='demoaccount@demo.gserviceaccount.com', private_key='private_key')
|
|
57
|
+
polygons = open("polygon_file.geojson").read()
|
|
58
|
+
start_period = '202001' # January 2020
|
|
59
|
+
end_period = '202011' # December 2020
|
|
60
|
+
band_names = ['temperature_2m', 'total_precipitation_sum']
|
|
61
|
+
data = chap_core.fetch.gee_era5(credentials, polygons, start_period, end_period, band_names)
|
|
62
|
+
print(data)
|
|
63
|
+
start_week = '2020W03' # Week 3 of 2020
|
|
64
|
+
end_week = '2020W05' # Week 5 of 2020
|
|
65
|
+
data = chap_core.fetch.gee_era5(credentials, polygons, start_week, end_week, band_names)
|
|
66
|
+
print(data)
|
|
67
|
+
```
|
|
File without changes
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
from typing import List
|
|
2
|
+
|
|
3
|
+
import chap_core.time_period.dataclasses as dc
|
|
4
|
+
from chap_core.time_period import TimePeriod, Month, Day, Year
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def parse_period_string(time_string: str) -> TimePeriod:
|
|
8
|
+
period = TimePeriod.parse(time_string)
|
|
9
|
+
return period
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def write_time_series_data(data):
|
|
13
|
+
def topandas(self):
|
|
14
|
+
data = pd.DataFrame(
|
|
15
|
+
{
|
|
16
|
+
"time_period": self.time_period.topandas(),
|
|
17
|
+
"rainfall": self.rainfall,
|
|
18
|
+
"mean_temperature": self.mean_temperature,
|
|
19
|
+
"disease_cases": self.disease_cases,
|
|
20
|
+
}
|
|
21
|
+
)
|
|
22
|
+
return data
|
|
23
|
+
|
|
24
|
+
to_pandas = topandas
|
|
25
|
+
|
|
26
|
+
def to_csv(self, csv_file: str, **kwargs):
|
|
27
|
+
"""Write data to a csv file."""
|
|
28
|
+
data = self.to_pandas()
|
|
29
|
+
data.to_csv(csv_file, index=False, **kwargs)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def parse_periods_strings(time_strings: List[str]) -> dc.Period:
|
|
33
|
+
periods = [parse_period_string(time_string) for time_string in time_strings]
|
|
34
|
+
if not periods:
|
|
35
|
+
return dc.Period.empty()
|
|
36
|
+
t = type(periods[0])
|
|
37
|
+
assert all(type(period) == t for period in periods), periods
|
|
38
|
+
|
|
39
|
+
if t == Year:
|
|
40
|
+
return dc.Year([period.year for period in periods])
|
|
41
|
+
if t == Month:
|
|
42
|
+
return dc.Month(
|
|
43
|
+
[period.year for period in periods], [period.month for period in periods]
|
|
44
|
+
)
|
|
45
|
+
elif t == Day:
|
|
46
|
+
return dc.Day(
|
|
47
|
+
[period.year for period in periods],
|
|
48
|
+
[period.month for period in periods],
|
|
49
|
+
[period.day for period in periods],
|
|
50
|
+
)
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
from typing import Protocol, TypeAlias, Union, Iterable, TypeVar, Tuple
|
|
2
|
+
|
|
3
|
+
import pandas as pd
|
|
4
|
+
from pydantic import BaseModel
|
|
5
|
+
|
|
6
|
+
from chap_core.datatypes import Location
|
|
7
|
+
from chap_core.time_period.dataclasses import Period
|
|
8
|
+
|
|
9
|
+
SpatialIndexType: TypeAlias = Union[str, Location]
|
|
10
|
+
TemporalIndexType: TypeAlias = Union[Period, Iterable[Period], slice]
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
FeaturesT = TypeVar("FeaturesT")
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class ClimateData(BaseModel):
|
|
17
|
+
temperature: float
|
|
18
|
+
rainfall: float
|
|
19
|
+
humidity: float
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class DataType(BaseModel):
|
|
23
|
+
disease_cases: int
|
|
24
|
+
climate_data: ClimateData
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class IsTemporalDataSet(Protocol[FeaturesT]):
|
|
28
|
+
def restrict_time_period(
|
|
29
|
+
self, start_period: Period = None, end_period: Period = None
|
|
30
|
+
) -> "IsTemporalDataSet[FeaturesT]": ...
|
|
31
|
+
|
|
32
|
+
def to_tidy_dataframe(self) -> pd.DataFrame: ...
|
|
33
|
+
|
|
34
|
+
@classmethod
|
|
35
|
+
def from_tidy_dataframe(cls, df: pd.DataFrame) -> "IsSpatialDataSet[FeaturesT]": ...
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class TemporalArray:
|
|
39
|
+
def __init__(self, time_index, data):
|
|
40
|
+
self._time_index = time_index
|
|
41
|
+
self._data = data
|
|
42
|
+
|
|
43
|
+
def __array_ufunc__(self, ufunc, method, *inputs, **kwargs):
|
|
44
|
+
return ufunc
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class IsSpatialDataSet(Protocol[FeaturesT]):
|
|
48
|
+
def get_locations(
|
|
49
|
+
self, location: Iterable[SpatialIndexType]
|
|
50
|
+
) -> "IsSpatialDataSet[FeaturesT]": ...
|
|
51
|
+
|
|
52
|
+
def get_location(self, location: SpatialIndexType) -> FeaturesT: ...
|
|
53
|
+
|
|
54
|
+
def locations(self) -> Iterable[SpatialIndexType]: ...
|
|
55
|
+
|
|
56
|
+
def data(self) -> Iterable[FeaturesT]: ...
|
|
57
|
+
|
|
58
|
+
def location_items(self) -> Iterable[Tuple[SpatialIndexType, FeaturesT]]: ...
|
|
59
|
+
|
|
60
|
+
def to_tidy_dataframe(self) -> pd.DataFrame: ...
|
|
61
|
+
|
|
62
|
+
@classmethod
|
|
63
|
+
def from_tidy_dataframe(cls, df: pd.DataFrame) -> "IsSpatialDataSet[FeaturesT]": ...
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class IsSpatioTemporalDataSet(Protocol[FeaturesT]):
|
|
67
|
+
dataclass = ...
|
|
68
|
+
|
|
69
|
+
def get_data_for_locations(
|
|
70
|
+
self, location: Iterable[SpatialIndexType]
|
|
71
|
+
) -> "IsSpatioTemporalDataSet[FeaturesT]": ...
|
|
72
|
+
|
|
73
|
+
def get_data_for_location(self, location: SpatialIndexType) -> FeaturesT: ...
|
|
74
|
+
|
|
75
|
+
def restrict_time_period(
|
|
76
|
+
self, start_period: Period = None, end_period: Period = None
|
|
77
|
+
) -> "IsSpatioTemporalDataSet[FeaturesT]": ...
|
|
78
|
+
|
|
79
|
+
def start_time(self) -> Period: ...
|
|
80
|
+
|
|
81
|
+
def end_time(self) -> Period: ...
|
|
82
|
+
|
|
83
|
+
def locations(self) -> Iterable[SpatialIndexType]: ...
|
|
84
|
+
|
|
85
|
+
def data(self) -> Iterable[FeaturesT]: ...
|
|
86
|
+
|
|
87
|
+
def location_items(
|
|
88
|
+
self,
|
|
89
|
+
) -> Iterable[Tuple[SpatialIndexType, IsTemporalDataSet[FeaturesT]]]: ...
|
|
90
|
+
|
|
91
|
+
def to_tidy_dataframe(self) -> pd.DataFrame: ...
|
|
92
|
+
|
|
93
|
+
@classmethod
|
|
94
|
+
def from_tidy_dataframe(
|
|
95
|
+
cls, df: pd.DataFrame
|
|
96
|
+
) -> "IsSpatioTemporalDataSet[FeaturesT]": ...
|
|
97
|
+
|
|
98
|
+
def to_csv(self, file_name: str): ...
|
|
99
|
+
|
|
100
|
+
@classmethod
|
|
101
|
+
def from_csv(self, file_name: str) -> "IsSpatioTemporalDataSet[FeaturesT]": ...
|
|
File without changes
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
from gluonts.model.estimator import Estimator
|
|
2
|
+
from gluonts.dataset.common import ListDataset
|
|
3
|
+
from gluonts.model.predictor import Predictor
|
|
4
|
+
from ..data import DataSet
|
|
5
|
+
from ..data.gluonts_adaptor.dataset import DataSetAdaptor
|
|
6
|
+
from ..datatypes import Samples
|
|
7
|
+
from ..time_period import PeriodRange
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
from dataclasses import dataclass
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@dataclass
|
|
13
|
+
class GluonTSPredictor:
|
|
14
|
+
gluonts_predictor: Predictor
|
|
15
|
+
|
|
16
|
+
def predict(
|
|
17
|
+
self, history: DataSet, future_data: DataSet, num_samples=100
|
|
18
|
+
) -> DataSet:
|
|
19
|
+
gluonts_dataset = DataSetAdaptor.to_gluonts_testinstances(
|
|
20
|
+
history, future_data, self.gluonts_predictor.prediction_length
|
|
21
|
+
)
|
|
22
|
+
forecasts = self.gluonts_predictor.predict(
|
|
23
|
+
gluonts_dataset, num_samples=num_samples
|
|
24
|
+
)
|
|
25
|
+
data = {
|
|
26
|
+
location: Samples(
|
|
27
|
+
PeriodRange.from_pandas(forecast.index), forecast.samples.T
|
|
28
|
+
)
|
|
29
|
+
for location, forecast in zip(history.keys(), forecasts)
|
|
30
|
+
}
|
|
31
|
+
return DataSet(data)
|
|
32
|
+
|
|
33
|
+
def save(self, filename: str):
|
|
34
|
+
filepath = Path(filename)
|
|
35
|
+
filepath.mkdir(exist_ok=True, parents=True)
|
|
36
|
+
self.gluonts_predictor.serialize(filepath)
|
|
37
|
+
|
|
38
|
+
@classmethod
|
|
39
|
+
def load(cls, filename: str):
|
|
40
|
+
return GluonTSPredictor(Predictor.deserialize(Path(filename)))
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
@dataclass
|
|
44
|
+
class GluonTSEstimator:
|
|
45
|
+
gluont_ts_estimator: Estimator
|
|
46
|
+
|
|
47
|
+
def train(self, dataset: DataSet) -> GluonTSPredictor:
|
|
48
|
+
gluonts_dataset = DataSetAdaptor.to_gluonts(dataset)
|
|
49
|
+
ds = ListDataset(gluonts_dataset, freq="m")
|
|
50
|
+
return GluonTSPredictor(self.gluont_ts_estimator.train(ds))
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
from typing import Iterable
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
from pydantic import BaseModel
|
|
5
|
+
|
|
6
|
+
# Epidemioglical week: different from calendar week
|
|
7
|
+
# https://www.cdc.gov/flu/weekly/overview.htm
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class OutbreakParameters(BaseModel):
|
|
11
|
+
endemic_factor: float
|
|
12
|
+
probability_threshold: float
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def outbreak_prediction(
|
|
16
|
+
parameters: OutbreakParameters, case_samples: Iterable[float]
|
|
17
|
+
) -> bool:
|
|
18
|
+
return np.mean()
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import json
|
|
3
|
+
|
|
4
|
+
from .assessment.forecast import forecast as do_forecast
|
|
5
|
+
import zipfile
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from typing import Optional, List
|
|
8
|
+
|
|
9
|
+
import numpy as np
|
|
10
|
+
|
|
11
|
+
from .assessment.dataset_splitting import train_test_split_with_weather
|
|
12
|
+
from .datatypes import (
|
|
13
|
+
HealthData,
|
|
14
|
+
ClimateData,
|
|
15
|
+
HealthPopulationData,
|
|
16
|
+
SimpleClimateData,
|
|
17
|
+
FullData,
|
|
18
|
+
)
|
|
19
|
+
from .dhis2_interface.json_parsing import (
|
|
20
|
+
predictions_to_datavalue,
|
|
21
|
+
parse_disease_data,
|
|
22
|
+
json_to_pandas,
|
|
23
|
+
parse_population_data,
|
|
24
|
+
)
|
|
25
|
+
from .external.external_model import get_model_from_directory_or_github_url
|
|
26
|
+
from .file_io.example_data_set import DataSetType, datasets
|
|
27
|
+
from .geojson import geojson_to_graph, NeighbourGraph
|
|
28
|
+
from .plotting.prediction_plot import plot_forecast_from_summaries
|
|
29
|
+
from .predictor import get_model
|
|
30
|
+
from .spatio_temporal_data.temporal_dataclass import DataSet
|
|
31
|
+
import dataclasses
|
|
32
|
+
|
|
33
|
+
from .time_period.date_util_wrapper import delta_month, Month
|
|
34
|
+
|
|
35
|
+
from .transformations.covid_mask import mask_covid_data
|
|
36
|
+
|
|
37
|
+
logger = logging.getLogger(__name__)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class DummyControl:
|
|
41
|
+
def set_status(self, status):
|
|
42
|
+
pass
|
|
43
|
+
|
|
44
|
+
@property
|
|
45
|
+
def current_control(self):
|
|
46
|
+
return None
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
@dataclasses.dataclass
|
|
50
|
+
class AreaPolygons:
|
|
51
|
+
shape_file: str
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
@dataclasses.dataclass
|
|
55
|
+
class PredictionData:
|
|
56
|
+
area_polygons: AreaPolygons = None
|
|
57
|
+
health_data: DataSet[HealthData] = None
|
|
58
|
+
climate_data: DataSet[ClimateData] = None
|
|
59
|
+
population_data: DataSet[HealthPopulationData] = None
|
|
60
|
+
disease_id: Optional[str] = None
|
|
61
|
+
features: List[object] = None
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def extract_disease_name(health_data: dict) -> str:
|
|
65
|
+
return health_data["rows"][0][0]
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def read_zip_folder(zip_file_path: str) -> PredictionData:
|
|
69
|
+
# read zipfile, create PredictionData
|
|
70
|
+
print(zip_file_path)
|
|
71
|
+
ziparchive = zipfile.ZipFile(zip_file_path)
|
|
72
|
+
expected_files = {
|
|
73
|
+
"area_polygons": "orgUnits.geojson",
|
|
74
|
+
"disease": "disease.json",
|
|
75
|
+
"population": "population.json",
|
|
76
|
+
"temperature": "temperature.json",
|
|
77
|
+
"precipitation": "precipitation.json",
|
|
78
|
+
}
|
|
79
|
+
json_data = json.load(ziparchive.open(expected_files["disease"]))
|
|
80
|
+
name_mapping = {"time_period": 2, "disease_cases": 3, "location": 1}
|
|
81
|
+
disease = parse_disease_data(json_data, name_mapping=name_mapping)
|
|
82
|
+
disease_id = extract_disease_name(json_data)
|
|
83
|
+
temperature_json = json.load(ziparchive.open(expected_files["temperature"]))
|
|
84
|
+
name_mapping = {"time_period": 2, "mean_temperature": 3, "location": 1}
|
|
85
|
+
temperature = json_to_pandas(temperature_json, name_mapping)
|
|
86
|
+
|
|
87
|
+
precipitation_json = json.load(ziparchive.open(expected_files["temperature"]))
|
|
88
|
+
name_mapping = {"time_period": 2, "precipitation": 3, "location": 1}
|
|
89
|
+
precipitation = json_to_pandas(precipitation_json, name_mapping)
|
|
90
|
+
|
|
91
|
+
assert np.all(precipitation.time_period == temperature.time_period)
|
|
92
|
+
assert np.all(precipitation.location == temperature.location)
|
|
93
|
+
|
|
94
|
+
temperature["rainfall"] = precipitation["precipitation"]
|
|
95
|
+
temperature["rainfall"] = temperature["rainfall"].astype(float)
|
|
96
|
+
temperature["mean_temperature"] = temperature["mean_temperature"].astype(float)
|
|
97
|
+
|
|
98
|
+
features = json.load(ziparchive.open(expected_files["area_polygons"]))["features"]
|
|
99
|
+
climate = DataSet.from_pandas(temperature, dataclass=SimpleClimateData)
|
|
100
|
+
|
|
101
|
+
population_json = json.load(ziparchive.open(expected_files["population"]))
|
|
102
|
+
population = parse_population_data(population_json)
|
|
103
|
+
graph_file_name = ""
|
|
104
|
+
graph = NeighbourGraph.from_geojson_file(
|
|
105
|
+
ziparchive.open(expected_files["area_polygons"])
|
|
106
|
+
)
|
|
107
|
+
print(graph)
|
|
108
|
+
if False:
|
|
109
|
+
graph_file_name = Path(zip_file_path).with_suffix(".graph")
|
|
110
|
+
area_polygons_file = ziparchive.open(expected_files["area_polygons"])
|
|
111
|
+
geojson_to_graph(area_polygons_file, graph_file_name)
|
|
112
|
+
# geojson_to_shape(area_polygons_file, shape_file_name)
|
|
113
|
+
|
|
114
|
+
# geojson_to_shape(str(zip_file_path) + "!area_polygons", shape_file_name)
|
|
115
|
+
|
|
116
|
+
return PredictionData(
|
|
117
|
+
health_data=disease,
|
|
118
|
+
climate_data=climate,
|
|
119
|
+
population_data=population,
|
|
120
|
+
area_polygons=graph,
|
|
121
|
+
disease_id=disease_id,
|
|
122
|
+
features=features,
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
out_data = {}
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
# ...
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def dhis_zip_flow(
|
|
132
|
+
zip_file_path: str,
|
|
133
|
+
out_json: Optional[str] = None,
|
|
134
|
+
model_name=None,
|
|
135
|
+
n_months=4,
|
|
136
|
+
docker_filename: Optional[str] = None,
|
|
137
|
+
) -> List[dict] | None:
|
|
138
|
+
data: PredictionData = read_zip_folder(zip_file_path)
|
|
139
|
+
json_body = train_on_prediction_data(data, model_name, n_months, docker_filename)
|
|
140
|
+
if out_json is not None:
|
|
141
|
+
with open(out_json, "w") as f:
|
|
142
|
+
json.dump(json_body, f)
|
|
143
|
+
return None
|
|
144
|
+
else:
|
|
145
|
+
return json_body
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
def train_on_prediction_data(
|
|
149
|
+
data,
|
|
150
|
+
model_name=None,
|
|
151
|
+
n_months=4,
|
|
152
|
+
docker_filename=None,
|
|
153
|
+
model_path=None,
|
|
154
|
+
control=None,
|
|
155
|
+
):
|
|
156
|
+
if control is None:
|
|
157
|
+
control = DummyControl()
|
|
158
|
+
control.set_status("Preprocessing")
|
|
159
|
+
if model_name == "external":
|
|
160
|
+
model = get_model_from_directory_or_github_url(model_path)
|
|
161
|
+
else:
|
|
162
|
+
model = get_model(model_name)()
|
|
163
|
+
start_timestamp = min(
|
|
164
|
+
data.health_data.start_timestamp, data.climate_data.start_timestamp
|
|
165
|
+
)
|
|
166
|
+
end_timestamp = max(data.health_data.end_timestamp, data.climate_data.end_timestamp)
|
|
167
|
+
new_dict = {}
|
|
168
|
+
for location in data.health_data.locations():
|
|
169
|
+
health = data.health_data.get_location(location).fill_to_range(
|
|
170
|
+
start_timestamp, end_timestamp
|
|
171
|
+
)
|
|
172
|
+
climate = data.climate_data.get_location(location).fill_to_range(
|
|
173
|
+
start_timestamp, end_timestamp
|
|
174
|
+
)
|
|
175
|
+
assert (
|
|
176
|
+
location in data.population_data
|
|
177
|
+
), f"Location {location} not in population data: {data.population_data.keys()}"
|
|
178
|
+
population = data.population_data[location]
|
|
179
|
+
new_dict[location] = FullData.combine(health.data(), climate.data(), population)
|
|
180
|
+
|
|
181
|
+
climate_health_data = DataSet(new_dict)
|
|
182
|
+
prediction_start = Month(climate_health_data.end_timestamp) - n_months * delta_month
|
|
183
|
+
train_data, _, future_weather = train_test_split_with_weather(
|
|
184
|
+
climate_health_data, prediction_start
|
|
185
|
+
)
|
|
186
|
+
logger.info(f"Training model {model_name} on {len(train_data.items())} locations")
|
|
187
|
+
control.set_status("Training")
|
|
188
|
+
if hasattr(model, "set_training_control"):
|
|
189
|
+
model.set_training_control(control.current_control)
|
|
190
|
+
if hasattr(model, "set_graph"):
|
|
191
|
+
model.set_graph(data.area_polygons)
|
|
192
|
+
|
|
193
|
+
model.train(train_data) # , extra_args=data.area_polygons)
|
|
194
|
+
logger.info(
|
|
195
|
+
f"Forecasting using {model_name} on {len(train_data.items())} locations"
|
|
196
|
+
)
|
|
197
|
+
control.set_status("Forecasting")
|
|
198
|
+
predictions = model.forecast(future_weather, forecast_delta=n_months * delta_month)
|
|
199
|
+
attrs = ["median", "quantile_high", "quantile_low"]
|
|
200
|
+
logger.info("Converting predictions to json")
|
|
201
|
+
control.set_status("Postprocessing")
|
|
202
|
+
data_values = predictions_to_datavalue(
|
|
203
|
+
predictions, attribute_mapping=dict(zip(attrs, attrs))
|
|
204
|
+
)
|
|
205
|
+
json_body = [dataclasses.asdict(element) for element in data_values]
|
|
206
|
+
diseaseId = data.disease_id
|
|
207
|
+
return {"diseaseId": diseaseId, "dataValues": json_body}
|
|
208
|
+
# return json_body
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
def train_with_validation(model_name, dataset_name, n_months=12):
|
|
212
|
+
dataset = datasets[dataset_name].load()
|
|
213
|
+
# assert not np.any(np.any(np.isnan(data.to_array()[:, 1:])) for data in dataset.values()), "Dataset contains NaN values"
|
|
214
|
+
# assert not any(np.any(np.isnan(data.mean_temperature) | np.isnan(data.rainfall)) for data in dataset.values()), "Dataset contains NaN values"
|
|
215
|
+
dataset = mask_covid_data(dataset)
|
|
216
|
+
model = get_model(model_name)(n_iter=32000)
|
|
217
|
+
# split_point = dataset.end_timestamp - n_months * delta_month
|
|
218
|
+
# train_data, test_data, future_weather = train_test_split_with_weather(dataset, split_point)
|
|
219
|
+
prediction_length = n_months * delta_month
|
|
220
|
+
split_point = dataset.end_timestamp - prediction_length
|
|
221
|
+
split_period = Month(split_point.year, split_point.month)
|
|
222
|
+
train_data, test_set, future_weather = train_test_split_with_weather(
|
|
223
|
+
dataset, split_period
|
|
224
|
+
)
|
|
225
|
+
model.set_validation_data(test_set)
|
|
226
|
+
model.train(train_data)
|
|
227
|
+
predictions = model.forecast(
|
|
228
|
+
future_weather, forecast_delta=n_months * delta_month, n_samples=100
|
|
229
|
+
)
|
|
230
|
+
# plot predictions
|
|
231
|
+
figs = []
|
|
232
|
+
for location, prediction in predictions.items():
|
|
233
|
+
fig = plot_forecast_from_summaries(
|
|
234
|
+
prediction.data(), dataset.get_location(location).data()
|
|
235
|
+
) # , lambda x: np.log(x+1))
|
|
236
|
+
figs.append(fig)
|
|
237
|
+
return figs
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
def forecast(
|
|
241
|
+
model_name: str,
|
|
242
|
+
dataset_name: DataSetType,
|
|
243
|
+
n_months: int,
|
|
244
|
+
model_path: Optional[str] = None,
|
|
245
|
+
):
|
|
246
|
+
logging.basicConfig(level=logging.INFO)
|
|
247
|
+
dataset = datasets[dataset_name].load()
|
|
248
|
+
|
|
249
|
+
if model_name == "external":
|
|
250
|
+
model = get_model_from_directory_or_github_url(model_path)
|
|
251
|
+
else:
|
|
252
|
+
model = get_model(model_name)
|
|
253
|
+
model = model()
|
|
254
|
+
|
|
255
|
+
# model = get_model(model_name)()
|
|
256
|
+
predictions = do_forecast(model, dataset, n_months * delta_month)
|
|
257
|
+
|
|
258
|
+
figs = []
|
|
259
|
+
for location, prediction in predictions.items():
|
|
260
|
+
fig = plot_forecast_from_summaries(
|
|
261
|
+
prediction.data(), dataset.get_location(location).data()
|
|
262
|
+
) # , lambda x: np.log(x+1))
|
|
263
|
+
figs.append(fig)
|
|
264
|
+
return figs
|