Skip to content

Commit 92e65e9

Browse files
New estimators and interval dilation (#10)
* new estimators and interval dilation * exclude install for scikit-fda py version
1 parent d3ab235 commit 92e65e9

26 files changed

+959
-82
lines changed

pyproject.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ extras = [
4848
"pyfftw>=0.12.0,<0.14.0",
4949
"statsmodels>=0.12.1,<0.14.0",
5050
"wildboar>=1.1.0,<1.2.0",
51+
"scikit-fda>=0.7.0,<0.9.0 ; python_version <= '3.10'",
52+
"stumpy>=1.6.0,<1.12.0"
5153
]
5254
unstable_extras = [
5355
"mrsqm>=0.0.1,<0.1.0 ; platform_system == 'Darwin'", # requires gcc and fftw to be installed for Windows and some other OS (see http://www.fftw.org/index.html)

tsml/distance_based/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33

44
__all__ = [
55
"ProximityForestClassifier",
6+
"MPDistClassifier",
67
]
78

9+
from tsml.distance_based._mpdist import MPDistClassifier
810
from tsml.distance_based._pf import ProximityForestClassifier

tsml/distance_based/_mpdist.py

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
# -*- coding: utf-8 -*-
2+
""""""
3+
4+
__author__ = ["TonyBagnall", "patrickzib", "MatthewMiddlehurst"]
5+
__all__ = ["MPDistClassifier"]
6+
7+
import numpy as np
8+
import stumpy
9+
from sklearn.base import ClassifierMixin
10+
from sklearn.metrics import pairwise
11+
from sklearn.utils.multiclass import check_classification_targets
12+
from sklearn.utils.validation import check_is_fitted
13+
14+
from tsml.base import BaseTimeSeriesEstimator
15+
from tsml.utils.validation import check_n_jobs
16+
17+
18+
class MPDistClassifier(ClassifierMixin, BaseTimeSeriesEstimator):
19+
"""MPDist 1-NN classifier-adaptor."""
20+
21+
def __init__(self, window=10, n_jobs=1):
22+
self.window = window
23+
self.n_jobs = n_jobs
24+
25+
super(MPDistClassifier, self).__init__()
26+
27+
def fit(self, X, y):
28+
X, y = self._validate_data(X=X, y=y, ensure_min_samples=2)
29+
X = self._convert_X(X)
30+
31+
check_classification_targets(y)
32+
33+
self.n_instances_, self.series_length_ = X.shape
34+
self.classes_ = np.unique(y)
35+
self.n_classes_ = self.classes_.shape[0]
36+
self.class_dictionary_ = {}
37+
for index, class_val in enumerate(self.classes_):
38+
self.class_dictionary_[class_val] = index
39+
40+
if self.n_classes_ == 1:
41+
return self
42+
43+
self._n_jobs = check_n_jobs(self.n_jobs)
44+
45+
self._X_train = X.astype(np.float64)
46+
self._y_train = y
47+
48+
return self
49+
50+
def predict(self, X) -> np.ndarray:
51+
check_is_fitted(self)
52+
53+
# treat case of single class seen in fit
54+
if self.n_classes_ == 1:
55+
return np.repeat(list(self.class_dictionary_.keys()), X.shape[0], axis=0)
56+
57+
X = self._validate_data(X=X, reset=False)
58+
X = self._convert_X(X)
59+
60+
window = (
61+
self.window if self.window >= 1 else int(self.window * self.series_length_)
62+
)
63+
64+
distance_matrix = pairwise.pairwise_distances(
65+
X.astype(np.float64),
66+
self._X_train,
67+
metric=(lambda x, y: stumpy.mpdist(x, y, window)),
68+
n_jobs=self._n_jobs,
69+
)
70+
71+
return self._y_train[np.argmin(distance_matrix, axis=1)]
72+
73+
def _more_tags(self):
74+
return {
75+
"X_types": ["2darray"],
76+
"optional_dependency": True,
77+
}
78+
79+
@classmethod
80+
def get_test_params(cls, parameter_set="default"):
81+
"""Return testing parameter settings for the estimator.
82+
83+
Parameters
84+
----------
85+
parameter_set : str, default="default"
86+
Name of the set of test parameters to return, for use in tests. If no
87+
special parameters are defined for a value, will return `"default"` set.
88+
For classifiers, a "default" set of parameters should be provided for
89+
general testing, and a "results_comparison" set for comparing against
90+
previously recorded results if the general set does not produce suitable
91+
probabilities to compare against.
92+
93+
Returns
94+
-------
95+
params : dict or list of dict, default={}
96+
Parameters to create testing instances of the class.
97+
Each dict are parameters to construct an "interesting" test instance, i.e.,
98+
`MyClass(**params)` or `MyClass(**params[i])` creates a valid test instance.
99+
`create_test_instance` uses the first (or only) dictionary in `params`.
100+
"""
101+
102+
return {
103+
"window": 0.8,
104+
}

tsml/distance_based/_pf.py

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -20,33 +20,29 @@ def __init__(
2020
pivot_sample="label",
2121
metric_sample="weighted",
2222
metric_factories="default",
23-
oob_score=False,
2423
max_depth=None,
2524
min_samples_split=2,
2625
min_samples_leaf=1,
2726
min_impurity_decrease=0,
2827
criterion="entropy",
2928
bootstrap=True,
30-
warm_start=False,
29+
oob_score=False,
3130
n_jobs=None,
32-
class_weight=None,
3331
random_state=None,
3432
):
3533
self.n_estimators = n_estimators
3634
self.n_pivot = n_pivot
3735
self.pivot_sample = pivot_sample
3836
self.metric_sample = metric_sample
3937
self.metric_factories = metric_factories
40-
self.oob_score = oob_score
4138
self.max_depth = max_depth
4239
self.min_samples_split = min_samples_split
4340
self.min_samples_leaf = min_samples_leaf
4441
self.min_impurity_decrease = min_impurity_decrease
4542
self.criterion = criterion
4643
self.bootstrap = bootstrap
47-
self.warm_start = warm_start
44+
self.oob_score = oob_score
4845
self.n_jobs = n_jobs
49-
self.class_weight = class_weight
5046
self.random_state = random_state
5147

5248
_check_optional_dependency("wildboar", "wildboar", self)
@@ -65,8 +61,8 @@ def fit(self, X, y):
6561
self.classes_ = np.unique(y)
6662
self.n_classes_ = self.classes_.shape[0]
6763
self.class_dictionary_ = {}
68-
for index, classVal in enumerate(self.classes_):
69-
self.class_dictionary_[classVal] = index
64+
for index, class_val in enumerate(self.classes_):
65+
self.class_dictionary_[class_val] = index
7066

7167
if self.n_classes_ == 1:
7268
return self
@@ -91,9 +87,7 @@ def fit(self, X, y):
9187
min_impurity_decrease=self.min_impurity_decrease,
9288
criterion=self.criterion,
9389
bootstrap=self.bootstrap,
94-
warm_start=self.warm_start,
9590
n_jobs=self.n_jobs,
96-
class_weight=self.class_weight,
9791
random_state=self.random_state,
9892
)
9993
self.clf_.fit(X, y)
@@ -115,7 +109,7 @@ def predict(self, X) -> np.ndarray:
115109

116110
return self.clf_.predict(X)
117111

118-
def _predict_proba(self, X) -> np.ndarray:
112+
def predict_proba(self, X) -> np.ndarray:
119113
check_is_fitted(self)
120114

121115
# treat case of single class seen in fit
@@ -129,3 +123,30 @@ def _predict_proba(self, X) -> np.ndarray:
129123
X = np.reshape(X, (X.shape[0], X.shape[2]))
130124

131125
return self.clf_.predict_proba(X)
126+
127+
@classmethod
128+
def get_test_params(cls, parameter_set="default"):
129+
"""Return testing parameter settings for the estimator.
130+
131+
Parameters
132+
----------
133+
parameter_set : str, default="default"
134+
Name of the set of test parameters to return, for use in tests. If no
135+
special parameters are defined for a value, will return `"default"` set.
136+
For classifiers, a "default" set of parameters should be provided for
137+
general testing, and a "results_comparison" set for comparing against
138+
previously recorded results if the general set does not produce suitable
139+
probabilities to compare against.
140+
141+
Returns
142+
-------
143+
params : dict or list of dict, default={}
144+
Parameters to create testing instances of the class.
145+
Each dict are parameters to construct an "interesting" test instance, i.e.,
146+
`MyClass(**params)` or `MyClass(**params[i])` creates a valid test instance.
147+
`create_test_instance` uses the first (or only) dictionary in `params`.
148+
"""
149+
150+
return {
151+
"n_estimators": 2,
152+
}

tsml/dummy/_dummy.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,8 +107,8 @@ def fit(self, X, y):
107107
if self.validate:
108108
self.n_classes_ = self.classes_.shape[0]
109109
self.class_dictionary_ = {}
110-
for index, classVal in enumerate(self.classes_):
111-
self.class_dictionary_[classVal] = index
110+
for index, class_val in enumerate(self.classes_):
111+
self.class_dictionary_[class_val] = index
112112

113113
if self.n_classes_ == 1:
114114
return self

tsml/feature_based/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44
__all__ = [
55
"Catch22Classifier",
66
"Catch22Regressor",
7+
"FPCAClassifier",
8+
"FPCARegressor",
79
]
810

911
from tsml.feature_based._catch22 import Catch22Classifier, Catch22Regressor
12+
from tsml.feature_based._fpca import FPCAClassifier, FPCARegressor

tsml/feature_based/_catch22.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -137,9 +137,7 @@ def fit(self, X, y):
137137
Changes state by creating a fitted model that updates attributes
138138
ending in "_" and sets is_fitted flag to True.
139139
"""
140-
X, y = self._validate_data(
141-
X=X, y=y, ensure_min_samples=2, ensure_min_series_length=3
142-
)
140+
X, y = self._validate_data(X=X, y=y, ensure_min_samples=2)
143141
X = self._convert_X(X)
144142

145143
check_classification_targets(y)
@@ -148,8 +146,8 @@ def fit(self, X, y):
148146
self.classes_ = np.unique(y)
149147
self.n_classes_ = self.classes_.shape[0]
150148
self.class_dictionary_ = {}
151-
for index, classVal in enumerate(self.classes_):
152-
self.class_dictionary_[classVal] = index
149+
for index, class_val in enumerate(self.classes_):
150+
self.class_dictionary_[class_val] = index
153151

154152
if self.n_classes_ == 1:
155153
return self

0 commit comments

Comments
 (0)