<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def gridsearch(self, X, y, exposure=None, weights=None, return_scores=False, keep_best=True, objective='auto', **param_grids):
 """ performs a grid search over a space of parameters for a given objective NOTE: gridsearch method is lazy and will not remove useless combinations from the search space, eg. will result in 10 loops, of which 5 are equivalent because even though fit_splines==False it is not recommended to search over a grid that alternates between known scales and unknown scales, as the scores of the candidate models will not be comparable. Parameters X : array input data of shape (n_samples, m_features) y : array label data of shape (n_samples,) exposure : array-like shape (n_samples,) or None, default: None containing exposures if None, defaults to array of ones weights : array-like shape (n_samples,) or None, default: None containing sample weights if None, defaults to array of ones return_scores : boolean, default False whether to return the hyperpamaters and score for each element in the grid keep_best : boolean whether to keep the best GAM as self. default: True objective : string, default: 'auto' metric to optimize. must be in ['AIC', 'AICc', 'GCV', 'UBRE', 'auto'] if 'auto', then grid search will optimize GCV for models with unknown scale and UBRE for models with known scale. **kwargs : dict, default {'lam': np.logspace(-3, 3, 11)} pairs of parameters and iterables of floats, or parameters and iterables of iterables of floats. if iterable of iterables of floats, the outer iterable must have length m_features. the method will make a grid of all the combinations of the parameters and fit a GAM to each combination. Returns ------- if return_values == True: model_scores : dict Contains each fitted model as keys and corresponding objective scores as values else: self, ie possibly the newly fitted model """

        y, weights = self._exposure_to_weights(y, exposure, weights)
        return super(PoissonGAM, self).gridsearch(X, y,
                                                  weights=weights,
                                                  return_scores=return_scores,
                                                  keep_best=keep_best,
                                                  objective=objective,
                                                  **param_grids)