{"action":"created","comment":{"url":"https://api.github.com/repos/scikit-learn/scikit-learn/pulls/comments/128146961","pull_request_review_id":50797199,"id":128146961,"diff_hunk":"@@ -0,0 +1,872 @@\n+\"\"\"\n+Generalized Linear Models with Exponential Dispersion Family\n+\"\"\"\n+\n+# Author: Christian Lorentzen <lorentzen.ch@googlemail.ch>\n+# License: BSD 3 clause\n+\n+# TODO: Which name? GeneralizedLinearModel vs GeneralizedLinearRegression.\n+#       So far, it is GeneralizedLinearModel, since it could very easily\n+#       extended by Bernoulli/Binomial distribution.\n+# TODO: Which name/symbol for coefficients and weights in docu?\n+#       sklearn.linear_models uses w for coefficients.\n+#       So far, coefficients=beta and weight=w (as standard literature)\n+# TODO: Add l2-penalty\n+# TODO: Add l1-penalty (elastic net)\n+# TODO: Add cross validation\n+# TODO: Write docu and examples\n+\n+# Design Decisions:\n+# - The link funtion (instance of class Link) is necessary for the evaluation\n+#   of deviance, score, Fisher and Hessian matrix as functions of the\n+#   coefficients, which is needed by optimizers.\n+#   Solution: link as argument in those functions\n+\n+from __future__ import division\n+from abc import ABCMeta, abstractmethod, abstractproperty\n+import numbers\n+import numpy as np\n+from scipy import linalg, optimize, sparse\n+import warnings\n+from .base import LinearModel, LinearRegression\n+from ..base import RegressorMixin\n+from ..utils import check_X_y\n+from ..utils.extmath import safe_sparse_dot\n+from ..utils.optimize import newton_cg\n+from ..utils.validation import check_is_fitted\n+\n+\n+\n+class Link(metaclass=ABCMeta):\n+    \"\"\"Abstract base class for Link funtions\n+    \"\"\"\n+\n+    @abstractmethod\n+    def link(self, mu):\n+        \"\"\"The link function g(mu) with argument mu=E[Y] returns the\n+        linear predictor.\n+        \"\"\"\n+        raise NotImplementedError\n+\n+    @abstractmethod\n+    def derivative(self, mu):\n+        \"\"\"Derivative of the link g'(mu).\n+        \"\"\"\n+        raise NotImplementedError\n+\n+    @abstractmethod\n+    def inverse(self, lin_pred):\n+        \"\"\"The inverse link function h(lin_pred) with the linear predictor as\n+        argument returns mu=E[Y].\n+        \"\"\"\n+        raise NotImplementedError\n+\n+    @abstractmethod\n+    def inverse_derivative(self, lin_pred):\n+        \"\"\"Derivative of the inverse link function h'(lin_pred).\n+        \"\"\"\n+        raise NotImplementedError\n+\n+    @abstractmethod\n+    def inverse_derivative2(self, lin_pred):\n+        \"\"\"Second derivative of the inverse link function h''(lin_pred).\n+        \"\"\"\n+        raise NotImplementedError\n+\n+class IdentityLink(Link):\n+    \"\"\"The identity link function g(x)=x.\n+    \"\"\"\n+\n+    def link(self, mu):\n+        return mu\n+\n+    def derivative(self, mu):\n+        return np.ones_like(mu)\n+\n+    def inverse(self, lin_pred):\n+        return lin_pred\n+\n+    def inverse_derivative(self, lin_pred):\n+        return np.ones_like(lin_pred)\n+\n+    def inverse_derivative2(self, lin_pred):\n+        return np.zeros_like(lin_pred)\n+\n+\n+class LogLink(Link):\n+    \"\"\"The log link function g(x)=log(x).\n+    \"\"\"\n+\n+    def link(self, mu):\n+        return np.log(mu)\n+\n+    def derivative(self, mu):\n+        return 1./mu\n+\n+    def inverse(self, lin_pred):\n+        return np.exp(lin_pred)\n+\n+    def inverse_derivative(self, lin_pred):\n+        return np.exp(lin_pred)\n+\n+    def inverse_derivative2(self, lin_pred):\n+        return np.exp(lin_pred)\n+\n+\n+class ExponentialDispersionModel(metaclass=ABCMeta):\n+    \"\"\"Base class for reproductive Exponential Dispersion Models (EDM).\n+\n+    The pdf of :math:`Y\\sim \\mathrm{EDM}(\\mu, \\phi)` is given by\n+\n+    .. math:: p(y| \\theta, \\phi) = c(y, \\phi)\n+        \\exp\\left(\\frac{\\theta y-A(\\theta)}{\\phi}\\right)\n+        = \\tilde{c}(y, \\phi)\n+            \\exp\\left(-\\frac{d(y, \\mu)}{2\\phi}\\right)\n+\n+    with mean :math:`\\mathrm{E}[Y] = A'(\\theta) = \\mu`,\n+    variance :math:`\\mathrm{Var}[Y] = \\phi \\cdot v(\\mu)`,\n+    unit variance :math:`v(\\mu)` and\n+    unit deviance :math:`d(y,\\mu)`.\n+\n+    Attributes\n+    ----------\n+    lower_bound\n+    upper_bound\n+\n+    Methods\n+    -------\n+    in_y_range\n+    unit_variance\n+    unit_variance_derivative\n+    variance\n+    variance_derivative\n+    unit_deviance\n+    unit_deviance_derivative\n+    deviance\n+    deviance_derivative\n+    starting_mu\n+\n+    _score\n+    _fisher_matrix\n+    _observed_information\n+    _deviance\n+    _deviance_derivative\n+    _deviance_hessian\n+\n+    References\n+    ----------\n+    See https://en.wikipedia.org/wiki/Exponential_dispersion_model.\n+    \"\"\"\n+\n+    @abstractproperty\n+    def lower_bound(self):\n+        \"\"\"The lower bound of values of Y~EDM.\n+        \"\"\"\n+        raise NotImplementedError()\n+\n+    @abstractproperty\n+    def upper_bound(self):\n+        \"\"\"The upper bound of values of Y~EDM.\n+        \"\"\"\n+        raise NotImplementedError()\n+\n+    @abstractmethod\n+    def in_y_range(self, x):\n+        \"\"\"Returns true if x is in the valid range of Y~EDM.\n+        \"\"\"\n+        raise NotImplementedError()\n+\n+    @abstractmethod\n+    def unit_variance(self, mu):\n+        \"\"\"The unit variance :math:`v(mu)` determines the variance as\n+        a function of the mean mu by\n+        :math:`\\mathrm{Var}[Y_i] = \\phi/w_i*v(\\mu_i)`.\n+        It can also be derived from the unit deviance :math:`d(y,\\mu)` as\n+\n+        .. math:: v(\\mu) = \\frac{2}{\\frac{\\partial^2 d(y,\\mu)}{\n+            \\partial\\mu^2}}\\big|_{y=\\mu}\n+        \"\"\"\n+        raise NotImplementedError()\n+\n+    @abstractmethod\n+    def unit_variance_derivative(self, mu):\n+        \"\"\"The derivative of the unit variance w.r.t. mu, :math:`v'(\\mu)`.\n+        \"\"\"\n+        raise NotImplementedError()\n+\n+    def variance(self, mu, phi=1, weight=1):\n+        \"\"\"The variance of :math:`Y \\sim \\mathrm{EDM}(\\mu,\\phi)` is\n+        :math:`\\mathrm{Var}[Y_i]=\\phi/w_i*v(\\mu_i)`,\n+        with unit variance v(mu).\n+        \"\"\"\n+        return phi/weight * self.unit_variance(mu)\n+\n+    def variance_derivative(self, mu, phi=1, weight=1):\n+        \"\"\"The derivative of the variance w.r.t. mu,\n+        :math:`\\frac{\\partial}{\\partial\\mu}\\mathrm{Var}[Y_i]\n+        =phi/w_i*v'(\\mu_i)`, with unit variance v(mu).\n+        \"\"\"\n+        return phi/weight * self.unit_variance_derivative(mu)\n+\n+    @abstractmethod\n+    def unit_deviance(self, y, mu):\n+        \"\"\"The unit_deviance :math:`d(y,\\mu)`.\n+        In terms of the log-likelihood it is given by\n+        :math:`d(y,\\mu) = -2\\phi\\cdot\n+        \\left(loglike(y,\\mu,phi) - loglike(y,y,phi)\\right).`\n+        \"\"\"\n+        raise NotImplementedError()\n+\n+    def unit_deviance_derivative(self, y, mu):\n+        \"\"\"The derivative w.r.t. mu of the unit_deviance\n+        :math:`\\frac{d}{d\\mu}d(y,\\mu) = -2\\frac{y-\\mu}{v(\\mu)}`\n+        with unit variance :math:`v(\\mu)`.\n+\n+        Returns\n+        -------\n+        derivative: array, shape = (n_samples,)\n+        \"\"\"\n+        return -2*(y-mu)/self.unit_variance(mu)\n+\n+    def deviance(self, y, mu, weight=1):\n+        \"\"\"The deviance is given by :math:`D = \\sum_i w_i \\cdot d(y, \\mu)\n+        with weight :math:`w_i` and unit_deviance :math:`d(y,mu)`.\n+        In terms of the likelihood it is :math:`D = -2\\phi\\cdot\n+        \\left(loglike(y,\\mu,\\frac{phi}{w})\n+        - loglike(y,y,\\frac{phi}{w})\\right).`\n+        \"\"\"\n+        return np.sum(weight*self.unit_deviance(y,mu))\n+\n+    def _deviance(self, coef, X, y, weight, link):\n+        \"\"\"The deviance as a function of the coefficients ``coef``\n+        (:math:`beta`).\n+        \"\"\"\n+        lin_pred = safe_sparse_dot(X, coef, dense_output=True)\n+        mu = link.inverse(lin_pred)\n+        return self.deviance(y, mu, weight)\n+\n+    def deviance_derivative(self, y, mu, weight=1):\n+        \"\"\"The derivative w.r.t. mu of the deviance.`\n+        \"\"\"\n+        return weight*self.unit_deviance_derivative(y,mu)\n+\n+    def _score(self, coef, phi, X, y, weight, link):\n+        \"\"\"The score function :math:`s` is the derivative of the\n+        log-likelihood w.r.t. the ``coef`` (:math:`\\beta`).\n+        It is given by\n+\n+        .. math:\n+\n+            \\mathbf{s}(\\boldsymbol{\\beta}) = \\mathbf{X}^T \\mathbf{D}\n+            \\boldsymbol{\\Sigma}^-1 (\\mathbf{y} - \\boldsymbol{\\mu})\\,,\n+\n+        with :math:`\\mathbf{D}=\\mathrm{diag}(h'(\\eta_1),\\ldots)` and\n+        :math:`\\boldsymbol{\\Sigma}=\\mathrm{diag}(\\mathbf{V}(y_1),\\ldots)`.\n+        \"\"\"\n+        n_samples = X.shape[0]\n+        lin_pred = safe_sparse_dot(X, coef, dense_output=True)\n+        mu = link.inverse(lin_pred)\n+        sigma_inv = 1/self.variance(mu, phi=phi, weight=weight)\n+        d = link.inverse_derivative(lin_pred)\n+        d_sigma_inv = sparse.dia_matrix((sigma_inv*d, 0),\n+            shape=(n_samples, n_samples))\n+        temp = safe_sparse_dot(d_sigma_inv, (y-mu), dense_output=False)\n+        score = safe_sparse_dot(X.T, temp, dense_output=False)\n+        return score\n+\n+    def _fisher_matrix(self, coef, phi, X, y, weight, link):\n+        \"\"\"The Fisher information matrix, also known as expected\n+        information matrix. It is given by\n+\n+        .. math:\n+\n+            \\mathbf{F}(\\boldsymbol{\\beta}) = \\mathrm{E}\\left[\n+            -\\frac{\\partial^2 loglike}{\\partial\\boldsymbol{\\beta}\n+            \\partial\\boldsymbol{\\beta}^T}\\right]\n+            = \\mathbf{X}^T W \\mathbf{X} \\,,\n+\n+        with :math:`\\mathbf{W} = \\mathbf{D}^2 \\boldsymbol{\\Sigma}^{-1}`,\n+        see score function.\n+        \"\"\"\n+        n_samples = X.shape[0]\n+        lin_pred = safe_sparse_dot(X, coef, dense_output=True)\n+        mu = link.inverse(lin_pred)\n+        sigma_inv = 1/self.variance(mu, phi=phi, weight=weight)\n+        d2 = link.inverse_derivative(lin_pred)**2\n+        d2_sigma_inv = sparse.dia_matrix((sigma_inv*d2, 0),\n+            shape=(n_samples, n_samples))\n+        temp = safe_sparse_dot(d2_sigma_inv, X, dense_output=False)\n+        fisher_matrix = safe_sparse_dot(X.T, temp, dense_output=False)\n+        return fisher_matrix\n+\n+    def _observed_information(self, coef, phi, X, y, weight, link):\n+        \"\"\"The observed information matrix, also known as the negative of\n+        the Hessian matrix of the log-likelihood. It is given by\n+\n+        .. math:\n+\n+            \\mathbf{H}(\\boldsymbol{\\beta}) =\n+            -\\frac{\\partial^2 loglike}{\\partial\\boldsymbol{\\beta}\n+            \\partial\\boldsymbol{\\beta}^T}\n+            = \\mathbf{X}^T \\legt[\n+            - \\mathbf{D}' \\mathbf{R}\n+            + \\mathbf{D}^2 \\mathbf{V} \\mathbf{R}\n+            + \\mathbf{D}^2\n+            \\right] \\boldsymbol{\\Sigma}^{-1} \\mathbf{X} \\,,\n+\n+        with :math:`\\mathbf{R} = \\mathrm{diag}(y_i - \\mu_i)`,\n+        :math:`\\mathbf{V} = \\mathrm{diag}\\left(\\frac{v'(\\mu_i)}{\n+        v(\\mu_i)}\n+        \\right)`,\n+        see score function and Fisher matrix.\n+        \"\"\"\n+        n_samples = X.shape[0]\n+        lin_pred = safe_sparse_dot(X, coef, dense_output=True)\n+        mu = link.inverse(lin_pred)\n+        sigma_inv = 1/self.variance(mu, phi=phi, weight=weight)\n+        dp = link.inverse_derivative2(lin_pred)\n+        d2 = link.inverse_derivative(lin_pred)**2\n+        v = self.unit_variance_derivative(mu)/self.unit_variance(mu)\n+        r = y - mu\n+        temp = sparse.dia_matrix((sigma_inv*(-dp*r+d2*v*r+d2), 0),\n+            shape=(n_samples, n_samples))\n+        temp = safe_sparse_dot(temp, X, dense_output=False)\n+        observed_information = safe_sparse_dot(X.T, temp, dense_output=False)\n+        return observed_information\n+\n+    def _deviance_derivative(self, coef, X, y, weight, link):\n+        \"\"\"The derivative w.r.t. ``coef`` (:math:`\\beta`) of the deviance as a\n+        function of the coefficients ``coef``.\n+        This is equivalent to :math:`-2\\phi` times the score function\n+        :math:`s` (derivative of the log-likelihood).\n+        \"\"\"\n+        score = self._score(coef=coef, phi=1, X=X, y=y, weight=weight,\n+            link=link)\n+        return -2*score\n+\n+    def _deviance_hessian(self, coef, X, y, weight, link):\n+        \"\"\"The hessian matrix w.r.t. ``coef`` (:math:`\\beta`) of the deviance\n+        as a function of the coefficients ``coef``.\n+        This is equivalent to :math:`+2\\phi` times the observed information\n+        matrix.\n+        \"\"\"\n+        info_matrix = self._observed_information(coef=coef, phi=1,\n+            X=X, y=y, weight=weight, link=link)\n+        return 2*info_matrix\n+\n+    def starting_mu(self, y, weight=1):\n+        \"\"\"Starting values for the mean mu_i in IRLS.\"\"\"\n+        return (weight*y+np.mean(weight*y))/(2.*np.sum(np.ones_like(y)*weight))\n+\n+\n+class TweedieDistribution(ExponentialDispersionModel):\n+    \"\"\"A class for the Tweedie distribution.\n+    They have mu=E[X] and Var[X] \\propto mu**power.\n+\n+    Attributes\n+    ----------\n+    power : float\n+            The variance power of the unit_variance\n+            :math:`v(mu) = mu^{power}`.\n+    \"\"\"\n+    def __init__(self, power=0):\n+        self.power = power\n+        self._upper_bound = np.Inf\n+        self._upper_compare = lambda x: np.less(x, self.upper_bound)\n+        if power < 0:\n+            #Extreme Stable\n+            self._lower_bound = -np.Inf\n+            self._lower_compare = lambda x: np.greater(x, self.lower_bound)\n+        elif power == 0:\n+            #GaussianDistribution\n+            self._lower_bound = -np.Inf\n+            self._lower_compare = lambda x: np.greater(x, self.lower_bound)\n+        elif (power > 0) and (power < 1):\n+            raise ValueError('For 0<power<1, no distribution exists.')\n+        elif power == 1:\n+            #PoissonDistribution\n+            self._lower_bound = 0\n+            self._lower_compare = (\n+                lambda x: np.greater_equal(x, self.lower_bound))\n+        elif (power > 1) and (power < 2):\n+            #Compound Poisson\n+            self._lower_bound = 0\n+            self._lower_compare = (\n+                lambda x: np.greater_equal(x, self.lower_bound))\n+        elif power == 2:\n+            #GammaDistribution\n+            self._lower_bound = 0\n+            self._lower_compare = lambda x: np.greater(x, self.lower_bound)\n+        elif (power > 2) and (power < 3):\n+            #Positive Stable\n+            self._lower_bound = 0\n+            self._lower_compare = lambda x: np.greater(x, self.lower_bound)\n+        elif power == 3:\n+            #InverseGaussianDistribution\n+            self._lower_bound = 0\n+            self._lower_compare = lambda x: np.greater(x, self.lower_bound)\n+        elif power > 3:\n+            #Positive Stable\n+            self._lower_bound = 0\n+            self._lower_compare = lambda x: np.greater(x, self.lower_bound)\n+\n+    @property\n+    def power(self):\n+        return self._power\n+\n+    @power.setter\n+    def power(self, power):\n+        if not isinstance(power, numbers.Real):\n+            raise TypeError('power must be a real number, input was {0}'\n+                .format(power))\n+        self._power = power\n+\n+    @property\n+    def lower_bound(self):\n+        return self._lower_bound\n+\n+    @property\n+    def upper_bound(self):\n+        return self._upper_bound\n+\n+    def in_y_range(self, x):\n+        return np.logical_and(self._lower_compare(x), self._upper_compare(x))\n+\n+    def unit_variance(self, mu):\n+        \"\"\"The unit variance of a Tweedie distribution is v(mu)=mu**power.\n+        \"\"\"\n+        return np.power(mu, self.power)\n+\n+    def unit_variance_derivative(self, mu):\n+        \"\"\"The derivative of the unit variance of a Tweedie distribution is\n+        v(mu)=power*mu**(power-1).\n+        \"\"\"\n+        return self.power*np.power(mu, self.power-1)\n+\n+    def unit_deviance(self, y, mu):\n+        p = self.power\n+        if p == 0:\n+            #NormalDistribution\n+            return (y-mu)**2\n+        if p == 1:\n+            #PoissonDistribution\n+            return 2 * (np.where(y==0,0,y*np.log(y/mu))-y+mu)\n+        elif p == 2:\n+            #GammaDistribution\n+            return 2 * (np.log(mu/y)+y/mu-1)\n+        else:\n+            #return 2 * (np.maximum(y,0)**(2-p)/((1-p)*(2-p))\n+            #    - y*mu**(1-p)/(1-p) + mu**(2-p)/(2-p))\n+            return 2 * (np.power(np.maximum(y,0), 2-p)/((1-p)*(2-p))\n+                - y*np.power(mu, 1-p)/(1-p) + np.power(mu, 2-p)/(2-p))\n+\n+    def likelihood(self, y, X, beta, phi, weight=1):\n+        raise NotImplementedError('This function is not (yet) implemented.')\n+\n+\n+class NormalDistribution(TweedieDistribution):\n+    \"\"\"Class for the Normal (aka Gaussian) distribution\"\"\"\n+    def __init__(self):\n+        super(NormalDistribution, self).__init__(power=0)\n+\n+GaussianDistribution = NormalDistribution\n+\n+class PoissonDistribution(TweedieDistribution):\n+    \"\"\"Class for the scaled Poisson distribution\"\"\"\n+    def __init__(self):\n+        super(PoissonDistribution, self).__init__(power=1)\n+\n+class GammaDistribution(TweedieDistribution):\n+    \"\"\"Class for the Gamma distribution\"\"\"\n+    def __init__(self):\n+        super(GammaDistribution, self).__init__(power=2)\n+\n+class InverseGaussianDistribution(TweedieDistribution):\n+    \"\"\"Class for the scaled InverseGaussianDistribution distribution\"\"\"\n+    def __init__(self):\n+        super(InverseGaussianDistribution, self).__init__(power=3)\n+\n+class GeneralizedHyperbolicSecand(ExponentialDispersionModel):\n+    \"\"\"A class for the von Generalized Hyperbolic Secand (GHS) distribution.\n+\n+    The GHS distribution is for data y in (-inf, inf).\n+    \"\"\"\n+    def __init__(self):\n+        self._lower_bound = -np.Inf\n+        self._upper_bound = np.Inf\n+\n+    @property\n+    def lower_bound(self):\n+        return self._lower_bound\n+\n+    @property\n+    def upper_bound(self):\n+        return self._upper_bound\n+\n+    def in_y_range(self, x):\n+        np.logical_and(\n+            np.greater(x, self.lower_bound),\n+            np.less(x, self.lower_bound)\n+            )\n+\n+    def unit_variance(self, mu):\n+        return 1 + mu**2\n+\n+    def unit_variance_derivative(self, mu):\n+        return 2*mu\n+\n+    def unit_deviance(self, y, mu):\n+        return (2*y*(np.arctan(y) - np.arctan(mu))\n+            + np.log((1+mu**2)/(1+y**2)))\n+\n+\n+\n+class GeneralizedLinearModel(LinearModel, RegressorMixin):\n+    \"\"\"\n+    Class to fit a Generalized Linear Model (GLM) based on reproductive\n+    Exponential Dispersion Models (EDM).\n+\n+    Assumptions:","path":"sklearn/linear_model/glm.py","position":529,"original_position":529,"commit_id":"859216b2b8222c311052b6efa464aee3a13fc3cf","original_commit_id":"859216b2b8222c311052b6efa464aee3a13fc3cf","user":{"login":"jnothman","id":78827,"avatar_url":"https://avatars2.githubusercontent.com/u/78827?v=4","gravatar_id":"","url":"https://api.github.com/users/jnothman","html_url":"https://github.com/jnothman","followers_url":"https://api.github.com/users/jnothman/followers","following_url":"https://api.github.com/users/jnothman/following{/other_user}","gists_url":"https://api.github.com/users/jnothman/gists{/gist_id}","starred_url":"https://api.github.com/users/jnothman/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jnothman/subscriptions","organizations_url":"https://api.github.com/users/jnothman/orgs","repos_url":"https://api.github.com/users/jnothman/repos","events_url":"https://api.github.com/users/jnothman/events{/privacy}","received_events_url":"https://api.github.com/users/jnothman/received_events","type":"User","site_admin":false},"body":"Most of the below belongs in the [User Guide](https://github.com/scikit-learn/scikit-learn/blob/master/doc/modules/linear_model.rst)","created_at":"2017-07-19T03:44:55Z","updated_at":"2017-07-19T03:47:43Z","html_url":"https://github.com/scikit-learn/scikit-learn/pull/9405#discussion_r128146961","pull_request_url":"https://api.github.com/repos/scikit-learn/scikit-learn/pulls/9405","_links":{"self":{"href":"https://api.github.com/repos/scikit-learn/scikit-learn/pulls/comments/128146961"},"html":{"href":"https://github.com/scikit-learn/scikit-learn/pull/9405#discussion_r128146961"},"pull_request":{"href":"https://api.github.com/repos/scikit-learn/scikit-learn/pulls/9405"}}},"pull_request":{"url":"https://api.github.com/repos/scikit-learn/scikit-learn/pulls/9405","id":131174924,"html_url":"https://github.com/scikit-learn/scikit-learn/pull/9405","diff_url":"https://github.com/scikit-learn/scikit-learn/pull/9405.diff","patch_url":"https://github.com/scikit-learn/scikit-learn/pull/9405.patch","issue_url":"https://api.github.com/repos/scikit-learn/scikit-learn/issues/9405","number":9405,"state":"open","locked":false,"title":"[WIP] Add Generalized Linear Models, issue #5975, initial commit","user":{"login":"lorentzenchr","id":15324633,"avatar_url":"https://avatars2.githubusercontent.com/u/15324633?v=4","gravatar_id":"","url":"https://api.github.com/users/lorentzenchr","html_url":"https://github.com/lorentzenchr","followers_url":"https://api.github.com/users/lorentzenchr/followers","following_url":"https://api.github.com/users/lorentzenchr/following{/other_user}","gists_url":"https://api.github.com/users/lorentzenchr/gists{/gist_id}","starred_url":"https://api.github.com/users/lorentzenchr/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/lorentzenchr/subscriptions","organizations_url":"https://api.github.com/users/lorentzenchr/orgs","repos_url":"https://api.github.com/users/lorentzenchr/repos","events_url":"https://api.github.com/users/lorentzenchr/events{/privacy}","received_events_url":"https://api.github.com/users/lorentzenchr/received_events","type":"User","site_admin":false},"body":"This PR adds Generalized Linear Models (full Tweedie family), see issue #5975. Futher distributions of the exponential dispersion family can be added easily.\r\n\r\nSorry, for not posting this earlier.\r\n\r\nThere is still a lot to do, i.e. adding l2 and l1 penalties (glmnet), docs, examples, bug fixing...\r\n\r\nI'm excited about your feedback.","created_at":"2017-07-18T20:05:43Z","updated_at":"2017-07-19T03:47:43Z","closed_at":null,"merged_at":null,"merge_commit_sha":"ffd8617f911d643509dedf2a01afec1b4a4c9c09","assignee":null,"assignees":[],"requested_reviewers":[],"milestone":null,"commits_url":"https://api.github.com/repos/scikit-learn/scikit-learn/pulls/9405/commits","review_comments_url":"https://api.github.com/repos/scikit-learn/scikit-learn/pulls/9405/comments","review_comment_url":"https://api.github.com/repos/scikit-learn/scikit-learn/pulls/comments{/number}","comments_url":"https://api.github.com/repos/scikit-learn/scikit-learn/issues/9405/comments","statuses_url":"https://api.github.com/repos/scikit-learn/scikit-learn/statuses/859216b2b8222c311052b6efa464aee3a13fc3cf","head":{"label":"lorentzenchr:GLM","ref":"GLM","sha":"859216b2b8222c311052b6efa464aee3a13fc3cf","user":{"login":"lorentzenchr","id":15324633,"avatar_url":"https://avatars2.githubusercontent.com/u/15324633?v=4","gravatar_id":"","url":"https://api.github.com/users/lorentzenchr","html_url":"https://github.com/lorentzenchr","followers_url":"https://api.github.com/users/lorentzenchr/followers","following_url":"https://api.github.com/users/lorentzenchr/following{/other_user}","gists_url":"https://api.github.com/users/lorentzenchr/gists{/gist_id}","starred_url":"https://api.github.com/users/lorentzenchr/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/lorentzenchr/subscriptions","organizations_url":"https://api.github.com/users/lorentzenchr/orgs","repos_url":"https://api.github.com/users/lorentzenchr/repos","events_url":"https://api.github.com/users/lorentzenchr/events{/privacy}","received_events_url":"https://api.github.com/users/lorentzenchr/received_events","type":"User","site_admin":false},"repo":{"id":93259654,"name":"scikit-learn","full_name":"lorentzenchr/scikit-learn","owner":{"login":"lorentzenchr","id":15324633,"avatar_url":"https://avatars2.githubusercontent.com/u/15324633?v=4","gravatar_id":"","url":"https://api.github.com/users/lorentzenchr","html_url":"https://github.com/lorentzenchr","followers_url":"https://api.github.com/users/lorentzenchr/followers","following_url":"https://api.github.com/users/lorentzenchr/following{/other_user}","gists_url":"https://api.github.com/users/lorentzenchr/gists{/gist_id}","starred_url":"https://api.github.com/users/lorentzenchr/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/lorentzenchr/subscriptions","organizations_url":"https://api.github.com/users/lorentzenchr/orgs","repos_url":"https://api.github.com/users/lorentzenchr/repos","events_url":"https://api.github.com/users/lorentzenchr/events{/privacy}","received_events_url":"https://api.github.com/users/lorentzenchr/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/lorentzenchr/scikit-learn","description":"scikit-learn: machine learning in Python","fork":true,"url":"https://api.github.com/repos/lorentzenchr/scikit-learn","forks_url":"https://api.github.com/repos/lorentzenchr/scikit-learn/forks","keys_url":"https://api.github.com/repos/lorentzenchr/scikit-learn/keys{/key_id}","collaborators_url":"https://api.github.com/repos/lorentzenchr/scikit-learn/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/lorentzenchr/scikit-learn/teams","hooks_url":"https://api.github.com/repos/lorentzenchr/scikit-learn/hooks","issue_events_url":"https://api.github.com/repos/lorentzenchr/scikit-learn/issues/events{/number}","events_url":"https://api.github.com/repos/lorentzenchr/scikit-learn/events","assignees_url":"https://api.github.com/repos/lorentzenchr/scikit-learn/assignees{/user}","branches_url":"https://api.github.com/repos/lorentzenchr/scikit-learn/branches{/branch}","tags_url":"https://api.github.com/repos/lorentzenchr/scikit-learn/tags","blobs_url":"https://api.github.com/repos/lorentzenchr/scikit-learn/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/lorentzenchr/scikit-learn/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/lorentzenchr/scikit-learn/git/refs{/sha}","trees_url":"https://api.github.com/repos/lorentzenchr/scikit-learn/git/trees{/sha}","statuses_url":"https://api.github.com/repos/lorentzenchr/scikit-learn/statuses/{sha}","languages_url":"https://api.github.com/repos/lorentzenchr/scikit-learn/languages","stargazers_url":"https://api.github.com/repos/lorentzenchr/scikit-learn/stargazers","contributors_url":"https://api.github.com/repos/lorentzenchr/scikit-learn/contributors","subscribers_url":"https://api.github.com/repos/lorentzenchr/scikit-learn/subscribers","subscription_url":"https://api.github.com/repos/lorentzenchr/scikit-learn/subscription","commits_url":"https://api.github.com/repos/lorentzenchr/scikit-learn/commits{/sha}","git_commits_url":"https://api.github.com/repos/lorentzenchr/scikit-learn/git/commits{/sha}","comments_url":"https://api.github.com/repos/lorentzenchr/scikit-learn/comments{/number}","issue_comment_url":"https://api.github.com/repos/lorentzenchr/scikit-learn/issues/comments{/number}","contents_url":"https://api.github.com/repos/lorentzenchr/scikit-learn/contents/{+path}","compare_url":"https://api.github.com/repos/lorentzenchr/scikit-learn/compare/{base}...{head}","merges_url":"https://api.github.com/repos/lorentzenchr/scikit-learn/merges","archive_url":"https://api.github.com/repos/lorentzenchr/scikit-learn/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/lorentzenchr/scikit-learn/downloads","issues_url":"https://api.github.com/repos/lorentzenchr/scikit-learn/issues{/number}","pulls_url":"https://api.github.com/repos/lorentzenchr/scikit-learn/pulls{/number}","milestones_url":"https://api.github.com/repos/lorentzenchr/scikit-learn/milestones{/number}","notifications_url":"https://api.github.com/repos/lorentzenchr/scikit-learn/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/lorentzenchr/scikit-learn/labels{/name}","releases_url":"https://api.github.com/repos/lorentzenchr/scikit-learn/releases{/id}","deployments_url":"https://api.github.com/repos/lorentzenchr/scikit-learn/deployments","created_at":"2017-06-03T16:16:55Z","updated_at":"2017-06-03T16:17:06Z","pushed_at":"2017-07-18T19:53:44Z","git_url":"git://github.com/lorentzenchr/scikit-learn.git","ssh_url":"git@github.com:lorentzenchr/scikit-learn.git","clone_url":"https://github.com/lorentzenchr/scikit-learn.git","svn_url":"https://github.com/lorentzenchr/scikit-learn","homepage":"http://scikit-learn.org","size":80736,"stargazers_count":0,"watchers_count":0,"language":"Python","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"scikit-learn:master","ref":"master","sha":"71408e09e4bf01a72567f9167a1e33fb9620d786","user":{"login":"scikit-learn","id":365630,"avatar_url":"https://avatars2.githubusercontent.com/u/365630?v=4","gravatar_id":"","url":"https://api.github.com/users/scikit-learn","html_url":"https://github.com/scikit-learn","followers_url":"https://api.github.com/users/scikit-learn/followers","following_url":"https://api.github.com/users/scikit-learn/following{/other_user}","gists_url":"https://api.github.com/users/scikit-learn/gists{/gist_id}","starred_url":"https://api.github.com/users/scikit-learn/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/scikit-learn/subscriptions","organizations_url":"https://api.github.com/users/scikit-learn/orgs","repos_url":"https://api.github.com/users/scikit-learn/repos","events_url":"https://api.github.com/users/scikit-learn/events{/privacy}","received_events_url":"https://api.github.com/users/scikit-learn/received_events","type":"Organization","site_admin":false},"repo":{"id":843222,"name":"scikit-learn","full_name":"scikit-learn/scikit-learn","owner":{"login":"scikit-learn","id":365630,"avatar_url":"https://avatars2.githubusercontent.com/u/365630?v=4","gravatar_id":"","url":"https://api.github.com/users/scikit-learn","html_url":"https://github.com/scikit-learn","followers_url":"https://api.github.com/users/scikit-learn/followers","following_url":"https://api.github.com/users/scikit-learn/following{/other_user}","gists_url":"https://api.github.com/users/scikit-learn/gists{/gist_id}","starred_url":"https://api.github.com/users/scikit-learn/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/scikit-learn/subscriptions","organizations_url":"https://api.github.com/users/scikit-learn/orgs","repos_url":"https://api.github.com/users/scikit-learn/repos","events_url":"https://api.github.com/users/scikit-learn/events{/privacy}","received_events_url":"https://api.github.com/users/scikit-learn/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/scikit-learn/scikit-learn","description":"scikit-learn: machine learning in Python","fork":false,"url":"https://api.github.com/repos/scikit-learn/scikit-learn","forks_url":"https://api.github.com/repos/scikit-learn/scikit-learn/forks","keys_url":"https://api.github.com/repos/scikit-learn/scikit-learn/keys{/key_id}","collaborators_url":"https://api.github.com/repos/scikit-learn/scikit-learn/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/scikit-learn/scikit-learn/teams","hooks_url":"https://api.github.com/repos/scikit-learn/scikit-learn/hooks","issue_events_url":"https://api.github.com/repos/scikit-learn/scikit-learn/issues/events{/number}","events_url":"https://api.github.com/repos/scikit-learn/scikit-learn/events","assignees_url":"https://api.github.com/repos/scikit-learn/scikit-learn/assignees{/user}","branches_url":"https://api.github.com/repos/scikit-learn/scikit-learn/branches{/branch}","tags_url":"https://api.github.com/repos/scikit-learn/scikit-learn/tags","blobs_url":"https://api.github.com/repos/scikit-learn/scikit-learn/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/scikit-learn/scikit-learn/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/scikit-learn/scikit-learn/git/refs{/sha}","trees_url":"https://api.github.com/repos/scikit-learn/scikit-learn/git/trees{/sha}","statuses_url":"https://api.github.com/repos/scikit-learn/scikit-learn/statuses/{sha}","languages_url":"https://api.github.com/repos/scikit-learn/scikit-learn/languages","stargazers_url":"https://api.github.com/repos/scikit-learn/scikit-learn/stargazers","contributors_url":"https://api.github.com/repos/scikit-learn/scikit-learn/contributors","subscribers_url":"https://api.github.com/repos/scikit-learn/scikit-learn/subscribers","subscription_url":"https://api.github.com/repos/scikit-learn/scikit-learn/subscription","commits_url":"https://api.github.com/repos/scikit-learn/scikit-learn/commits{/sha}","git_commits_url":"https://api.github.com/repos/scikit-learn/scikit-learn/git/commits{/sha}","comments_url":"https://api.github.com/repos/scikit-learn/scikit-learn/comments{/number}","issue_comment_url":"https://api.github.com/repos/scikit-learn/scikit-learn/issues/comments{/number}","contents_url":"https://api.github.com/repos/scikit-learn/scikit-learn/contents/{+path}","compare_url":"https://api.github.com/repos/scikit-learn/scikit-learn/compare/{base}...{head}","merges_url":"https://api.github.com/repos/scikit-learn/scikit-learn/merges","archive_url":"https://api.github.com/repos/scikit-learn/scikit-learn/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/scikit-learn/scikit-learn/downloads","issues_url":"https://api.github.com/repos/scikit-learn/scikit-learn/issues{/number}","pulls_url":"https://api.github.com/repos/scikit-learn/scikit-learn/pulls{/number}","milestones_url":"https://api.github.com/repos/scikit-learn/scikit-learn/milestones{/number}","notifications_url":"https://api.github.com/repos/scikit-learn/scikit-learn/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/scikit-learn/scikit-learn/labels{/name}","releases_url":"https://api.github.com/repos/scikit-learn/scikit-learn/releases{/id}","deployments_url":"https://api.github.com/repos/scikit-learn/scikit-learn/deployments","created_at":"2010-08-17T09:43:38Z","updated_at":"2017-07-19T03:40:19Z","pushed_at":"2017-07-19T01:11:23Z","git_url":"git://github.com/scikit-learn/scikit-learn.git","ssh_url":"git@github.com:scikit-learn/scikit-learn.git","clone_url":"https://github.com/scikit-learn/scikit-learn.git","svn_url":"https://github.com/scikit-learn/scikit-learn","homepage":"http://scikit-learn.org","size":84070,"stargazers_count":19907,"watchers_count":19907,"language":"Python","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":10742,"mirror_url":null,"open_issues_count":1391,"forks":10742,"open_issues":1391,"watchers":19907,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/scikit-learn/scikit-learn/pulls/9405"},"html":{"href":"https://github.com/scikit-learn/scikit-learn/pull/9405"},"issue":{"href":"https://api.github.com/repos/scikit-learn/scikit-learn/issues/9405"},"comments":{"href":"https://api.github.com/repos/scikit-learn/scikit-learn/issues/9405/comments"},"review_comments":{"href":"https://api.github.com/repos/scikit-learn/scikit-learn/pulls/9405/comments"},"review_comment":{"href":"https://api.github.com/repos/scikit-learn/scikit-learn/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/scikit-learn/scikit-learn/pulls/9405/commits"},"statuses":{"href":"https://api.github.com/repos/scikit-learn/scikit-learn/statuses/859216b2b8222c311052b6efa464aee3a13fc3cf"}}}}
{"actor":{"display_login":"jnothman"}}