Return the basis function applied to X.

        I.e. Phi(X, params), where params can also optionally be used and
        learned.

        Parameters
        ----------
        X : ndarray
            (N, d) array of observations where N is the number of samples, and
            d is the dimensionality of X.
        *params : optional
            parameter aguments, these are the parameters of the concatenated
            bases `in the order` they were concatenated.

        Returns
        -------
        ndarray :
            of shape (N, D) where D is the number of basis functions.

def transform(self, X, *params):
        """
        Return the basis function applied to X.

        I.e. Phi(X, params), where params can also optionally be used and
        learned.

        Parameters
        ----------
        X : ndarray
            (N, d) array of observations where N is the number of samples, and
            d is the dimensionality of X.
        *params : optional
            parameter aguments, these are the parameters of the concatenated
            bases `in the order` they were concatenated.

        Returns
        -------
        ndarray :
            of shape (N, D) where D is the number of basis functions.
        """
        Phi = []
        args = list(params)

        for base in self.bases:
            phi, args = base._transform_popargs(X, *args)
            Phi.append(phi)

        return np.hstack(Phi)