Skip to content

Commit 66c1e9b

Browse files
committed
Extending LocalModel class to handle Time Series too
1 parent 4499ff9 commit 66c1e9b

File tree

11 files changed

+74
-20
lines changed

11 files changed

+74
-20
lines changed

HISTORY.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,12 @@
33
History
44
-------
55

6+
9.4.0 (2023-06-14)
7+
------------------
8+
9+
- Extending LocalModel class to handle Time Series locally.
10+
11+
612
9.3.0 (2023-06-09)
713
------------------
814

bigml/bigmlconnection.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -765,10 +765,6 @@ def _download(self, url, filename=None, wait_time=10, retries=10,
765765
return file_object
766766
try:
767767
code = response.status_code
768-
print("*** response headers ****", response.headers)
769-
print("***")
770-
print("*** request ")
771-
print(response.request.__dict__)
772768
if code == HTTP_OK:
773769
# starting the dataset export procedure
774770
if response.headers.get("content-type") == JSON_TYPE:

bigml/cluster.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -648,12 +648,12 @@ def summarize(self, out=sys.stdout):
648648

649649
def predict(self, input_data, full=False):
650650
"""Method to homogeneize the local models interface for all BigML
651-
models. It returns the centroid method result. The full parameter has
652-
no effect in this case because the original centroid information is
653-
already a complete dictionary. Is kept to mimic the interface of the
654-
general method.
651+
models. It returns the centroid method result.
655652
"""
656-
return self.centroid(input_data)
653+
centroid = self.centroid(input_data)
654+
if not full:
655+
return {"centroid_name": centroid["name"]}
656+
return centroid
657657

658658
def batch_predict(self, input_data_list, outputs=None, **kwargs):
659659
"""Creates a batch centroid for a list of inputs using the local

bigml/deepnet.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,7 @@ def __init__(self, deepnet, api=None, cache_get=None,
213213
else:
214214
settings = None
215215

216+
#pylint: disable=locally-disabled,broad-except
216217
if not self.using_laminar:
217218
try:
218219
self.deepnet = create_model(deepnet,

bigml/local_model.py

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
from bigml.cluster import Cluster
5858
from bigml.anomaly import Anomaly
5959
from bigml.association import Association
60+
from bigml.timeseries import TimeSeries
6061
try:
6162
from bigml.topicmodel import TopicModel
6263
TOPIC_ENABLED = True
@@ -83,9 +84,11 @@
8384
"cluster": Cluster,
8485
"anomaly": Anomaly,
8586
"association": Association,
86-
"topicmodel": TopicModel,
87-
"pca": PCA}
87+
"pca": PCA,
88+
"timeseries": TimeSeries}
8889
MODEL_CLASSES.update(SUPERVISED_CLASSES)
90+
if TOPIC_ENABLED:
91+
MODEL_CLASSES.update({"topicmodel": TopicModel})
8992

9093

9194
def extract_id(model, api):
@@ -139,7 +142,7 @@ def extract_id(model, api):
139142
class LocalModel(BaseModel):
140143
""" A lightweight wrapper around any BigML model.
141144
142-
Uses any BigML remote supervised model to build a local version
145+
Uses any BigML remote model to build a local version
143146
that can be used to generate predictions locally.
144147
145148
"""
@@ -179,7 +182,7 @@ def data_transformations(self):
179182

180183
def batch_predict(self, input_data_list, outputs=None, **kwargs):
181184
"""Creates a batch prediction for a list of inputs using the local
182-
supervised model. Allows to define some output settings to
185+
BigML model. Allows to define some output settings to
183186
decide the fields to be added to the input_data (prediction,
184187
probability, etc.) and the name that we want to assign to these new
185188
fields. The outputs argument accepts a dictionary with keys
@@ -196,8 +199,9 @@ def batch_predict(self, input_data_list, outputs=None, **kwargs):
196199
:rtype: list or Panda's dataframe depending on the input type in
197200
input_data_list
198201
"""
199-
if isinstance(self.local_model, Association):
200-
raise("The method is not available for Associations.")
202+
if isinstance(self.local_model, (Association, TimeSeries)):
203+
raise ValueError("The method is not available for Associations or "
204+
"TimeSeries.")
201205
if self.supervised:
202206
if outputs is None:
203207
outputs = {}
@@ -220,9 +224,8 @@ def batch_predict(self, input_data_list, outputs=None, **kwargs):
220224
if data_format != INTERNAL:
221225
return format_data(inner_data_list, out_format=data_format)
222226
return inner_data_list
223-
else:
224-
return self.local_model.batch_predict(input_data_list,
225-
outputs=outputs, **kwargs)
227+
return self.local_model.batch_predict(input_data_list,
228+
outputs=outputs, **kwargs)
226229

227230
#pylint: disable=locally-disabled,arguments-differ
228231
def dump(self, **kwargs):

bigml/tests/compare_predictions_steps.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,8 @@ def i_create_a_local_bigml_model_prediction(step, data=None,
140140

141141
def the_local_bigml_prediction_is(step, value, prediction_type=None, key=None,
142142
precision=None):
143+
"""Step: the local BigML model prediction is
144+
"""
143145
prediction = step.bigml["local_%s" % prediction_type]
144146
if key is not None:
145147
prediction = prediction[key]

bigml/tests/test_34_time_series.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,15 @@
2020
""" Creating time series forecasts
2121
2222
"""
23+
import json
24+
2325
from .world import world, setup_module, teardown_module, show_doc, \
2426
show_method
2527
from . import create_source_steps as source_create
2628
from . import create_dataset_steps as dataset_create
2729
from . import create_time_series_steps as time_series_create
2830
from . import create_forecast_steps as forecast_create
31+
from . import compare_predictions_steps as prediction_compare
2932

3033

3134
class TestTimeSeries:
@@ -91,3 +94,10 @@ def test_scenario1(self):
9194
forecast_create.i_create_a_forecast(
9295
self, example["input_data"])
9396
forecast_create.the_forecast_is(self, example["forecast_points"])
97+
prediction_compare.i_create_a_local_bigml_model(self,
98+
model_type="time_series")
99+
prediction_compare.i_create_a_local_bigml_model_prediction(
100+
self, example["input_data"], prediction_type="forecast")
101+
forecast_points = json.loads(example["forecast_points"])
102+
prediction_compare.the_local_bigml_prediction_is(
103+
self, {"forecast": forecast_points}, prediction_type="forecast")

bigml/tests/world.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,17 @@ def flatten_shared():
124124
return ids_list
125125

126126

127+
def sort_dict(item):
128+
"""
129+
Sort nested dict
130+
"""
131+
if isinstance(item, list):
132+
return [sort_dict(v) for v in item]
133+
if not isinstance(item, dict):
134+
return item
135+
return {k: sort_dict(v) for k, v in sorted(item.items())}
136+
137+
127138
def eq_(*args, msg=None, precision=None):
128139
"""Wrapper to assert. If precision is set, previous rounding"""
129140
new_args = list(args)
@@ -133,15 +144,26 @@ def eq_(*args, msg=None, precision=None):
133144
new_args[index] = list(dict(sorted(arg.items())).values())
134145
if precision is not None:
135146
if isinstance(new_args[0], list):
147+
if msg is None:
148+
msg = "Comparing: %s" % new_args
136149
assert all(len(new_args[0]) == len(b) for b in new_args[1:]), msg
137150
pairs = zip(new_args[0], new_args[1])
151+
if msg is None:
152+
msg = "Comparing: %s" % new_args
138153
assert all(float_round(a, precision) == float_round(b, precision)
139154
for a, b in pairs), msg
140155
else:
141156
for index, arg in enumerate(new_args):
142157
new_args[index] = float_round(arg, precision)
158+
if msg is None:
159+
msg = "Comparing: %s" % new_args
143160
assert all(new_args[0] == b for b in new_args[1:]), msg
144161
else:
162+
if isinstance(new_args[0], (dict, list)):
163+
for index, arg in enumerate(new_args):
164+
new_args[index] = sort_dict(new_args[index])
165+
if msg is None:
166+
msg = "expected: %s, got: %s" % (new_args[0], new_args[1])
145167
assert new_args[0] == new_args[1], msg
146168

147169

bigml/timeseries.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
from bigml.util import utf8, use_cache, load
5050
from bigml.basemodel import get_resource_dict, extract_objective
5151
from bigml.modelfields import ModelFields
52+
from bigml.constants import DECIMALS
5253
from bigml.tssubmodels import SUBMODELS
5354
from bigml.tsoutconstants import SUBMODELS_CODE, TRIVIAL_MODEL, \
5455
SEASONAL_CODE, FORECAST_FUNCTION, USAGE_DOC
@@ -78,7 +79,8 @@ def compute_forecasts(submodels, horizon):
7879

7980
forecasts.append( \
8081
{"model": name,
81-
"point_forecast": SUBMODELS[trend](*args)})
82+
"point_forecast": [round(value, DECIMALS) for value in
83+
SUBMODELS[trend](*args)]})
8284
return forecasts
8385

8486

@@ -258,6 +260,15 @@ def forecast(self, input_data=None):
258260

259261
return forecasts
260262

263+
def predict(self, input_data, full=False):
264+
"""Method to homogeneize the local models interface for all BigML
265+
models. It returns the forecast method result.
266+
"""
267+
forecast = self.forecast(input_data)
268+
if full:
269+
return {"forecast": forecast}
270+
return forecast
271+
261272
def filter_objectives(self, input_data,
262273
full=False):
263274
"""Filters the keys given in input_data checking against the

bigml/topicmodel.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,9 @@ def infer(self, list_of_indices):
401401
for k in range(self.ntopics)]
402402

403403
def predict(self, input_data, full=False):
404+
"""Method to homogeneize the local models interface for all BigML
405+
models. It returns the distribution method result.
406+
"""
404407
distribution = self.distribution(input_data)
405408
if full:
406409
return distribution_to_dict(distribution)

0 commit comments

Comments
 (0)