{"id":28203972,"url":"https://github.com/kyleclo/structural","last_synced_at":"2025-06-10T14:30:41.081Z","repository":{"id":153274189,"uuid":"85387934","full_name":"kyleclo/structural","owner":"kyleclo","description":"Structural time series modeling and forecasting in Python","archived":false,"fork":false,"pushed_at":"2017-09-08T05:52:45.000Z","size":2360,"stargazers_count":9,"open_issues_count":1,"forks_count":4,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-05-17T03:17:08.057Z","etag":null,"topics":["changepoint","forecast","forecasting","prophet","python","stan","structural","time-series","timeseries"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kyleclo.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2017-03-18T08:52:14.000Z","updated_at":"2023-11-11T23:52:15.000Z","dependencies_parsed_at":"2023-07-12T11:45:46.912Z","dependency_job_id":null,"html_url":"https://github.com/kyleclo/structural","commit_stats":{"total_commits":21,"total_committers":1,"mean_commits":21.0,"dds":0.0,"last_synced_commit":"ac26bb4226bceb88acc95f4d479dffa21bd5d475"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kyleclo%2Fstructural","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kyleclo%2Fstructural/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kyleclo%2Fstructural/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kyleclo%2Fstructural/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kyleclo","download_url":"https://codeload.github.com/kyleclo/structural/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kyleclo%2Fstructural/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":259092517,"owners_count":22804029,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["changepoint","forecast","forecasting","prophet","python","stan","structural","time-series","timeseries"],"created_at":"2025-05-17T03:17:54.901Z","updated_at":"2025-06-10T14:30:41.072Z","avatar_url":"https://github.com/kyleclo.png","language":"Python","readme":"# Structural time series modeling and forecasting\n\n**Structural** is a Python library for structural time series modeling and forecasting of daily univariate sequential data.\n\nThis code is released under the BSD 3-Clause license, which I've included in this repo under `/LICENSE`.\n\n\n## Installation\n\nClone the repo if you want the source code\n```\ngit clone https://github.com/kyleclo/structural.git\npip install -r requirements.txt\n```\n\nOr install the module using\n```\npip install git+git://github.com/kyleclo/structural.git#egg=structural\n```\n\n\n## Usage\n\nTypical usage looks like this:\n\n```python\nimport pandas as pd\nfrom structural import LinearTrend\n\ndf = pd.read_csv(DATA_FILEPATH)\nmodel = LinearTrend(STAN_MODEL_FILEPATH)\nmodel.fit(df)\n\nyhat_fitted = model.predict(df)\n\nnew_df = pd.DataFrame({'ds': model.make_forecast_dates(h=100)})\nyhat_forecasted = model.predict(new_df)\n```\n\nSee `/example.py` for a sample script.  I recommend using it as starter code for those looking to deploy an automated forecasting service.\n\n\n## Backlog\n\nI'm currently working on (in no particular order):\n\n  1. Adding in MCMC sampling + variability estimation\n  2. Adding in manual changepoint selection\n  3. Adding in manual holiday indicators\n  4. Adding a prior over changepoint locations\n  5. Adding in ARMA errors\n  6. Adding a testing suite\n  7. Creating a pypi distribution\n  8. Generalizing LinearTrend to allow for link functions\n  9. Refactor code structure so we're \"building\" each structural component into the model.  (This probably requires piecing together Stan code snippets at runtime)\n  \n\n## About\n\nThis project was inspired by **Prophet**, an open-source library released by the good folks over at Facebook.  Check out their repo here: https://github.com/facebookincubator/prophet.\n\nI developed this library while working at CDK Global on some projects involving large-scale time series forecasting.  I tried using Prophet at first, but their library seems more geared toward use by analysts who will be tuning models manually.  I needed a more general-purpose, automated procedure for my project, so I ended up writing this library instead.  I've documented the differences below, but overall I've maintained a similar API.\n\n## Compared to Prophet\n\nMajor differences include:\n  \n  - In Structural, `Structural` is actually an abstract base class.  Users implement subclasses of `Structural` and instantiation is handled by `Structural.create()` at runtime.  I found this more extensible than Prophet's `Prophet` class, which uses if-statements in its methods to switch between \"linear\" and \"logistic\" growth models.    \n  \n  - In Structural, Stan models are compiled and imported using `Structural.compile_stan_model()` and `Structural.import_stan_model()`, as opposed to Prophet, which compiles Stan models during package installation.  I made this change because I wanted the flexibility to add / modify / select different Stan models at runtime, without having to re-run the package installation.\n  \n  - In Structural, automated changepoint generation places changepoints at the first of each month (excluding the first and last) in the training data, as opposed to Prophet, which generates changepoints using `np.linspace` over the first 80% of training set dates.  I simply felt this was a more intuitive default choice when no changepoints are specified.\n\nOther differences are more for style / personal preference:\n\n  - Stylistically, I've written Structural such that the only methods that can set members are the constructor and `Structural.fit()`, while all other methods will return a result.  Hence, I've removed/rewritten methods with side-effects like `Prophet.setup_dataframe()` and `Prophet.set_changepoints()`.\n  \n  - The user can now specify `yearly_order` and `monthly_order` for the fourier expansion when instantiating a `Structural` object.  In Prophet, these values are hard-coded to `10` and `3` within the `Prophet.make_all_seasonality_features()` method.\n  \n  - I've rewritten `Structural.make_seasonality_df()` and `Structural.make_changepoint_df()` to have consistent style: They both only create the `zeros` feature vector when specifying no seasonality or no changepoints, respectively.  \n    \n  - In Structural, `Structural.make_changepoint_df()` returns a feature vector of zeros (instead of ones) in the no-changepoint case, so the fitted `delta` will be zero.  In Prophet, when specifying no changepoints, `Prophet.get_changepoint_matrix()` will still return a feature vector of ones.  This results in fitting a non-zero `delta` term, which requires an additional correction step in `Prophet.fit()` by setting `k = k + delta` and `delta = 0`.  \n  \n  \nStructural currently doesn't have support for:\n\n  1. MCMC sampling\n  2. Variability estimation (based on (1))\n  3. Plotting   \n\nwhich Prophet provides.\n\n\n*Note: I'm making these comparisons based on what I saw in Prophet v0.0.post1 which have changed by now*","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkyleclo%2Fstructural","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkyleclo%2Fstructural","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkyleclo%2Fstructural/lists"}