code: def _estimate_r2(self, X=None, y=None, mu=None, weights=None):
          
          if mu is None:
              mu = self.predict_mu(X=X)
  
          if weights is None:
              weights = np.ones_like(y).astype('float64')
  
          null_mu = y.mean() * np.ones_like(y).astype('float64')
  
          null_d = self.distribution.deviance(y=y, mu=null_mu, weights=weights)
          full_d = self.distribution.deviance(y=y, mu=mu, weights=weights)
  
          null_ll = self._loglikelihood(y=y, mu=null_mu, weights=weights)
          full_ll = self._loglikelihood(y=y, mu=mu, weights=weights)
  
          r2 = OrderedDict()
          r2['explained_deviance'] = 1. - full_d.sum()/null_d.sum()
          r2['McFadden'] = full_ll/null_ll
          r2['McFadden_adj'] = 1. - (full_ll - self.statistics_['edof'])/null_ll
  
          return r2
docs: estimate some pseudo R^2 values
  
          currently only computes explained deviance.
          results are stored
  
          Parameters
          ----------
          y : array-like of shape (n_samples,)
              output data vector
          mu : array-like of shape (n_samples,)
              expected value of the targets given the model and inputs
          weights : array-like shape (n_samples,) or None, optional
              containing sample weights
              if None, defaults to array of ones
  
          Returns
          -------
          None