prompt: You will be provided with a partial code base and an issue statement explaining a problem to resolve.
  <issue>
  Lightwood.api.ensemble is not necessary
  This script is deprecated, as the ensemble module has moved to `lw.ensemble` with a base abstraction. A quick inspection of the code (ex: grep for this call) and I don't see any references. Please double check if this file is required, as I think it should be removed.
  
  The culprit link is [here](https://github.com/mindsdb/lightwood/blob/0372d292796a6d1f91ac9df9b8658ad2f128b7c9/lightwood/api/ensemble.py)
  
  </issue>
  <code>
  [start of lightwood/api/ensemble.py]
  1 from lightwood import Predictor
  2 from lightwood.constants.lightwood import ColumnDataTypes
  3 from collections import Counter
  4 import numpy as np
  5 import pickle
  6 import os
  7 
  8 
  9 class LightwoodEnsemble:
  10     def __init__(self, predictors=None, load_from_path=None):
  11         self.path_list = None
  12         if load_from_path is not None:
  13             with open(os.path.join(load_from_path, 'lightwood_data'), 'rb') as pickle_in:
  14                 obj = pickle.load(pickle_in)
  15                 self.path = load_from_path
  16                 self.path_list = obj.path_list
  17                 self.ensemble = [Predictor(load_from_path=path) for path in self.path_list]
  18         elif isinstance(predictors, Predictor):
  19             self.ensemble = [predictors]
  20         elif isinstance(predictors, list):
  21             self.ensemble = predictors
  22 
  23     def append(self, predictor):
  24         if isinstance(self.ensemble, list):
  25             self.ensemble.append(predictor)
  26         else:
  27             self.ensemble = [predictor]
  28 
  29     def __iter__(self):
  30         yield self.ensemble
  31 
  32     def predict(self, when_data):
  33         predictions = [p.predict(when_data=when_data) for p in self.ensemble]
  34         formatted_predictions = {}
  35         for target in self.ensemble[0].config['output_features']:
  36             target_name = target['name']
  37             formatted_predictions[target_name] = {}
  38             pred_arr = np.array([p[target_name]['predictions'] for p in predictions])
  39             if target['type'] == ColumnDataTypes.NUMERIC:
  40                 final_preds = np.mean(pred_arr, axis=0).tolist()
  41             elif target['type'] == ColumnDataTypes.CATEGORICAL:
  42                 final_preds = [max(Counter(pred_arr[:, idx])) for idx in range(pred_arr.shape[1])]
  43 
  44                 # @TODO: implement class distribution for ensembles
  45                 # NOTE: label set *could* grow when adding predictors, which complicates belief score computation
  46                 formatted_predictions[target_name]['class_distribution'] = np.ones(shape=(len(final_preds), 1))
  47             else:
  48                 raise Exception('Only numeric and categorical datatypes are supported for ensembles')
  49 
  50             formatted_predictions[target_name]['predictions'] = final_preds
  51 
  52         return formatted_predictions
  53 
  54     def save(self, path_to):
  55         # TODO: potentially save predictors inside ensemble pickle, though there's the issue of nonpersistent stuff with torch.save() # noqa
  56         path_list = []
  57         for i, model in enumerate(self.ensemble):
  58             path = os.path.join(path_to, f'lightwood_predictor_{i}')
  59             path_list.append(path)
  60             model.save(path_to=path)
  61 
  62         self.path_list = path_list
  63 
  64         # TODO: in the future, save preds inside this data struct
  65         self.ensemble = None  # we deref predictors for now
  66         with open(os.path.join(path_to, 'lightwood_data'), 'wb') as file:
  67             pickle.dump(self, file, pickle.HIGHEST_PROTOCOL)
  68
  [end of lightwood/api/ensemble.py]
  </code>
  
  I need you to solve this issue by generating a single patch file that I can apply directly to this repository using git apply. Please respond with a single patch file in the following format.
  <patch>
  diff --git a/file.py b/file.py
  --- a/file.py
  +++ b/file.py
  @@ -1,27 +1,35 @@
   def euclidean(a, b):
  -    while b:
  -        a, b = b, a % b
  -    return a
  +    if b == 0:
  +        return a
  +    return euclidean(b, a % b)
   
   
   def bresenham(x0, y0, x1, y1):
       points = []
       dx = abs(x1 - x0)
       dy = abs(y1 - y0)
  -    sx = 1 if x0 < x1 else -1
  -    sy = 1 if y0 < y1 else -1
  -    err = dx - dy
  +    x, y = x0, y0
  +    sx = -1 if x0 > x1 else 1
  +    sy = -1 if y0 > y1 else 1
   
  -    while True:
  -        points.append((x0, y0))
  -        if x0 == x1 and y0 == y1:
  -            break
  -        e2 = 2 * err
  -        if e2 > -dy:
  -            err -= dy
  -            x0 += sx
  -        if e2 < dx:
  -            err += dx
  -            y0 += sy
  +    if dx > dy:
  +        err = dx / 2.0
  +        while x != x1:
  +            points.append((x, y))
  +            err -= dy
  +            if err < 0:
  +                y += sy
  +                err += dx
  +            x += sx
  +    else:
  +        err = dy / 2.0
  +        while y != y1:
  +            points.append((x, y))
  +            err -= dx
  +            if err < 0:
  +                x += sx
  +                err += dy
  +            y += sy
  +
  +    points.append((x, y))
       return points
  
  </patch>
golden_diff: diff --git a/lightwood/api/ensemble.py b/lightwood/api/ensemble.py
  deleted file mode 100644
  --- a/lightwood/api/ensemble.py
  +++ /dev/null
  @@ -1,67 +0,0 @@
  -from lightwood import Predictor
  -from lightwood.constants.lightwood import ColumnDataTypes
  -from collections import Counter
  -import numpy as np
  -import pickle
  -import os
  -
  -
  -class LightwoodEnsemble:
  -    def __init__(self, predictors=None, load_from_path=None):
  -        self.path_list = None
  -        if load_from_path is not None:
  -            with open(os.path.join(load_from_path, 'lightwood_data'), 'rb') as pickle_in:
  -                obj = pickle.load(pickle_in)
  -                self.path = load_from_path
  -                self.path_list = obj.path_list
  -                self.ensemble = [Predictor(load_from_path=path) for path in self.path_list]
  -        elif isinstance(predictors, Predictor):
  -            self.ensemble = [predictors]
  -        elif isinstance(predictors, list):
  -            self.ensemble = predictors
  -
  -    def append(self, predictor):
  -        if isinstance(self.ensemble, list):
  -            self.ensemble.append(predictor)
  -        else:
  -            self.ensemble = [predictor]
  -
  -    def __iter__(self):
  -        yield self.ensemble
  -
  -    def predict(self, when_data):
  -        predictions = [p.predict(when_data=when_data) for p in self.ensemble]
  -        formatted_predictions = {}
  -        for target in self.ensemble[0].config['output_features']:
  -            target_name = target['name']
  -            formatted_predictions[target_name] = {}
  -            pred_arr = np.array([p[target_name]['predictions'] for p in predictions])
  -            if target['type'] == ColumnDataTypes.NUMERIC:
  -                final_preds = np.mean(pred_arr, axis=0).tolist()
  -            elif target['type'] == ColumnDataTypes.CATEGORICAL:
  -                final_preds = [max(Counter(pred_arr[:, idx])) for idx in range(pred_arr.shape[1])]
  -
  -                # @TODO: implement class distribution for ensembles
  -                # NOTE: label set *could* grow when adding predictors, which complicates belief score computation
  -                formatted_predictions[target_name]['class_distribution'] = np.ones(shape=(len(final_preds), 1))
  -            else:
  -                raise Exception('Only numeric and categorical datatypes are supported for ensembles')
  -
  -            formatted_predictions[target_name]['predictions'] = final_preds
  -
  -        return formatted_predictions
  -
  -    def save(self, path_to):
  -        # TODO: potentially save predictors inside ensemble pickle, though there's the issue of nonpersistent stuff with torch.save() # noqa
  -        path_list = []
  -        for i, model in enumerate(self.ensemble):
  -            path = os.path.join(path_to, f'lightwood_predictor_{i}')
  -            path_list.append(path)
  -            model.save(path_to=path)
  -
  -        self.path_list = path_list
  -
  -        # TODO: in the future, save preds inside this data struct
  -        self.ensemble = None  # we deref predictors for now
  -        with open(os.path.join(path_to, 'lightwood_data'), 'wb') as file:
  -            pickle.dump(self, file, pickle.HIGHEST_PROTOCOL)
  
verification_info: {"golden_diff": "diff --git a/lightwood/api/ensemble.py b/lightwood/api/ensemble.py\ndeleted file mode 100644\n--- a/lightwood/api/ensemble.py\n+++ /dev/null\n@@ -1,67 +0,0 @@\n-from lightwood import Predictor\n-from lightwood.constants.lightwood import ColumnDataTypes\n-from collections import Counter\n-import numpy as np\n-import pickle\n-import os\n-\n-\n-class LightwoodEnsemble:\n-    def __init__(self, predictors=None, load_from_path=None):\n-        self.path_list = None\n-        if load_from_path is not None:\n-            with open(os.path.join(load_from_path, 'lightwood_data'), 'rb') as pickle_in:\n-                obj = pickle.load(pickle_in)\n-                self.path = load_from_path\n-                self.path_list = obj.path_list\n-                self.ensemble = [Predictor(load_from_path=path) for path in self.path_list]\n-        elif isinstance(predictors, Predictor):\n-            self.ensemble = [predictors]\n-        elif isinstance(predictors, list):\n-            self.ensemble = predictors\n-\n-    def append(self, predictor):\n-        if isinstance(self.ensemble, list):\n-            self.ensemble.append(predictor)\n-        else:\n-            self.ensemble = [predictor]\n-\n-    def __iter__(self):\n-        yield self.ensemble\n-\n-    def predict(self, when_data):\n-        predictions = [p.predict(when_data=when_data) for p in self.ensemble]\n-        formatted_predictions = {}\n-        for target in self.ensemble[0].config['output_features']:\n-            target_name = target['name']\n-            formatted_predictions[target_name] = {}\n-            pred_arr = np.array([p[target_name]['predictions'] for p in predictions])\n-            if target['type'] == ColumnDataTypes.NUMERIC:\n-                final_preds = np.mean(pred_arr, axis=0).tolist()\n-            elif target['type'] == ColumnDataTypes.CATEGORICAL:\n-                final_preds = [max(Counter(pred_arr[:, idx])) for idx in range(pred_arr.shape[1])]\n-\n-                # @TODO: implement class distribution for ensembles\n-                # NOTE: label set *could* grow when adding predictors, which complicates belief score computation\n-                formatted_predictions[target_name]['class_distribution'] = np.ones(shape=(len(final_preds), 1))\n-            else:\n-                raise Exception('Only numeric and categorical datatypes are supported for ensembles')\n-\n-            formatted_predictions[target_name]['predictions'] = final_preds\n-\n-        return formatted_predictions\n-\n-    def save(self, path_to):\n-        # TODO: potentially save predictors inside ensemble pickle, though there's the issue of nonpersistent stuff with torch.save() # noqa\n-        path_list = []\n-        for i, model in enumerate(self.ensemble):\n-            path = os.path.join(path_to, f'lightwood_predictor_{i}')\n-            path_list.append(path)\n-            model.save(path_to=path)\n-\n-        self.path_list = path_list\n-\n-        # TODO: in the future, save preds inside this data struct\n-        self.ensemble = None  # we deref predictors for now\n-        with open(os.path.join(path_to, 'lightwood_data'), 'wb') as file:\n-            pickle.dump(self, file, pickle.HIGHEST_PROTOCOL)\n", "issue": "Lightwood.api.ensemble is not necessary\nThis script is deprecated, as the ensemble module has moved to `lw.ensemble` with a base abstraction. A quick inspection of the code (ex: grep for this call) and I don't see any references. Please double check if this file is required, as I think it should be removed.\r\n\r\nThe culprit link is [here](https://github.com/mindsdb/lightwood/blob/0372d292796a6d1f91ac9df9b8658ad2f128b7c9/lightwood/api/ensemble.py)\n", "before_files": [{"content": "from lightwood import Predictor\nfrom lightwood.constants.lightwood import ColumnDataTypes\nfrom collections import Counter\nimport numpy as np\nimport pickle\nimport os\n\n\nclass LightwoodEnsemble:\n    def __init__(self, predictors=None, load_from_path=None):\n        self.path_list = None\n        if load_from_path is not None:\n            with open(os.path.join(load_from_path, 'lightwood_data'), 'rb') as pickle_in:\n                obj = pickle.load(pickle_in)\n                self.path = load_from_path\n                self.path_list = obj.path_list\n                self.ensemble = [Predictor(load_from_path=path) for path in self.path_list]\n        elif isinstance(predictors, Predictor):\n            self.ensemble = [predictors]\n        elif isinstance(predictors, list):\n            self.ensemble = predictors\n\n    def append(self, predictor):\n        if isinstance(self.ensemble, list):\n            self.ensemble.append(predictor)\n        else:\n            self.ensemble = [predictor]\n\n    def __iter__(self):\n        yield self.ensemble\n\n    def predict(self, when_data):\n        predictions = [p.predict(when_data=when_data) for p in self.ensemble]\n        formatted_predictions = {}\n        for target in self.ensemble[0].config['output_features']:\n            target_name = target['name']\n            formatted_predictions[target_name] = {}\n            pred_arr = np.array([p[target_name]['predictions'] for p in predictions])\n            if target['type'] == ColumnDataTypes.NUMERIC:\n                final_preds = np.mean(pred_arr, axis=0).tolist()\n            elif target['type'] == ColumnDataTypes.CATEGORICAL:\n                final_preds = [max(Counter(pred_arr[:, idx])) for idx in range(pred_arr.shape[1])]\n\n                # @TODO: implement class distribution for ensembles\n                # NOTE: label set *could* grow when adding predictors, which complicates belief score computation\n                formatted_predictions[target_name]['class_distribution'] = np.ones(shape=(len(final_preds), 1))\n            else:\n                raise Exception('Only numeric and categorical datatypes are supported for ensembles')\n\n            formatted_predictions[target_name]['predictions'] = final_preds\n\n        return formatted_predictions\n\n    def save(self, path_to):\n        # TODO: potentially save predictors inside ensemble pickle, though there's the issue of nonpersistent stuff with torch.save() # noqa\n        path_list = []\n        for i, model in enumerate(self.ensemble):\n            path = os.path.join(path_to, f'lightwood_predictor_{i}')\n            path_list.append(path)\n            model.save(path_to=path)\n\n        self.path_list = path_list\n\n        # TODO: in the future, save preds inside this data struct\n        self.ensemble = None  # we deref predictors for now\n        with open(os.path.join(path_to, 'lightwood_data'), 'wb') as file:\n            pickle.dump(self, file, pickle.HIGHEST_PROTOCOL)\n", "path": "lightwood/api/ensemble.py"}]}