- a `Path` is a better description for an instance of the model
- the `Location`s en route are renamed into `.waypoints`
- generic `assoc` is renamed into `path` in the test suite
Adapt code to prevent new warnings and errors (as of SQLAlchemy 1.4):
- Overlapping foreign key columns could be set in a conflicting way
=> This is prevented by the application logic
=> Ignore the warning by setting a `overlaps` flag
- Transaction already rolled back
=> This only happens when tests cause an `IntegrityError` on purpose
=> Filter away the corresponding warning in the fixture
- Query returns `Row` objects and not scalars
=> Add genexpr to pull out `primary_id`
... from the dev dependencies.
Longer queries in SQLAlchemy get flagged even though they are not
complicated. Other expressions are generally not that complicated.
- as of September 2021, PyCharm is used to write some of the code
- PyCharm's built-in code styler, linter, and type checker issued
some warnings that are resolved in this commit
+ spelling mistakes
+ all instance attributes must be specified explicitly
in a class's __init__() method
=> use `functools.cached_property` for caching
+ make `tuple`s explicit with `(...)`
+ one test failed randomly although everything is ok
=> adjust the fixture's return value (stub for Google Directions API)
+ reformulate SQL so that PyCharm can understand the symbols
- problem: because of the randomization of test cases, every once in a
while, the schema holding the test db already exists and cannot be
created a second time (background: we run all tests against a db
created with `metadate.create_all()` by SQLAlchemy at once and
a db created by running all incremental Alchemy migration scripts)
- quick fix: possible, we could find a way to run all tests against
one of the two test db's in random order and then against the other
=> in the interest of time, we simply do not randomize the test cases
- `DistanceMatrix.from_addresses()` takes a variable number of
`Address` objects and creates distance matrix entries for them
- as a base measure, the air distance between two `Address`
objects is calculated
- in addition, an integration with the Google Maps Directions API is
implemented that provides a more realistic measure of the distance
and duration a rider on a bicycle would need to travel between two
`Address` objects
- add a `Location.lat_lng` convenience property that provides the
`.latitude` and `.longitude` of an `Address` as a 2-`tuple`
- the class stores the data of a distance matrix between all addresses
+ air distances
+ bicycle distances
- in addition, the "path" returned by the Google Directions API are
also stored as a JSON serialized sequence of latitude-longitude pairs
- we assume a symmetric graph
- the first notebook runs the tactical-forecasts command
- the second notebook describes the tactical demand forecasting process
+ demand aggregation on a per-pixel level
+ time series generation: horizontal, vertical, and real-time time series
+ STL decomposition into seasonal, trend, and residual components
+ choosing the most promising forecasting model
+ predicting demand with various models
- fix where to re-start the forecasting process after it was interrupted
- enable the heuristic for choosing the most promising model
to also work for 7 training weeks
- the two notebook files are helpful in visualizing all relevant
pickup (red) or delivery (blue) locations from the point of view
of either e restaurant or a customer
- add notebook that runs the plotting code
- add three visualizations per city:
+ all addresses, colored by zip code
+ all restaurants, incl. the number of received orders
+ all restaurants on a grid with pixel side length of 1000m
- the model applies a simple moving average on horizontal time series
- refactor `db.Forecast.from_dataframe()` to correctly convert
`float('NaN')` values into `None`; otherwise, SQLAlchemy complains
- the method implements a heuristic from the first research paper
that chooses the most promising forecasting `*Model` based on
the average daily demand in a `Pixel` for a given `train_horizon`
- adjust the test scenario => `LONG_TRAIN_HORIZON` becomes `8`
as that is part of the rule implemented in the heuristic
- `*Model`s use the `methods.*.predict()` functions to predict demand
given an order time series generated by `timify.OrderHistory`
- `models.base.ForecastingModelABC` unifies how all `*Model`s work
and implements a caching strategy
- implement three `*Model`s for tactical forecasting, based on the
hets, varima, and rtarima models described in the first research paper
- add overall documentation for `urban_meal_delivery.forecasts` package
- move the fixtures in `tests.forecasts.timify.conftest` to
`tests.forecasts.conftest` and adjust the horizon of the test horizon
from two to three weeks
- the function implements a forecasting "method" similar to the
seasonal naive method
=> instead of simply taking the last observation given a seasonal lag,
it linearly extrapolates all observations of the same seasonal lag
from the past into the future; conceptually, it is like the
seasonal naive method with built-in smoothing
- the function is tested just like the `arima.predict()` and
`ets.predict()` functions
+ rename the `tests.forecasts.methods.test_ts_methods` module
into `tests.forecasts.methods.test_predictions`
- re-organize some constants in the `tests` package
- streamline some docstrings
- move the module
- unify the corresponding tests in `tests.forecasts.methods` sub-package
- make all `predict()` and the `stl()` function round results
- streamline documentation