{"action":"created","comment":{"url":"https://api.github.com/repos/scikit-learn/scikit-learn/pulls/comments/37337452","id":37337452,"diff_hunk":"@@ -0,0 +1,454 @@\n+\"\"\"Base class for mixture models.\"\"\"\n+from __future__ import print_function\n+from time import time\n+import warnings\n+import numpy as np\n+from abc import ABCMeta, abstractmethod\n+\n+from ..externals import six\n+from ..base import BaseEstimator\n+from ..base import DensityMixin\n+from .. import cluster\n+from ..utils import check_random_state, check_array\n+from ..utils.extmath import logsumexp\n+from sklearn.utils import ConvergenceWarning\n+\n+\n+def check_shape(param, param_shape, name):\n+    \"\"\"Validate the input data X.\n+\n+    Raise informative messages otherwise.\n+\n+    Parameters\n+    ----------\n+    param : array\n+\n+    param_shape : tuple\n+\n+    name : string\n+    \"\"\"\n+    param = np.array(param)\n+    if param.shape != param_shape:\n+        raise ValueError(\"The parameter '%s' should have the shape of %s, \"\n+                         \"but got %s\" % (name, param_shape, param.shape))\n+\n+\n+def check_X(X, n_components=None, n_features=None):\n+    \"\"\"Check the input data X.\n+\n+    Parameters\n+    ----------\n+    X : array-like, (n_samples, n_features)\n+\n+    n_components : int\n+\n+    Returns\n+    -------\n+    X : array, (n_samples, n_features)\n+    \"\"\"\n+    X = check_array(X, dtype=[np.float64, np.float32], ensure_2d=False)\n+    if X.ndim != 2:\n+        raise ValueError(\"Expected the input data X have 2 dimensions, \"\n+                         \"but got %s dimension(s)\" %\n+                         X.ndim)\n+    if n_components is not None and X.shape[0] < n_components:\n+        raise ValueError('Expected n_samples >= n_components'\n+                         'but got n_components = %d, n_samples = %d'\n+                         % (n_components, X.shape[0]))\n+    if n_features is not None and X.shape[1] != n_features:\n+        raise ValueError(\"Expected the input data X have %d features, \"\n+                         \"but got %d features\"\n+                         % (n_features, X.shape[1]))\n+    return X\n+\n+\n+def check_weights(weights, desired_shape):\n+    \"\"\"Check the user provided 'weights'.\n+\n+    'weights' are the proportions of components of the mixture\n+\n+    Parameters\n+    ----------\n+    weights : array-like, shape = (n_components,)\n+\n+    n_components : int\n+\n+    Returns\n+    -------\n+    weights : array, shape = (n_components,)\n+    \"\"\"\n+    # check value\n+    weights = check_array(weights, dtype=[np.float64, np.float32],\n+                          ensure_2d=False)\n+\n+    # check shape\n+    check_shape(weights, desired_shape, 'weights')\n+\n+    # check range\n+    if (any(np.less(weights, 0)) or\n+            any(np.greater(weights, 1))):\n+        raise ValueError(\"The parameter 'weights' should be in the range \"\n+                         \"[0, 1], but got max value %.5f, min value %.5f\"\n+                         % (np.min(weights), np.max(weights)))\n+\n+    # check normalization\n+    if not np.allclose(np.abs(1 - np.sum(weights)), 0.0):\n+        raise ValueError(\"The parameter 'weights' should be normalized, \"\n+                         \"but got sum(weights) = %.5f\" % np.sum(weights))\n+    return weights\n+\n+\n+class MixtureBase(six.with_metaclass(ABCMeta, DensityMixin, BaseEstimator)):\n+\n+    \"\"\"Base class for mixture models.\n+\n+    This abstract class specifies the interface by abstract methods and\n+    provides basic common methods for mixture models.\n+    \"\"\"\n+\n+    def __init__(self, n_components, covariance_type, tol, reg_covar,\n+                 n_iter, n_init, init_params, random_state, verbose,\n+                 verbose_interval):\n+        self.n_components = n_components\n+        self.n_features = None\n+        self.covariance_type = covariance_type\n+        self.tol = tol\n+        self.reg_covar = reg_covar\n+        self.random_state = random_state\n+        self.random_state_ = check_random_state(random_state)\n+        self.n_iter = n_iter\n+        self.n_init = n_init\n+        self.init_params = init_params\n+        self.verbose = verbose\n+        self.verbose_interval = verbose_interval\n+        self.converged_ = False\n+\n+        if n_init < 1:\n+            raise ValueError(\"Invalid value for 'n_init': %d \"\n+                             \"Estimation requires at least one run\" % n_init)\n+\n+        if n_iter < 1:\n+            raise ValueError(\"Invalid value for 'n_iter': %d \"\n+                             \"Estimation requires at least one iteration\"\n+                             % n_iter)\n+\n+        if reg_covar < 0:\n+            raise ValueError(\"Invalid value for 'reg_covar': %.5f \"\n+                             \"regularization on covariance must be \"\n+                             \"non-negative\"\n+                             % reg_covar)\n+\n+    # e-step functions\n+    @abstractmethod\n+    def _estimate_log_weights(self):\n+        \"\"\"Estimate log weights in EM algorithm, E[ ln pi ] in VB algorithm.\n+\n+        Returns\n+        -------\n+        log_weight : array, shape = (n_components, )\n+        \"\"\"\n+        pass\n+\n+    @abstractmethod\n+    def _estimate_log_prob(self, X):\n+        \"\"\"Estimate the log probabilities ln P(X | Z).\n+\n+        Log probabilities per each component for each sample.\n+\n+        Parameters\n+        ----------\n+        X : array-like, shape = (n_samples, n_features)\n+\n+        Returns\n+        -------\n+        log_prob : array, shape = (n_samples, n_component)\n+        \"\"\"\n+        pass\n+\n+    def _estimate_weighted_log_prob(self, X):\n+        \"\"\"Estimate the weighted log probabilities, ln P(X | Z) + log weights.\n+\n+        Parameters\n+        ----------\n+        X : array-like, shape = (n_samples, n_features)\n+\n+        Returns\n+        -------\n+        weighted_log_prob : array, shape = (n_features, n_component)\n+        \"\"\"\n+        return self._estimate_log_weights() + self._estimate_log_prob(X)\n+\n+    def _estimate_log_prob_resp(self, X):\n+        \"\"\"Estimate log probabilities responsibilities for each sample.\n+\n+        Compute the log probabilities, weighted log probabilities per\n+        component and responsibilities for each sample in X with respect to\n+        the current state of the model.\n+\n+        Parameters\n+        ----------\n+        X : array-like, shape = (n_samples, n_features)\n+\n+        Returns\n+        -------\n+        log_prob_norm : array, shape = (n_samples,)\n+            ln p(X)\n+\n+        log_prob : array, shape = (n_samples, n_components)\n+            ln p(X|Z) + log weights\n+\n+        responsibilities : array, shape = (n_samples, n_components)\n+        \"\"\"\n+        weighted_log_prob = self._estimate_weighted_log_prob(X)\n+        log_prob_norm = logsumexp(weighted_log_prob, axis=1)\n+        with np.errstate(under='ignore'):\n+            # ignore underflow\n+            resp = np.exp(weighted_log_prob - log_prob_norm[:, np.newaxis])\n+        return log_prob_norm, weighted_log_prob, resp\n+\n+    @abstractmethod\n+    def _e_step(self, X):\n+        \"\"\"E step.\n+\n+        Parameters\n+        ----------\n+        X : array-like, shape = (n_samples, n_features)\n+\n+        Returns\n+        -------\n+        log-likelihood : scalar\n+\n+        responsibility : array, shape = (n_samples, n_components)\n+        \"\"\"\n+        pass\n+\n+    def _initialize_by_kmeans(self, X):\n+        \"\"\"Compute the responsibilities using k-means clustering.\n+\n+        Parameters\n+        ----------\n+        X : array-like, shape = (n_samples, n_features)\n+\n+        Returns\n+        -------\n+        resp : array, shape = (n_samples, n_components)\n+        \"\"\"\n+        n_samples = X.shape[0]\n+        labels = cluster.KMeans(n_clusters=self.n_components,\n+                                random_state=self.random_state_).fit(X).labels_\n+        resp = np.zeros((n_samples, self.n_components))\n+        resp[range(n_samples), labels] = 1\n+        return resp\n+\n+    def _initialize_resp(self, X):\n+        \"\"\"Compute the initial responsibilities for initialization.\n+\n+        Responsibilities are computed by the method `self.init_params`.\n+\n+        Parameters\n+        ----------\n+        X : array-like, shape = (n_samples, n_features)\n+\n+        Returns\n+        -------\n+        resp : array, shape = (n_samples, n_features)\n+        \"\"\"\n+        if self.init_params == 'kmeans':\n+            resp = self._initialize_by_kmeans(X)\n+        elif self.init_params == 'random':\n+            resp = self.random_state_.rand(X.shape[0], self.n_components)\n+            resp = resp / resp.sum(axis=1)[:, np.newaxis]\n+        else:\n+            raise ValueError(\"Unimplemented initialization method %s\"\n+                             % self.init_params)\n+        return resp\n+\n+    def score_samples(self, X):\n+        \"\"\"Compute the weighted log probabilities for each sample.\n+\n+        Parameters\n+        ----------\n+        X : array-like, shape = (n_samples, n_features)\n+\n+        Returns\n+        -------\n+        log_prob : array, shape = (n_samples,)\n+            log probabilities\n+        \"\"\"\n+        self._check_is_fitted()\n+        X = check_X(X, None, self.n_features)\n+\n+        log_prob = self._estimate_log_prob(X)\n+        return logsumexp(log_prob, axis=1)\n+\n+    def _initialize(self, X):\n+        \"\"\"Initialize the model parameters.\"\"\"\n+        resp = self._initialize_resp(X)\n+        self._initialize_parameters(X, resp)\n+\n+    def _print_verbose_msg_init_beg(self, n_init):\n+        \"\"\"Print verbose message on initialization.\"\"\"\n+        if self.verbose == 1:\n+            print(\"Initialization %d\" % n_init)\n+        elif self.verbose == 2:\n+            print(\"Initialization %d\" % n_init)\n+            self._init_prev_time = time()\n+            self._iter_prev_time = self._init_prev_time\n+\n+    def _print_verbose_msg_iter_end(self, n_iter, diff_ll):\n+        \"\"\"Print verbose message on initialization.\"\"\"\n+        if n_iter % self.verbose_interval == 0:\n+            if self.verbose == 1:\n+                print(\"  Iteration %d\" % n_iter)\n+            elif self.verbose == 2:\n+                cur_time = time()\n+                print(\"  Iteration %d\\t time lapse %.5fs\\t ll change %.5f\" % (\n+                    n_iter, cur_time - self._iter_prev_time, diff_ll))\n+                self._iter_prev_time = cur_time\n+\n+    def _print_verbose_msg_init_end(self, ll):\n+        \"\"\"Print verbose message on the end of iteration.\"\"\"\n+        if self.verbose == 1:\n+            print(\"Initialization converged: %s\" % self.converged_)\n+        elif self.verbose == 2:\n+            print(\"Initialization converged: %s\\t time lapse %.5fs\\t ll %.5f\" %\n+                  (self.converged_, time() - self._init_prev_time, ll))\n+\n+    def _fit(self, X, y=None):\n+        \"\"\"Fit the model on data X.\n+\n+        The method fit the model `n_init` times and set the parameters with\n+        which the model has the largest likelihood or lower bound. Within each\n+        trial, the method iterates between E-step and M-step for `n_iter`\n+        times until the change of likelihood or lower bound less than `tol`,\n+        otherwise, a `ConvergenceWarning` is raised.\n+\n+        Parameters\n+        ----------\n+        X : array-like, shape = (n_samples, n_features)\n+\n+        Returns\n+        -------\n+        self\n+        \"\"\"\n+        X = check_X(X, self.n_components)\n+        self.n_features = X.shape[1]\n+        self._check_initial_parameters()\n+\n+        max_log_likelihood = -np.infty\n+        best_params = self._get_parameters()\n+\n+        if self.verbose > 10:\n+            self._log_snapshot = []\n+\n+        for init in range(self.n_init):\n+            # print verbose msg\n+            self._print_verbose_msg_init_beg(init)\n+\n+            self._initialize(X)\n+            current_log_likelihood = -np.infty\n+            self.converged_ = False\n+\n+            for i in range(self.n_iter):\n+                prev_log_likelihood = current_log_likelihood\n+\n+                # e step\n+                current_log_likelihood, resp = self._e_step(X)\n+                change = abs(current_log_likelihood - prev_log_likelihood)\n+\n+                # log the most verbose msg, debug only\n+                if self.verbose > 10:\n+                    self._snapshot(X)\n+                # print verbose msg\n+                self._print_verbose_msg_iter_end(i, change)\n+\n+                if change < self.tol:","path":"sklearn/mixture/base.py","position":365,"original_position":365,"commit_id":"5aa76c3b2a9f79a208968771995e9eaa9342ac0e","original_commit_id":"03f1fded524dd7295b5dc776cb22e4ae34fcd0ed","user":{"login":"superbobry","id":185856,"avatar_url":"https://avatars.githubusercontent.com/u/185856?v=3","gravatar_id":"","url":"https://api.github.com/users/superbobry","html_url":"https://github.com/superbobry","followers_url":"https://api.github.com/users/superbobry/followers","following_url":"https://api.github.com/users/superbobry/following{/other_user}","gists_url":"https://api.github.com/users/superbobry/gists{/gist_id}","starred_url":"https://api.github.com/users/superbobry/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/superbobry/subscriptions","organizations_url":"https://api.github.com/users/superbobry/orgs","repos_url":"https://api.github.com/users/superbobry/repos","events_url":"https://api.github.com/users/superbobry/events{/privacy}","received_events_url":"https://api.github.com/users/superbobry/received_events","type":"User","site_admin":false},"body":"Not necessarily. I'm experimenting with this approach in `hmmlearn`. Here's how the EM loop [looks](https://github.com/hmmlearn/hmmlearn/blob/master/hmmlearn/base.py#L418) in the current version:\r\n\r\n```python\r\nfor iter in range(self.n_iter):\r\n    curr_logprob = ...\r\n    # ...\r\n    self.monitor_.report(curr_logprob)\r\n    if self.monitor_.converged:\r\n        break\r\n```","created_at":"2015-08-18T18:47:22Z","updated_at":"2015-08-18T18:47:22Z","html_url":"https://github.com/scikit-learn/scikit-learn/pull/4802#discussion_r37337452","pull_request_url":"https://api.github.com/repos/scikit-learn/scikit-learn/pulls/4802","_links":{"self":{"href":"https://api.github.com/repos/scikit-learn/scikit-learn/pulls/comments/37337452"},"html":{"href":"https://github.com/scikit-learn/scikit-learn/pull/4802#discussion_r37337452"},"pull_request":{"href":"https://api.github.com/repos/scikit-learn/scikit-learn/pulls/4802"}}},"pull_request":{"url":"https://api.github.com/repos/scikit-learn/scikit-learn/pulls/4802","id":36740194,"html_url":"https://github.com/scikit-learn/scikit-learn/pull/4802","diff_url":"https://github.com/scikit-learn/scikit-learn/pull/4802.diff","patch_url":"https://github.com/scikit-learn/scikit-learn/pull/4802.patch","issue_url":"https://api.github.com/repos/scikit-learn/scikit-learn/issues/4802","number":4802,"state":"open","locked":false,"title":"[RFC] GSoC2015 Improve GMM API","user":{"login":"xuewei4d","id":1180956,"avatar_url":"https://avatars.githubusercontent.com/u/1180956?v=3","gravatar_id":"","url":"https://api.github.com/users/xuewei4d","html_url":"https://github.com/xuewei4d","followers_url":"https://api.github.com/users/xuewei4d/followers","following_url":"https://api.github.com/users/xuewei4d/following{/other_user}","gists_url":"https://api.github.com/users/xuewei4d/gists{/gist_id}","starred_url":"https://api.github.com/users/xuewei4d/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/xuewei4d/subscriptions","organizations_url":"https://api.github.com/users/xuewei4d/orgs","repos_url":"https://api.github.com/users/xuewei4d/repos","events_url":"https://api.github.com/users/xuewei4d/events{/privacy}","received_events_url":"https://api.github.com/users/xuewei4d/received_events","type":"User","site_admin":false},"body":"GSoC 2015 project,  Improve GMM API\r\n\r\n1. [x] Completes [derivation report](https://www.dropbox.com/s/8hlbb7dlwllwcry/VBGMM.pdf?dl=0).\r\n2. [x] Adds new classes. One abstract class ```_BasesMixture```. Three derived classes ```GaussianMixture```, ```BayesianGaussianMixture```, ```DirichletProcessGaussianMixture```\r\n3. [x] Decouples large functions, especially in ```DirichletProcessGaussianMixture``` and ```BayesianGaussianMixture```\r\n4. [x] Removes numerical stability fixes for HMM. It seems that whenever there is a numerical issue, the code always adds 10*EPS in the computation. I think in some cases there is a better way to address the problem, such as normalization the extremely small variables earlier, or we just simply remove ```10*EPS``` which is only for HMM.\r\n5. [x] Writes updating functions for ```BayesianGaussianMixtureModel``` and ```DirichletProcessGaussianMixtureModel``` according to the report.\r\n6. [x] Provides methods that allow users to initialize the model with user-provided data\r\n7. [x] Corrects kmeans initialization. It is weird when using kmeans initialization, only means is initialized. The weights and covariances are initialized by averaging.\r\n8. [x] Writes several checking functions for the initialization data\r\n9. [x] Adjusts the verbose messages. When ```verbose>1```, it display log-likelihood and time used in the same line of the message ```Iteration x```\r\n10. [x] Remove ```fit_predict```\r\n11. [x] Adds warning for ```params!='wmc'```\r\n12. [ ] Studies and contrasts the convergence of classical MLE / EM GMM with Bayesian GMM against the number of samples and the number of components\r\n13. [x] Friendly warning and error messages, or automatically addressing if possible (e.g. random re-init of singular components)\r\n14. [ ] Examples that shows how models can over-fit by comparing likelihood on training and validation sets (normalized by\r\nthe number of samples). For instance extend the BIC score example with a cross-validated likelihood plot\r\n15. [x] Testing on 1-D dimensions\r\n16. [x] Testing on Degenerating cases\r\n17. [optional] add a partial_fit function for incremental / out-of-core fitting of (classical) GMM, for instance http://arxiv.org/abs/0712.4273 \r\n18. [optional] ledoit_wolf covariance estimation","created_at":"2015-06-02T15:18:15Z","updated_at":"2015-08-18T18:47:22Z","closed_at":null,"merged_at":null,"merge_commit_sha":"42fac52ed8fed3cfee5f22b5043e2083adce364c","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/scikit-learn/scikit-learn/pulls/4802/commits","review_comments_url":"https://api.github.com/repos/scikit-learn/scikit-learn/pulls/4802/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/4802/comments","statuses_url":"https://api.github.com/repos/scikit-learn/scikit-learn/statuses/5aa76c3b2a9f79a208968771995e9eaa9342ac0e","head":{"label":"xuewei4d:gmm_api","ref":"gmm_api","sha":"5aa76c3b2a9f79a208968771995e9eaa9342ac0e","user":{"login":"xuewei4d","id":1180956,"avatar_url":"https://avatars.githubusercontent.com/u/1180956?v=3","gravatar_id":"","url":"https://api.github.com/users/xuewei4d","html_url":"https://github.com/xuewei4d","followers_url":"https://api.github.com/users/xuewei4d/followers","following_url":"https://api.github.com/users/xuewei4d/following{/other_user}","gists_url":"https://api.github.com/users/xuewei4d/gists{/gist_id}","starred_url":"https://api.github.com/users/xuewei4d/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/xuewei4d/subscriptions","organizations_url":"https://api.github.com/users/xuewei4d/orgs","repos_url":"https://api.github.com/users/xuewei4d/repos","events_url":"https://api.github.com/users/xuewei4d/events{/privacy}","received_events_url":"https://api.github.com/users/xuewei4d/received_events","type":"User","site_admin":false},"repo":{"id":31241818,"name":"scikit-learn","full_name":"xuewei4d/scikit-learn","owner":{"login":"xuewei4d","id":1180956,"avatar_url":"https://avatars.githubusercontent.com/u/1180956?v=3","gravatar_id":"","url":"https://api.github.com/users/xuewei4d","html_url":"https://github.com/xuewei4d","followers_url":"https://api.github.com/users/xuewei4d/followers","following_url":"https://api.github.com/users/xuewei4d/following{/other_user}","gists_url":"https://api.github.com/users/xuewei4d/gists{/gist_id}","starred_url":"https://api.github.com/users/xuewei4d/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/xuewei4d/subscriptions","organizations_url":"https://api.github.com/users/xuewei4d/orgs","repos_url":"https://api.github.com/users/xuewei4d/repos","events_url":"https://api.github.com/users/xuewei4d/events{/privacy}","received_events_url":"https://api.github.com/users/xuewei4d/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/xuewei4d/scikit-learn","description":"scikit-learn: machine learning in Python","fork":true,"url":"https://api.github.com/repos/xuewei4d/scikit-learn","forks_url":"https://api.github.com/repos/xuewei4d/scikit-learn/forks","keys_url":"https://api.github.com/repos/xuewei4d/scikit-learn/keys{/key_id}","collaborators_url":"https://api.github.com/repos/xuewei4d/scikit-learn/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/xuewei4d/scikit-learn/teams","hooks_url":"https://api.github.com/repos/xuewei4d/scikit-learn/hooks","issue_events_url":"https://api.github.com/repos/xuewei4d/scikit-learn/issues/events{/number}","events_url":"https://api.github.com/repos/xuewei4d/scikit-learn/events","assignees_url":"https://api.github.com/repos/xuewei4d/scikit-learn/assignees{/user}","branches_url":"https://api.github.com/repos/xuewei4d/scikit-learn/branches{/branch}","tags_url":"https://api.github.com/repos/xuewei4d/scikit-learn/tags","blobs_url":"https://api.github.com/repos/xuewei4d/scikit-learn/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/xuewei4d/scikit-learn/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/xuewei4d/scikit-learn/git/refs{/sha}","trees_url":"https://api.github.com/repos/xuewei4d/scikit-learn/git/trees{/sha}","statuses_url":"https://api.github.com/repos/xuewei4d/scikit-learn/statuses/{sha}","languages_url":"https://api.github.com/repos/xuewei4d/scikit-learn/languages","stargazers_url":"https://api.github.com/repos/xuewei4d/scikit-learn/stargazers","contributors_url":"https://api.github.com/repos/xuewei4d/scikit-learn/contributors","subscribers_url":"https://api.github.com/repos/xuewei4d/scikit-learn/subscribers","subscription_url":"https://api.github.com/repos/xuewei4d/scikit-learn/subscription","commits_url":"https://api.github.com/repos/xuewei4d/scikit-learn/commits{/sha}","git_commits_url":"https://api.github.com/repos/xuewei4d/scikit-learn/git/commits{/sha}","comments_url":"https://api.github.com/repos/xuewei4d/scikit-learn/comments{/number}","issue_comment_url":"https://api.github.com/repos/xuewei4d/scikit-learn/issues/comments{/number}","contents_url":"https://api.github.com/repos/xuewei4d/scikit-learn/contents/{+path}","compare_url":"https://api.github.com/repos/xuewei4d/scikit-learn/compare/{base}...{head}","merges_url":"https://api.github.com/repos/xuewei4d/scikit-learn/merges","archive_url":"https://api.github.com/repos/xuewei4d/scikit-learn/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/xuewei4d/scikit-learn/downloads","issues_url":"https://api.github.com/repos/xuewei4d/scikit-learn/issues{/number}","pulls_url":"https://api.github.com/repos/xuewei4d/scikit-learn/pulls{/number}","milestones_url":"https://api.github.com/repos/xuewei4d/scikit-learn/milestones{/number}","notifications_url":"https://api.github.com/repos/xuewei4d/scikit-learn/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/xuewei4d/scikit-learn/labels{/name}","releases_url":"https://api.github.com/repos/xuewei4d/scikit-learn/releases{/id}","created_at":"2015-02-24T02:43:56Z","updated_at":"2015-05-07T14:11:26Z","pushed_at":"2015-08-18T18:21:36Z","git_url":"git://github.com/xuewei4d/scikit-learn.git","ssh_url":"git@github.com:xuewei4d/scikit-learn.git","clone_url":"https://github.com/xuewei4d/scikit-learn.git","svn_url":"https://github.com/xuewei4d/scikit-learn","homepage":"http://scikit-learn.org","size":65500,"stargazers_count":0,"watchers_count":0,"language":"Python","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":1,"forks":0,"open_issues":1,"watchers":0,"default_branch":"master"}},"base":{"label":"scikit-learn:master","ref":"master","sha":"89ddbe26a7595e3a8643e31661eb51b90b77f49a","user":{"login":"scikit-learn","id":365630,"avatar_url":"https://avatars.githubusercontent.com/u/365630?v=3","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://avatars.githubusercontent.com/u/365630?v=3","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}","created_at":"2010-08-17T09:43:38Z","updated_at":"2015-08-18T18:24:15Z","pushed_at":"2015-08-18T18:21:42Z","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":131194,"stargazers_count":7208,"watchers_count":7208,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":4259,"mirror_url":null,"open_issues_count":764,"forks":4259,"open_issues":764,"watchers":7208,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/scikit-learn/scikit-learn/pulls/4802"},"html":{"href":"https://github.com/scikit-learn/scikit-learn/pull/4802"},"issue":{"href":"https://api.github.com/repos/scikit-learn/scikit-learn/issues/4802"},"comments":{"href":"https://api.github.com/repos/scikit-learn/scikit-learn/issues/4802/comments"},"review_comments":{"href":"https://api.github.com/repos/scikit-learn/scikit-learn/pulls/4802/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/4802/commits"},"statuses":{"href":"https://api.github.com/repos/scikit-learn/scikit-learn/statuses/5aa76c3b2a9f79a208968771995e9eaa9342ac0e"}}}}