Fit the generalized additive model.

        Parameters
        ----------
        X : array-like, shape (n_samples, m_features)
            Training vectors.
        y : array-like, shape (n_samples,)
            Target values,
            ie integers in classification, real numbers in
            regression)
        weights : array-like shape (n_samples,) or None, optional
            Sample weights.
            if None, defaults to array of ones

        Returns
        -------
        self : object
            Returns fitted GAM object

def fit(self, X, y, weights=None):
        """Fit the generalized additive model.

        Parameters
        ----------
        X : array-like, shape (n_samples, m_features)
            Training vectors.
        y : array-like, shape (n_samples,)
            Target values,
            ie integers in classification, real numbers in
            regression)
        weights : array-like shape (n_samples,) or None, optional
            Sample weights.
            if None, defaults to array of ones

        Returns
        -------
        self : object
            Returns fitted GAM object
        """

        # validate parameters
        self._validate_params()

        # validate data
        y = check_y(y, self.link, self.distribution, verbose=self.verbose)
        X = check_X(X, verbose=self.verbose)
        check_X_y(X, y)

        if weights is not None:
            weights = np.array(weights).astype('f').ravel()
            weights = check_array(weights, name='sample weights',
                                  ndim=1, verbose=self.verbose)
            check_lengths(y, weights)
        else:
            weights = np.ones_like(y).astype('float64')

        # validate data-dependent parameters
        self._validate_data_dep_params(X)

        # set up logging
        if not hasattr(self, 'logs_'):
            self.logs_ = defaultdict(list)

        # begin capturing statistics
        self.statistics_ = {}
        self.statistics_['n_samples'] = len(y)
        self.statistics_['m_features'] = X.shape[1]

        # optimize
        self._pirls(X, y, weights)
        # if self._opt == 0:
        #     self._pirls(X, y, weights)
        # if self._opt == 1:
        #     self._pirls_naive(X, y)
        return self