Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@sbuse
Copy link
Contributor

@sbuse sbuse commented Dec 1, 2023

Reference Issues/PRs

Discussion #5197

Depends on #5622 which should be merged first.

What does this implement/fix? Explain your changes.

This PR extracts the piece wise linear trend from the prophet algorithm. The algorithm is well suited to be used for trend forecasting in a pipeline and less useful alone.

Does your contribution introduce a new dependency? If yes, which one?

no new dependency, prophet was already implemented.

What should a reviewer concentrate their feedback on?

Since this is my first PR for sktime it would be good if the reviewer could check if i have done everything required and according to the conventions.

Did you add any tests for the change?

No I haven't added any test.

Any other comments?

PR checklist

For all contributions
  • I've added myself to the list of contributors with any new badges I've earned :-)
    How to: add yourself to the all-contributors file in the sktime root directory (not the CONTRIBUTORS.md). Common badges: code - fixing a bug, or adding code logic. doc - writing or improving documentation or docstrings. bug - reporting or diagnosing a bug (get this plus code if you also fixed the bug in the PR).maintenance - CI, test framework, release.
    See here for full badge reference
  • Optionally, I've added myself and possibly others to the CODEOWNERS file - do this if you want to become the owner or maintainer of an estimator you added.
    See here for further details on the algorithm maintainer role.
  • The PR title starts with either [ENH], [MNT], [DOC], or [BUG]. [BUG] - bugfix, [MNT] - CI, test framework, [ENH] - adding or improving code, [DOC] - writing or improving documentation or docstrings.
For new estimators
  • I've added the estimator to the API reference - in docs/source/api_reference/taskname.rst, follow the pattern.
  • I've added one or more illustrative usage examples to the docstring, in a pydocstyle compliant Examples section.
  • If the estimator relies on a soft dependency, I've set the python_dependencies tag and ensured
    dependency isolation, see the estimator dependencies guide.

@sbuse
Copy link
Contributor Author

sbuse commented Dec 1, 2023

Hello core developers this is my first PR and I would be happy to get some feedback and improve the code if needed.

Copy link
Collaborator

@fkiraly fkiraly left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good on superficial look!

One issue - which the tests will also highlight - is that you are not adhering to sktime code formatting (linting). These are various small and - logic-wise - inconsequential things, but it is enforced.

Instructions on this, including how to set this up on your computer in an automated way, here:
https://www.sktime.net/en/stable/developer_guide/coding_standards.html

@fkiraly fkiraly added module:forecasting forecasting module: forecasting, incl probabilistic and hierarchical forecasting enhancement Adding new functionality labels Dec 1, 2023
@sbuse
Copy link
Contributor Author

sbuse commented Dec 4, 2023

Looks good on superficial look!

One issue - which the tests will also highlight - is that you are not adhering to sktime code formatting (linting). These are various small and - logic-wise - inconsequential things, but it is enforced.

Instructions on this, including how to set this up on your computer in an automated way, here: https://www.sktime.net/en/stable/developer_guide/coding_standards.html

Thanks @fkiraly for the comments. I ran pre-commit run --all-files which hopefully fixed all linting complaints.

@yarnabrina yarnabrina mentioned this pull request Dec 4, 2023
6 tasks
Copy link
Collaborator

@fkiraly fkiraly left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great!

There is a subtle issue, related to how sktime does testing.

In testing, we pass multiple data scenarios to fit/predict, this is with varying index and index type.

In get_test_params, you have specified changepoints that make sense for some indices, but not for others, but all data scenarios are run with these parameters, which can lead to the "changepoints outside range" issue.

An acceptable solution would be, imo, to specify changepoints only by number or relatively, without direct reference to the index range, and set up separate tests, in a test_pwl_trend or similar file, with changepoints matching index range.

fkiraly
fkiraly previously approved these changes Dec 13, 2023
Copy link
Collaborator

@fkiraly fkiraly left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me.

I would recommend, let's add at least a second parameter set to get_test_params as well, covering different parameter settings.

Will not merge yet as this is still a draft, but looks done.

@fkiraly
Copy link
Collaborator

fkiraly commented Dec 13, 2023

FYI @sbuse , @tpvasconcelos, @yarnabrina, this PR actually contains an example of a second descendant of _ProphetAdapter.

Post-merge #5597, code that previously would not have failed, fails now.
To address this, I have decoupled the fit_kwargs parameter better in #5622, and have merged it into this PR. #5622 should be merged first.

Reviews would be appreciated, from the perspective of the prophet adapter.

@sbuse
Copy link
Contributor Author

sbuse commented Dec 14, 2023

Looks good to me.

I would recommend, let's add at least a second parameter set to get_test_params as well, covering different parameter settings.

Will not merge yet as this is still a draft, but looks done.

Okay, I will add test_pwl_trend and include some tests there. It feels a bit redundant since this is just a wrapper but I figure it is good practice to fully test the code you want to commit.

@tpvasconcelos
Copy link
Contributor

@sbuse @fkiraly quick question on this one. Referencing the original example in #5197 , isn't this already possible with:

pwl_trend_forecaster = Prophet(
    daily_seasonality=False,
    weekly_seasonality=False,
    yearly_seasonality=False
)
forecaster = TransformedTargetForecaster(
    [
        ("detrend", Detrender(forecaster=pwl_trend_forecaster)),
        ("forecast", ARIMA() )  
    ]
)

@sbuse sbuse marked this pull request as ready for review December 21, 2023 14:49
@fkiraly fkiraly changed the title [ENH] Adding a piecewise linear trend forecaster [ENH] prophet based piecewise linear trend forecaster Dec 24, 2023
@fkiraly fkiraly merged commit 101ce68 into sktime:main Dec 24, 2023
@sbuse
Copy link
Contributor Author

sbuse commented Jan 18, 2024

Hi @tpvasconcelos, Hi @fkiraly
I ran an experimental test to see if the suggestion from @tpvasconcelos or the current implementation works better on an experimental level. The suggestion looks good but a quick test showed that the current implementation and the suggestions tend to not return the same result. That is why I wanted to test this more rigorously. I created some random data with no structure and let the two implementations fit it. What I got, as a result, is that the current implementation seems to be a tiny bit better than what @tpvasconcelos suggested. I think this shows that the current implementation is fine. Please let me know if you think otherwise or have any suggestions.

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sktime.forecasting.base                import ForecastingHorizon
from sktime.forecasting.trend               import ProphetPiecewiseLinearTrendForecaster
from sktime.forecasting.model_selection     import temporal_train_test_split
from sktime.forecasting.fbprophet           import Prophet
from sktime.performance_metrics.forecasting import MeanSquaredError

def Randomwalk1D(n): 
   y = 0
   yposition = [0] 
   for i in range(n-1):
       step = np.random.uniform(0,1)
       if step < 0.5:  
           y += 1  
       if step > 0.5:   
           y += -1 
       yposition.append(y)
   return yposition

n = 1000
np.random.seed(42)
mse = MeanSquaredError(square_root=True)
all_mse_current = []
all_mse_suggestion = []

for prior_scale in np.logspace(-3,-1/3,num=10): #values within 0.001 and 0.46
    for i in range(500):
        y = pd.Series(
                    data=Randomwalk1D(n),
                    index=pd.date_range('2016-01-01',periods=n, freq='15min')
                    )
        y_train, y_test = temporal_train_test_split(y)
        fh = ForecastingHorizon(y.index, is_relative=False)
        current = ProphetPiecewiseLinearTrendForecaster(
                            changepoint_prior_scale=prior_scale
                            )
        suggestion = Prophet(
                            daily_seasonality=False,
                            weekly_seasonality=False,
                            yearly_seasonality=False,
                            changepoint_prior_scale=prior_scale
                            )
        
        y_pred_current  = current.fit(y).predict(fh)
        y_pred_suggestion  = suggestion.fit(y).predict(fh)        
        mse_current = mse(y,y_pred_current)
        mse_suggestion = mse(y,y_pred_suggestion)

        all_mse_current.append(mse_current)
        all_mse_suggestion.append(mse_suggestion)

total = len(np.array(all_mse_current))
current_wins = np.sum(np.array(all_mse_current)<np.array(all_mse_suggestion))
suggestion_wins = np.sum(np.array(all_mse_current)>np.array(all_mse_suggestion))
ties = np.sum(np.array(all_mse_current)==np.array(all_mse_suggestion))

print(f"Out of {total} runs: \nThe current implementation is more accurate in "+
      f"{current_wins} ({np.round_(current_wins/total*100,1)}%) cases.\n"+
      f"The suggested change is more accurate in {suggestion_wins}"+
      f"({np.round_(suggestion_wins/total*100,1)}%) cases.\n"+
      f"In {ties} ({np.round_(ties/total*100,1)}%) cases they return the same value.")        
Out of 5000 runs: 
The current implementation is more accurate in 2908 (58.2%) cases.
The suggested change is more accurate in 2092(41.8%) cases.
In 0 (0.0%) cases they return the same value.
        

@fkiraly
Copy link
Collaborator

fkiraly commented Jan 20, 2024

probably will depend on the data - my intuition would tell me, if there are different sensible suggestions on how it should behave internally, just expose them to the user, i.e., the seasonality parameters, with default being current.

@sbuse sbuse deleted the pcw-linear-detrender branch January 25, 2024 14:29
fkiraly pushed a commit that referenced this pull request Feb 18, 2024
…ecaster (#5834)

<!--
Welcome to sktime, and thanks for contributing!
Please have a look at our contribution guide:
https://www.sktime.net/en/latest/get_involved/contributing.html
-->
The PR exposes the seasonal parameters of the
ProphetPiecewiseLinearTrendForecaster.

The PR is the result of the discussion in this
(#5592).

#### What does this implement/fix? Explain your changes.
<!--
A clear and concise description of what you have implemented.
-->
This is a simple change to allow the user to define what the seasonality
parameters should be. @tpvasconcelos suggested they should be

```python
daily_seasonality=False,
weekly_seasonality=False,
yearly_seasonality=False
```
but as the discussion (#5592)
showed it is not clear if this is the best setting.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement Adding new functionality module:forecasting forecasting module: forecasting, incl probabilistic and hierarchical forecasting

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants