docs: def fit(self, X, y, step_size=0.1, init_weights=None, warm_start: bool=False):
          """Fit the weights on the given predictions.
  
          Args:
              X (array-like): Predictions of different models for the labels.
              y (array-like): Labels.
              step_size (float): Step size for optimizing the weights.
                                 Smaller step sizes most likely improve resulting score but increases training time.
              init_weights (array-like): Initial weights for training.
                                         When `warm_start` is used `init_weights` are ignored.
              warm_start (bool): Continues training. Will only work when `fit` has been called with this object earlier.
                                 When `warm_start` is used `init_weights` are ignored.
          Returns: self
          """
          assert len(np.shape(X)) == 2, 'X must be 2-dimensional, got {}-D instead.'.format(len(np.shape(X)))
          assert np.shape(X)[0] > 1, 'X must contain predictions from at least two models. ' \
                                     'Got {} instead'.format(np.shape(X)[0])
  
          assert np.shape(X)[1] == len(y), (
              'BlendingOptimizer: Length of predictions and labels does not match: '
              'preds_len={}, y_len={}'.format(np.shape(X)[1], len(y)))
  
          if warm_start:
              assert self._weights is not None, 'Optimizer has to be fitted before `warm_start` can be used.'
              weights = self._weights
          elif init_weights is None:
              weights = np.array([1.0] * len(X))
          else:
              assert (len(init_weights) == np.shape(X)[0]), (
                  'BlendingOptimizer: Number of models to blend its predictions and weights does not match: '
                  'n_models={}, weights_len={}'.format(np.shape(X)[0], len(init_weights)))
              weights = init_weights
  
          def __is_better_score(score_to_test, score):
              return score_to_test > score if self.maximize else not score_to_test > score
  
          score = 0
          best_score = self.maximize - 0.5
  
          while __is_better_score(best_score, score):
              best_score = self.metric(y, np.average(np.power(X, self._power), weights=weights, axis=0) ** (
                      1.0 / self._power))
              score = best_score
              best_index, best_step = -1, 0.0
              for j in range(len(X)):
                  delta = np.array([(0 if k != j else step_size) for k in range(len(X))])
                  s = self.metric(y, np.average(np.power(X, self._power), weights=weights + delta, axis=0) ** (
                          1.0 / self._power))
                  if __is_better_score(s, best_score):
                      best_index, best_score, best_step = j, s, step_size
                      continue
                  if weights[j] - step_size >= 0:
                      s = self.metric(y, np.average(np.power(X, self._power), weights=weights - delta, axis=0) ** (
                              1.0 / self._power))
                      if s > best_score:
                          best_index, best_score, best_step = j, s, -step_size
              if __is_better_score(best_score, score):
                  weights[best_index] += best_step
  
          self._weights = weights
          self._score = best_score
  
          return self