Repository: sktime/sktime

Issue:
[BUG] rise.fit fails with "x contains a constant. Adding a constant with trend='c' is not allowed."
**Describe the bug**
<!--
A clear and concise description of what the bug is.
-->
rise.fit fails with error.
**To Reproduce**
<!--
Add a Minimal, Complete, and Verifiable example (for more details, see e.g. 
https://stackoverflow.com/help/mcve

If the code is too long, feel free to put it in a public gist and link
it in the issue: https://gist.github.com
-->

```python
from sktime.transformers.compose import RowwiseTransformer
from sktime.transformers.compose import Tabulariser
from sktime.transformers.segment import RandomIntervalSegmenter
from sktime.pipeline import Pipeline
from sktime.pipeline import FeatureUnion
from sktime.classifiers.compose import TimeSeriesForestClassifier
from sktime.datasets import load_gunpoint
from statsmodels.tsa.stattools import acf
from statsmodels.tsa.ar_model import AR
from sklearn.preprocessing import FunctionTransformer
from sklearn.tree import DecisionTreeClassifier
import numpy as np

X_train, y_train = load_gunpoint(split='TRAIN', return_X_y=True)
X_test, y_test = load_gunpoint(split='TEST', return_X_y=True)

def ar_coefs(x, maxlag=100):
    x = np.asarray(x).ravel()
    nlags = np.minimum(len(x) - 1, maxlag)
    model = AR(endog=x) 
    return model.fit(maxlag=nlags).params.ravel()

def acf_coefs(x, maxlag=100):
    x = np.asarray(x).ravel() 
    nlags = np.minimum(len(x) - 1, maxlag)
    return acf(x, nlags=nlags).ravel()

def powerspectrum(x, **kwargs):
    x = np.asarray(x).ravel()
    fft = np.fft.fft(x)
    ps = fft.real * fft.real + fft.imag * fft.imag
    return ps[:ps.shape[0] // 2].ravel()

steps = [
    ('segment', RandomIntervalSegmenter(n_intervals=1, min_length=5)),
    ('transform', FeatureUnion([
        ('ar', RowwiseTransformer(FunctionTransformer(func=ar_coefs, validate=False))),
        ('acf', RowwiseTransformer(FunctionTransformer(func=acf_coefs, validate=False))),
        ('ps', RowwiseTransformer(FunctionTransformer(func=powerspectrum, validate=False)))
    ])),
    ('tabularise', Tabulariser()),
    ('clf', DecisionTreeClassifier())
]
base_estimator = Pipeline(steps)

rise = TimeSeriesForestClassifier(base_estimator=base_estimator,
                                  n_estimators=50, 
                                  bootstrap=True,
                                  oob_score=True)

rise.fit(X_train, y_train)
if rise.oob_score:
    print(rise.oob_score_)

# ---------------------------------------------------------------------------
# ValueError                                Traceback (most recent call last)
# ~/anaconda3/envs/sktime/lib/python3.7/site-packages/sktime/transformers/compose.py in _apply_rowwise(self, func, X, y)
#     235             Xt = pd.concat([pd.Series(col.apply(func))
# --> 236                             for _, col in X.items()], axis=1)
#     237 

# ~/anaconda3/envs/sktime/lib/python3.7/site-packages/sktime/transformers/compose.py in <listcomp>(.0)
#     235             Xt = pd.concat([pd.Series(col.apply(func))
# --> 236                             for _, col in X.items()], axis=1)
#     237 

# ~/anaconda3/envs/sktime/lib/python3.7/site-packages/pandas/core/series.py in apply(self, func, convert_dtype, args, **kwds)
#    4044                 values = self.astype(object).values
# -> 4045                 mapped = lib.map_infer(values, f, convert=convert_dtype)
#    4046 

# pandas/_libs/lib.pyx in pandas._libs.lib.map_infer()

# ~/anaconda3/envs/sktime/lib/python3.7/site-packages/sklearn/base.py in fit_transform(self, X, y, **fit_params)
#     552             # fit method of arity 1 (unsupervised transformation)
# --> 553             return self.fit(X, **fit_params).transform(X)
#     554         else:

# ~/anaconda3/envs/sktime/lib/python3.7/site-packages/sklearn/preprocessing/_function_transformer.py in transform(self, X)
#     152         """
# --> 153         return self._transform(X, func=self.func, kw_args=self.kw_args)
#     154 

# ~/anaconda3/envs/sktime/lib/python3.7/site-packages/sklearn/preprocessing/_function_transformer.py in _transform(self, X, func, kw_args)
#     178 
# --> 179         return func(X, **(kw_args if kw_args else {}))
#     180 

# <ipython-input-5-9af4e0007a3b> in ar_coefs(x, maxlag)
#      20     model = AR(endog=x)
# ---> 21     return model.fit(maxlag=nlags).params.ravel()
#      22 

# ~/anaconda3/envs/sktime/lib/python3.7/site-packages/statsmodels/tsa/ar_model.py in fit(self, maxlag, method, ic, trend, transparams, start_params, solver, maxiter, full_output, disp, callback, **kwargs)
#     546         # make lagged RHS
# --> 547         X = self._stackX(k_ar, trend)  # sets self.k_trend
#     548         k_trend = self.k_trend

# ~/anaconda3/envs/sktime/lib/python3.7/site-packages/statsmodels/tsa/ar_model.py in _stackX(self, k_ar, trend)
#     390         if k_trend:
# --> 391             X = add_trend(X, prepend=True, trend=trend, has_constant="raise")
#     392         self.k_trend = k_trend

# ~/anaconda3/envs/sktime/lib/python3.7/site-packages/statsmodels/tsa/tsatools.py in add_trend(x, trend, prepend, has_constant)
#     107                       "trend='{0}' is not allowed.".format(trend)
# --> 108                 raise ValueError(msg)
#     109             elif has_constant == 'skip':

# ValueError: x contains a constant. Adding a constant with trend='c' is not allowed.

# During handling of the above exception, another exception occurred:

# ValueError                                Traceback (most recent call last)
# <ipython-input-5-9af4e0007a3b> in <module>
#      49                                   oob_score=True)
#      50 
# ---> 51 rise.fit(X_train, y_train)
#      52 if rise.oob_score:
#      53     print(rise.oob_score_)

# ~/anaconda3/envs/sktime/lib/python3.7/site-packages/sktime/classifiers/compose/ensemble.py in fit(self, X, y, sample_weight)
#     354                     t, self, X, y, sample_weight, i, len(trees),
#     355                     verbose=self.verbose, class_weight=self.class_weight)
# --> 356                 for i, t in enumerate(trees))
#     357 
#     358             # Collect newly grown trees

# ~/anaconda3/envs/sktime/lib/python3.7/site-packages/joblib/parallel.py in __call__(self, iterable)
#    1002             # remaining jobs.
#    1003             self._iterating = False
# -> 1004             if self.dispatch_one_batch(iterator):
#    1005                 self._iterating = self._original_iterator is not None
#    1006 

# ~/anaconda3/envs/sktime/lib/python3.7/site-packages/joblib/parallel.py in dispatch_one_batch(self, iterator)
#     833                 return False
#     834             else:
# --> 835                 self._dispatch(tasks)
#     836                 return True
#     837 

# ~/anaconda3/envs/sktime/lib/python3.7/site-packages/joblib/parallel.py in _dispatch(self, batch)
#     752         with self._lock:
#     753             job_idx = len(self._jobs)
# --> 754             job = self._backend.apply_async(batch, callback=cb)
#     755             # A job can complete so quickly than its callback is
#     756             # called before we get here, causing self._jobs to

# ~/anaconda3/envs/sktime/lib/python3.7/site-packages/joblib/_parallel_backends.py in apply_async(self, func, callback)
#     207     def apply_async(self, func, callback=None):
#     208         """Schedule a func to be run"""
# --> 209         result = ImmediateResult(func)
#     210         if callback:
#     211             callback(result)

# ~/anaconda3/envs/sktime/lib/python3.7/site-packages/joblib/_parallel_backends.py in __init__(self, batch)
#     588         # Don't delay the application, to avoid keeping the input
#     589         # arguments in memory
# --> 590         self.results = batch()
#     591 
#     592     def get(self):

# ~/anaconda3/envs/sktime/lib/python3.7/site-packages/joblib/parallel.py in __call__(self)
#     254         with parallel_backend(self._backend, n_jobs=self._n_jobs):
#     255             return [func(*args, **kwargs)
# --> 256                     for func, args, kwargs in self.items]
#     257 
#     258     def __len__(self):

# ~/anaconda3/envs/sktime/lib/python3.7/site-packages/joblib/parallel.py in <listcomp>(.0)
#     254         with parallel_backend(self._backend, n_jobs=self._n_jobs):
#     255             return [func(*args, **kwargs)
# --> 256                     for func, args, kwargs in self.items]
#     257 
#     258     def __len__(self):

# ~/anaconda3/envs/sktime/lib/python3.7/site-packages/sktime/classifiers/compose/ensemble.py in _parallel_build_trees(tree, forest, X, y, sample_weight, tree_idx, n_trees, verbose, class_weight)
#     494         fit_params = {f'{estimator}__sample_weight': curr_sample_weight,
#     495                       f'{estimator}__check_input': True}
# --> 496         tree.fit(X, y, **fit_params)
#     497 
#     498     else:

# ~/anaconda3/envs/sktime/lib/python3.7/site-packages/sklearn/pipeline.py in fit(self, X, y, **fit_params)
#     350             This estimator
#     351         """
# --> 352         Xt, fit_params = self._fit(X, y, **fit_params)
#     353         with _print_elapsed_time('Pipeline',
#     354                                  self._log_message(len(self.steps) - 1)):

# ~/anaconda3/envs/sktime/lib/python3.7/site-packages/sklearn/pipeline.py in _fit(self, X, y, **fit_params)
#     315                 message_clsname='Pipeline',
#     316                 message=self._log_message(step_idx),
# --> 317                 **fit_params_steps[name])
#     318             # Replace the transformer of the step with the fitted
#     319             # transformer. This is necessary when loading the transformer

# ~/anaconda3/envs/sktime/lib/python3.7/site-packages/joblib/memory.py in __call__(self, *args, **kwargs)
#     353 
#     354     def __call__(self, *args, **kwargs):
# --> 355         return self.func(*args, **kwargs)
#     356 
#     357     def call_and_shelve(self, *args, **kwargs):

# ~/anaconda3/envs/sktime/lib/python3.7/site-packages/sklearn/pipeline.py in _fit_transform_one(transformer, X, y, weight, message_clsname, message, **fit_params)
#     714     with _print_elapsed_time(message_clsname, message):
#     715         if hasattr(transformer, 'fit_transform'):
# --> 716             res = transformer.fit_transform(X, y, **fit_params)
#     717         else:
#     718             res = transformer.fit(X, y, **fit_params).transform(X)

# ~/anaconda3/envs/sktime/lib/python3.7/site-packages/sktime/pipeline.py in fit_transform(self, X, y, **fit_params)
#     182             delayed(_fit_transform_one)(trans, X, y, weight,
#     183                                         **fit_params)
# --> 184             for name, trans, weight in self._iter())
#     185 
#     186         if not result:

# ~/anaconda3/envs/sktime/lib/python3.7/site-packages/joblib/parallel.py in __call__(self, iterable)
#    1002             # remaining jobs.
#    1003             self._iterating = False
# -> 1004             if self.dispatch_one_batch(iterator):
#    1005                 self._iterating = self._original_iterator is not None
#    1006 

# ~/anaconda3/envs/sktime/lib/python3.7/site-packages/joblib/parallel.py in dispatch_one_batch(self, iterator)
#     833                 return False
#     834             else:
# --> 835                 self._dispatch(tasks)
#     836                 return True
#     837 

# ~/anaconda3/envs/sktime/lib/python3.7/site-packages/joblib/parallel.py in _dispatch(self, batch)
#     752         with self._lock:
#     753             job_idx = len(self._jobs)
# --> 754             job = self._backend.apply_async(batch, callback=cb)
#     755             # A job can complete so quickly than its callback is
#     756             # called before we get here, causing self._jobs to

# ~/anaconda3/envs/sktime/lib/python3.7/site-packages/joblib/_parallel_backends.py in apply_async(self, func, callback)
#     207     def apply_async(self, func, callback=None):
#     208         """Schedule a func to be run"""
# --> 209         result = ImmediateResult(func)
#     210         if callback:
#     211             callback(result)

# ~/anaconda3/envs/sktime/lib/python3.7/site-packages/joblib/_parallel_backends.py in __init__(self, batch)
#     588         # Don't delay the application, to avoid keeping the input
#     589         # arguments in memory
# --> 590         self.results = batch()
#     591 
#     592     def get(self):

# ~/anaconda3/envs/sktime/lib/python3.7/site-packages/joblib/parallel.py in __call__(self)
#     254         with parallel_backend(self._backend, n_jobs=self._n_jobs):
#     255             return [func(*args, **kwargs)
# --> 256                     for func, args, kwargs in self.items]
#     257 
#     258     def __len__(self):

# ~/anaconda3/envs/sktime/lib/python3.7/site-packages/joblib/parallel.py in <listcomp>(.0)
#     254         with parallel_backend(self._backend, n_jobs=self._n_jobs):
#     255             return [func(*args, **kwargs)
# --> 256                     for func, args, kwargs in self.items]
#     257 
#     258     def __len__(self):

# ~/anaconda3/envs/sktime/lib/python3.7/site-packages/sklearn/pipeline.py in _fit_transform_one(transformer, X, y, weight, message_clsname, message, **fit_params)
#     714     with _print_elapsed_time(message_clsname, message):
#     715         if hasattr(transformer, 'fit_transform'):
# --> 716             res = transformer.fit_transform(X, y, **fit_params)
#     717         else:
#     718             res = transformer.fit(X, y, **fit_params).transform(X)

# ~/anaconda3/envs/sktime/lib/python3.7/site-packages/sktime/transformers/base.py in fit_transform(self, X, y, **fit_params)
#      40             return self.fit(X, **fit_params).transform(X)
#      41         # fit method of arity 2 (supervised transformation)
# ---> 42         return self.fit(X, y, **fit_params).transform(X)

# ~/anaconda3/envs/sktime/lib/python3.7/site-packages/sktime/transformers/compose.py in transform(self, X, y)
#     201         """
#     202         func = self.transformer.fit_transform
# --> 203         return self._apply_rowwise(func, X, y)
#     204 
#     205     def inverse_transform(self, X, y=None):

# ~/anaconda3/envs/sktime/lib/python3.7/site-packages/sktime/transformers/compose.py in _apply_rowwise(self, func, X, y)
#     244                 for row in col:  # loop over rows in each column
#     245                     row_2d = pd.DataFrame(row)  # convert into 2d dataframe
# --> 246                     row_t = func(row_2d).ravel()  # apply transform
#     247                     rows_t.append(row_t)  # append transformed rows
#     248                 cols_t.append(rows_t)  # append transformed columns

# ~/anaconda3/envs/sktime/lib/python3.7/site-packages/sklearn/base.py in fit_transform(self, X, y, **fit_params)
#     551         if y is None:
#     552             # fit method of arity 1 (unsupervised transformation)
# --> 553             return self.fit(X, **fit_params).transform(X)
#     554         else:
#     555             # fit method of arity 2 (supervised transformation)

# ~/anaconda3/envs/sktime/lib/python3.7/site-packages/sklearn/preprocessing/_function_transformer.py in transform(self, X)
#     151             Transformed input.
#     152         """
# --> 153         return self._transform(X, func=self.func, kw_args=self.kw_args)
#     154 
#     155     def inverse_transform(self, X):

# ~/anaconda3/envs/sktime/lib/python3.7/site-packages/sklearn/preprocessing/_function_transformer.py in _transform(self, X, func, kw_args)
#     177             func = _identity
#     178 
# --> 179         return func(X, **(kw_args if kw_args else {}))
#     180 
#     181     def _more_tags(self):

# <ipython-input-5-9af4e0007a3b> in ar_coefs(x, maxlag)
#      19     nlags = np.minimum(len(x) - 1, maxlag)
#      20     model = AR(endog=x)
# ---> 21     return model.fit(maxlag=nlags).params.ravel()
#      22 
#      23 def acf_coefs(x, maxlag=100):

# ~/anaconda3/envs/sktime/lib/python3.7/site-packages/statsmodels/tsa/ar_model.py in fit(self, maxlag, method, ic, trend, transparams, start_params, solver, maxiter, full_output, disp, callback, **kwargs)
#     545         Y = endog[k_ar:, :]
#     546         # make lagged RHS
# --> 547         X = self._stackX(k_ar, trend)  # sets self.k_trend
#     548         k_trend = self.k_trend
#     549         self.exog_names = util.make_lag_names(self.endog_names, k_ar, k_trend)

# ~/anaconda3/envs/sktime/lib/python3.7/site-packages/statsmodels/tsa/ar_model.py in _stackX(self, k_ar, trend)
#     389         k_trend = util.get_trendorder(trend)
#     390         if k_trend:
# --> 391             X = add_trend(X, prepend=True, trend=trend, has_constant="raise")
#     392         self.k_trend = k_trend
#     393         return X

# ~/anaconda3/envs/sktime/lib/python3.7/site-packages/statsmodels/tsa/tsatools.py in add_trend(x, trend, prepend, has_constant)
#     106                 msg = "x contains a constant. Adding a constant with " \
#     107                       "trend='{0}' is not allowed.".format(trend)
# --> 108                 raise ValueError(msg)
#     109             elif has_constant == 'skip':
#     110                 columns = columns[1:]

# ValueError: x contains a constant. Adding a constant with trend='c' is not allowed.
```

**Expected behavior**
<!--
A clear and concise description of what you expected to happen.
-->
run without error


**Additional context**
<!--
Add any other context about the problem here.
-->

**Versions**
<details>

Linux-5.3.0-26-generic-x86_64-with-debian-buster-sid
Python 3.7.6 (default, Jan  8 2020, 19:59:22) 
[GCC 7.3.0]
NumPy 1.18.1
SciPy 1.3.2
sktime 0.3.1

<!--
Please run the following snippet and paste the output here.
import platform; print(platform.platform())
import sys; print("Python", sys.version)
import numpy; print("NumPy", numpy.__version__)
import scipy; print("SciPy", scipy.__version__)
import sktime; print("sktime", sktime.__version__)
-->

</details>

<!-- Thanks for contributing! -->



Discussion:

Resolving patch:
diff --git a/setup.py b/setup.py
--- a/setup.py
+++ b/setup.py
@@ -14,7 +14,7 @@
 import shutil
 import sys
 import traceback
-from distutils.command.clean import clean as Clean
+from distutils.command.clean import clean as Clean  # noqa
 
 from pkg_resources import parse_version
 
@@ -84,20 +84,17 @@ def find_version(*file_paths):
     'Programming Language :: Python :: 3.8'
 ]
 EXTRAS_REQUIRE = {
-    'tests': [
-        'pytest',
-        'pytest-cov',
-        'tsfresh',
-        'pmdarima'
-    ],
     'docs': [
+        'pmdarima',
+        'tsfresh',
+        'numba',
+        'matplotlib',
+        'jupyter',
         'sphinx',
         'sphinx-gallery',
-        'nbspinx',
+        'nbsphinx',
         'sphinx_rtd_theme',
         'numpydoc',
-        'matplotlib',
-        'sphinx_bootstrap_theme',
         'm2r @ git+https://github.com/crossnox/m2r@dev#egg=m2r'
     ]
 }
@@ -120,10 +117,7 @@ def find_version(*file_paths):
 
     extra_setuptools_args = dict(
         zip_safe=False,  # the package can run out of an .egg file
-        include_package_data=True,
-        extras_require={
-            'alldeps': EXTRAS_REQUIRE
-        },
+        include_package_data=True
     )
 
 else:
@@ -271,6 +265,7 @@ def setup_package():
         python_requires=">={}".format(MIN_PYTHON_VERSION),
         setup_requires=SETUP_REQUIRES,
         install_requires=INSTALL_REQUIRES,
+        extras_require=EXTRAS_REQUIRE,
         **extra_setuptools_args
     )
 


Test patch: