{"action":"created","comment":{"url":"https://api.github.com/repos/haifengl/smile/pulls/comments/226049090","pull_request_review_id":165778726,"id":226049090,"node_id":"MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDIyNjA0OTA5MA==","diff_hunk":"@@ -0,0 +1,178 @@\n+/*******************************************************************************\n+ * Copyright (c) 2010 Haifeng Li\n+ *\n+ * Licensed under the Apache License, Version 2.0 (the \"License\");\n+ * you may not use this file except in compliance with the License.\n+ * You may obtain a copy of the License at\n+ *\n+ *     http://www.apache.org/licenses/LICENSE-2.0\n+ *\n+ * Unless required by applicable law or agreed to in writing, software\n+ * distributed under the License is distributed on an \"AS IS\" BASIS,\n+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n+ * See the License for the specific language governing permissions and\n+ * limitations under the License.\n+ *******************************************************************************/\n+\n+package smile.classification;\n+\n+import java.io.Serializable;\n+import java.util.Arrays;\n+\n+import smile.sort.QuickSort;\n+\n+/**\n+ * An alternative approach to probability calibration is to fit an isotonic\n+ * regression model to an ill-calibrated probability model. This has been shown\n+ * to work better than Platt scaling, in particular when enough training data is\n+ * available.\n+ * \n+ * <h2>References</h2>\n+ * <ol>\n+ * <li>Niculescu-Mizil, Alexandru; Caruana, Rich: Predicting Good Probabilities\n+ * With Supervised Learning, 2005.</li>\n+ * </ol>\n+ *\n+ * @author rayeaster\n+ */\n+public class IsotonicRegressionScaling implements Serializable {\n+    private static final long serialVersionUID = 1L;\n+\n+    /** setep-wise constant functions */\n+    private static class StepwiseConsFunc {\n+        double lowScore;\n+        double highScore;\n+        double val;\n+        int weight = 1;\n+\n+        StepwiseConsFunc next;\n+        StepwiseConsFunc previous;\n+\n+        StepwiseConsFunc(double lowScore, double highScore, double val) {\n+            this.lowScore = lowScore;\n+            this.highScore = highScore;\n+            this.val = val;\n+        }\n+\n+        void setNext(StepwiseConsFunc next) {\n+            this.next = next;\n+        }\n+\n+        void setPrevious(StepwiseConsFunc previous) {\n+            this.previous = previous;\n+        }\n+\n+        public int getWeight() {\n+            return weight;\n+        }\n+\n+        public void setWeight(int weight) {\n+            this.weight = weight;\n+        }\n+\n+        boolean matchValue(double score) {\n+            if (score > lowScore && score <= highScore) {\n+                return true;\n+            } else {\n+                return false;\n+            }\n+        }\n+\n+        double getVal() {\n+            return this.val;\n+        }\n+    }\n+\n+    private StepwiseConsFunc startConstantFuncs;\n+\n+    /**\n+     * Trains the Isotonic Regression scaling.\n+     * \n+     * @param scores\n+     *            The predicted scores.\n+     * @param y\n+     *            The training labels.\n+     */\n+    public IsotonicRegressionScaling(double[] scores, int[] y) {\n+        initStepwiseConstFuncs(scores, y);\n+\n+        StepwiseConsFunc current = startConstantFuncs.next;\n+\n+        while (current != null) {\n+            StepwiseConsFunc previous = current.previous;\n+            while (previous != null) {\n+                if (previous.getVal() >= current.getVal()) {\n+                    int weight = previous.getWeight() + current.getWeight();\n+                    double val = (previous.getWeight() * previous.getVal() + current.getWeight() * current.getVal())\n+                            / weight;\n+                    StepwiseConsFunc newFunc = new StepwiseConsFunc(previous.lowScore, current.highScore, val);\n+                    newFunc.setWeight(weight);\n+\n+                    newFunc.next = current.next;\n+                    if (newFunc.next != null) {\n+                        newFunc.next.previous = newFunc;\n+                    }\n+\n+                    newFunc.previous = previous.previous;\n+                    if (newFunc.previous != null) {\n+                        newFunc.previous.next = newFunc;\n+                    }\n+\n+                    current = newFunc;\n+                    previous = current.previous;\n+                } else {\n+                    previous = previous.previous;\n+                }\n+            }\n+            current = current.next;\n+        }\n+    }\n+\n+    private void initStepwiseConstFuncs(double[] scores, int[] y) {\n+        double[] sortedScores = Arrays.copyOf(scores, scores.length);\n+        int[] sortedY = Arrays.copyOf(y, y.length);\n+\n+        QuickSort.sort(sortedScores, sortedY, sortedScores.length);\n+\n+        StepwiseConsFunc previous = new StepwiseConsFunc(sortedScores[0], sortedScores[0], (double) sortedY[0]);\n+        startConstantFuncs = previous;\n+\n+        for (int i = 1; i < sortedScores.length; i++) {\n+            StepwiseConsFunc init = new StepwiseConsFunc(sortedScores[i], sortedScores[i], (double) sortedY[i]);\n+            init.setPrevious(previous);\n+            previous.setNext(init);\n+            previous = init;\n+        }\n+    }\n+\n+    /**\n+     * Returns the posterior probability estimate P(y = 1 | x).\n+     *\n+     * @param y\n+     *            the binary classifier output score.\n+     * @return the estimated probability.\n+     */\n+    public double predict(double y) {\n+        double ret = Double.NaN;\n+        StepwiseConsFunc func = startConstantFuncs;\n+        while (func != null) {\n+            if (func.matchValue(y)) {\n+                ret = func.getVal();\n+                break;\n+            }\n+            func = func.next;\n+        }\n+        if (ret == Double.NaN) {\n+            throw new IllegalArgumentException(\"fail to get the posteriori probability for given prediction: \" + y);\n+        }\n+        return ret;\n+    }\n+\n+    /**\n+     * Estimates the multiclass probabilies.\n+     */\n+    public static void multiclass(int k, double[][] r, double[] p) {\n+        PlattScaling.multiclass(k, r, p);","path":"core/src/main/java/smile/classification/IsotonicRegressionScaling.java","position":175,"original_position":175,"commit_id":"8eb1e419222d1331aae7c02739ec0a6b5c0e490a","original_commit_id":"8eb1e419222d1331aae7c02739ec0a6b5c0e490a","user":{"login":"haifengl","id":5502052,"node_id":"MDQ6VXNlcjU1MDIwNTI=","avatar_url":"https://avatars3.githubusercontent.com/u/5502052?v=4","gravatar_id":"","url":"https://api.github.com/users/haifengl","html_url":"https://github.com/haifengl","followers_url":"https://api.github.com/users/haifengl/followers","following_url":"https://api.github.com/users/haifengl/following{/other_user}","gists_url":"https://api.github.com/users/haifengl/gists{/gist_id}","starred_url":"https://api.github.com/users/haifengl/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/haifengl/subscriptions","organizations_url":"https://api.github.com/users/haifengl/orgs","repos_url":"https://api.github.com/users/haifengl/repos","events_url":"https://api.github.com/users/haifengl/events{/privacy}","received_events_url":"https://api.github.com/users/haifengl/received_events","type":"User","site_admin":false},"body":"Can we do this? Do you have a reference?","created_at":"2018-10-17T18:37:06Z","updated_at":"2018-10-17T18:41:58Z","html_url":"https://github.com/haifengl/smile/pull/356#discussion_r226049090","pull_request_url":"https://api.github.com/repos/haifengl/smile/pulls/356","author_association":"OWNER","_links":{"self":{"href":"https://api.github.com/repos/haifengl/smile/pulls/comments/226049090"},"html":{"href":"https://github.com/haifengl/smile/pull/356#discussion_r226049090"},"pull_request":{"href":"https://api.github.com/repos/haifengl/smile/pulls/356"}}},"pull_request":{"url":"https://api.github.com/repos/haifengl/smile/pulls/356","id":213575021,"node_id":"MDExOlB1bGxSZXF1ZXN0MjEzNTc1MDIx","html_url":"https://github.com/haifengl/smile/pull/356","diff_url":"https://github.com/haifengl/smile/pull/356.diff","patch_url":"https://github.com/haifengl/smile/pull/356.patch","issue_url":"https://api.github.com/repos/haifengl/smile/issues/356","number":356,"state":"open","locked":false,"title":"add isotonic regression scaling to SVM","user":{"login":"rayeaster","id":1487283,"node_id":"MDQ6VXNlcjE0ODcyODM=","avatar_url":"https://avatars0.githubusercontent.com/u/1487283?v=4","gravatar_id":"","url":"https://api.github.com/users/rayeaster","html_url":"https://github.com/rayeaster","followers_url":"https://api.github.com/users/rayeaster/followers","following_url":"https://api.github.com/users/rayeaster/following{/other_user}","gists_url":"https://api.github.com/users/rayeaster/gists{/gist_id}","starred_url":"https://api.github.com/users/rayeaster/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rayeaster/subscriptions","organizations_url":"https://api.github.com/users/rayeaster/orgs","repos_url":"https://api.github.com/users/rayeaster/repos","events_url":"https://api.github.com/users/rayeaster/events{/privacy}","received_events_url":"https://api.github.com/users/rayeaster/received_events","type":"User","site_admin":false},"body":"https://github.com/haifengl/smile/issues/354","created_at":"2018-09-06T10:50:29Z","updated_at":"2018-10-17T18:41:58Z","closed_at":null,"merged_at":null,"merge_commit_sha":"15e0908f1d7976c4ff1f32f9a548ae4bc70907d2","assignee":null,"assignees":[],"requested_reviewers":[],"requested_teams":[],"labels":[{"id":722522908,"node_id":"MDU6TGFiZWw3MjI1MjI5MDg=","url":"https://api.github.com/repos/haifengl/smile/labels/new%20feature","name":"new feature","color":"006b75","default":false}],"milestone":null,"commits_url":"https://api.github.com/repos/haifengl/smile/pulls/356/commits","review_comments_url":"https://api.github.com/repos/haifengl/smile/pulls/356/comments","review_comment_url":"https://api.github.com/repos/haifengl/smile/pulls/comments{/number}","comments_url":"https://api.github.com/repos/haifengl/smile/issues/356/comments","statuses_url":"https://api.github.com/repos/haifengl/smile/statuses/8eb1e419222d1331aae7c02739ec0a6b5c0e490a","head":{"label":"rayeaster:isoreg","ref":"isoreg","sha":"8eb1e419222d1331aae7c02739ec0a6b5c0e490a","user":{"login":"rayeaster","id":1487283,"node_id":"MDQ6VXNlcjE0ODcyODM=","avatar_url":"https://avatars0.githubusercontent.com/u/1487283?v=4","gravatar_id":"","url":"https://api.github.com/users/rayeaster","html_url":"https://github.com/rayeaster","followers_url":"https://api.github.com/users/rayeaster/followers","following_url":"https://api.github.com/users/rayeaster/following{/other_user}","gists_url":"https://api.github.com/users/rayeaster/gists{/gist_id}","starred_url":"https://api.github.com/users/rayeaster/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rayeaster/subscriptions","organizations_url":"https://api.github.com/users/rayeaster/orgs","repos_url":"https://api.github.com/users/rayeaster/repos","events_url":"https://api.github.com/users/rayeaster/events{/privacy}","received_events_url":"https://api.github.com/users/rayeaster/received_events","type":"User","site_admin":false},"repo":{"id":131963268,"node_id":"MDEwOlJlcG9zaXRvcnkxMzE5NjMyNjg=","name":"smile","full_name":"rayeaster/smile","private":false,"owner":{"login":"rayeaster","id":1487283,"node_id":"MDQ6VXNlcjE0ODcyODM=","avatar_url":"https://avatars0.githubusercontent.com/u/1487283?v=4","gravatar_id":"","url":"https://api.github.com/users/rayeaster","html_url":"https://github.com/rayeaster","followers_url":"https://api.github.com/users/rayeaster/followers","following_url":"https://api.github.com/users/rayeaster/following{/other_user}","gists_url":"https://api.github.com/users/rayeaster/gists{/gist_id}","starred_url":"https://api.github.com/users/rayeaster/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rayeaster/subscriptions","organizations_url":"https://api.github.com/users/rayeaster/orgs","repos_url":"https://api.github.com/users/rayeaster/repos","events_url":"https://api.github.com/users/rayeaster/events{/privacy}","received_events_url":"https://api.github.com/users/rayeaster/received_events","type":"User","site_admin":false},"html_url":"https://github.com/rayeaster/smile","description":"Statistical Machine Intelligence & Learning Engine","fork":true,"url":"https://api.github.com/repos/rayeaster/smile","forks_url":"https://api.github.com/repos/rayeaster/smile/forks","keys_url":"https://api.github.com/repos/rayeaster/smile/keys{/key_id}","collaborators_url":"https://api.github.com/repos/rayeaster/smile/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/rayeaster/smile/teams","hooks_url":"https://api.github.com/repos/rayeaster/smile/hooks","issue_events_url":"https://api.github.com/repos/rayeaster/smile/issues/events{/number}","events_url":"https://api.github.com/repos/rayeaster/smile/events","assignees_url":"https://api.github.com/repos/rayeaster/smile/assignees{/user}","branches_url":"https://api.github.com/repos/rayeaster/smile/branches{/branch}","tags_url":"https://api.github.com/repos/rayeaster/smile/tags","blobs_url":"https://api.github.com/repos/rayeaster/smile/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/rayeaster/smile/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/rayeaster/smile/git/refs{/sha}","trees_url":"https://api.github.com/repos/rayeaster/smile/git/trees{/sha}","statuses_url":"https://api.github.com/repos/rayeaster/smile/statuses/{sha}","languages_url":"https://api.github.com/repos/rayeaster/smile/languages","stargazers_url":"https://api.github.com/repos/rayeaster/smile/stargazers","contributors_url":"https://api.github.com/repos/rayeaster/smile/contributors","subscribers_url":"https://api.github.com/repos/rayeaster/smile/subscribers","subscription_url":"https://api.github.com/repos/rayeaster/smile/subscription","commits_url":"https://api.github.com/repos/rayeaster/smile/commits{/sha}","git_commits_url":"https://api.github.com/repos/rayeaster/smile/git/commits{/sha}","comments_url":"https://api.github.com/repos/rayeaster/smile/comments{/number}","issue_comment_url":"https://api.github.com/repos/rayeaster/smile/issues/comments{/number}","contents_url":"https://api.github.com/repos/rayeaster/smile/contents/{+path}","compare_url":"https://api.github.com/repos/rayeaster/smile/compare/{base}...{head}","merges_url":"https://api.github.com/repos/rayeaster/smile/merges","archive_url":"https://api.github.com/repos/rayeaster/smile/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/rayeaster/smile/downloads","issues_url":"https://api.github.com/repos/rayeaster/smile/issues{/number}","pulls_url":"https://api.github.com/repos/rayeaster/smile/pulls{/number}","milestones_url":"https://api.github.com/repos/rayeaster/smile/milestones{/number}","notifications_url":"https://api.github.com/repos/rayeaster/smile/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/rayeaster/smile/labels{/name}","releases_url":"https://api.github.com/repos/rayeaster/smile/releases{/id}","deployments_url":"https://api.github.com/repos/rayeaster/smile/deployments","created_at":"2018-05-03T08:14:22Z","updated_at":"2018-05-07T02:01:06Z","pushed_at":"2018-10-16T09:23:52Z","git_url":"git://github.com/rayeaster/smile.git","ssh_url":"git@github.com:rayeaster/smile.git","clone_url":"https://github.com/rayeaster/smile.git","svn_url":"https://github.com/rayeaster/smile","homepage":"http://haifengl.github.io/smile/","size":163644,"stargazers_count":0,"watchers_count":0,"language":"Java","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"archived":false,"open_issues_count":0,"license":{"key":"apache-2.0","name":"Apache License 2.0","spdx_id":"Apache-2.0","url":"https://api.github.com/licenses/apache-2.0","node_id":"MDc6TGljZW5zZTI="},"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"haifengl:master","ref":"master","sha":"68082b47d132b7783bf1c0b80e5bfff13458c899","user":{"login":"haifengl","id":5502052,"node_id":"MDQ6VXNlcjU1MDIwNTI=","avatar_url":"https://avatars3.githubusercontent.com/u/5502052?v=4","gravatar_id":"","url":"https://api.github.com/users/haifengl","html_url":"https://github.com/haifengl","followers_url":"https://api.github.com/users/haifengl/followers","following_url":"https://api.github.com/users/haifengl/following{/other_user}","gists_url":"https://api.github.com/users/haifengl/gists{/gist_id}","starred_url":"https://api.github.com/users/haifengl/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/haifengl/subscriptions","organizations_url":"https://api.github.com/users/haifengl/orgs","repos_url":"https://api.github.com/users/haifengl/repos","events_url":"https://api.github.com/users/haifengl/events{/privacy}","received_events_url":"https://api.github.com/users/haifengl/received_events","type":"User","site_admin":false},"repo":{"id":26921116,"node_id":"MDEwOlJlcG9zaXRvcnkyNjkyMTExNg==","name":"smile","full_name":"haifengl/smile","private":false,"owner":{"login":"haifengl","id":5502052,"node_id":"MDQ6VXNlcjU1MDIwNTI=","avatar_url":"https://avatars3.githubusercontent.com/u/5502052?v=4","gravatar_id":"","url":"https://api.github.com/users/haifengl","html_url":"https://github.com/haifengl","followers_url":"https://api.github.com/users/haifengl/followers","following_url":"https://api.github.com/users/haifengl/following{/other_user}","gists_url":"https://api.github.com/users/haifengl/gists{/gist_id}","starred_url":"https://api.github.com/users/haifengl/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/haifengl/subscriptions","organizations_url":"https://api.github.com/users/haifengl/orgs","repos_url":"https://api.github.com/users/haifengl/repos","events_url":"https://api.github.com/users/haifengl/events{/privacy}","received_events_url":"https://api.github.com/users/haifengl/received_events","type":"User","site_admin":false},"html_url":"https://github.com/haifengl/smile","description":"Statistical Machine Intelligence & Learning Engine","fork":false,"url":"https://api.github.com/repos/haifengl/smile","forks_url":"https://api.github.com/repos/haifengl/smile/forks","keys_url":"https://api.github.com/repos/haifengl/smile/keys{/key_id}","collaborators_url":"https://api.github.com/repos/haifengl/smile/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/haifengl/smile/teams","hooks_url":"https://api.github.com/repos/haifengl/smile/hooks","issue_events_url":"https://api.github.com/repos/haifengl/smile/issues/events{/number}","events_url":"https://api.github.com/repos/haifengl/smile/events","assignees_url":"https://api.github.com/repos/haifengl/smile/assignees{/user}","branches_url":"https://api.github.com/repos/haifengl/smile/branches{/branch}","tags_url":"https://api.github.com/repos/haifengl/smile/tags","blobs_url":"https://api.github.com/repos/haifengl/smile/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/haifengl/smile/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/haifengl/smile/git/refs{/sha}","trees_url":"https://api.github.com/repos/haifengl/smile/git/trees{/sha}","statuses_url":"https://api.github.com/repos/haifengl/smile/statuses/{sha}","languages_url":"https://api.github.com/repos/haifengl/smile/languages","stargazers_url":"https://api.github.com/repos/haifengl/smile/stargazers","contributors_url":"https://api.github.com/repos/haifengl/smile/contributors","subscribers_url":"https://api.github.com/repos/haifengl/smile/subscribers","subscription_url":"https://api.github.com/repos/haifengl/smile/subscription","commits_url":"https://api.github.com/repos/haifengl/smile/commits{/sha}","git_commits_url":"https://api.github.com/repos/haifengl/smile/git/commits{/sha}","comments_url":"https://api.github.com/repos/haifengl/smile/comments{/number}","issue_comment_url":"https://api.github.com/repos/haifengl/smile/issues/comments{/number}","contents_url":"https://api.github.com/repos/haifengl/smile/contents/{+path}","compare_url":"https://api.github.com/repos/haifengl/smile/compare/{base}...{head}","merges_url":"https://api.github.com/repos/haifengl/smile/merges","archive_url":"https://api.github.com/repos/haifengl/smile/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/haifengl/smile/downloads","issues_url":"https://api.github.com/repos/haifengl/smile/issues{/number}","pulls_url":"https://api.github.com/repos/haifengl/smile/pulls{/number}","milestones_url":"https://api.github.com/repos/haifengl/smile/milestones{/number}","notifications_url":"https://api.github.com/repos/haifengl/smile/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/haifengl/smile/labels{/name}","releases_url":"https://api.github.com/repos/haifengl/smile/releases{/id}","deployments_url":"https://api.github.com/repos/haifengl/smile/deployments","created_at":"2014-11-20T16:28:12Z","updated_at":"2018-10-17T14:55:40Z","pushed_at":"2018-10-17T01:50:57Z","git_url":"git://github.com/haifengl/smile.git","ssh_url":"git@github.com:haifengl/smile.git","clone_url":"https://github.com/haifengl/smile.git","svn_url":"https://github.com/haifengl/smile","homepage":"http://haifengl.github.io/smile/","size":163846,"stargazers_count":4013,"watchers_count":4013,"language":"Java","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":770,"mirror_url":null,"archived":false,"open_issues_count":26,"license":{"key":"apache-2.0","name":"Apache License 2.0","spdx_id":"Apache-2.0","url":"https://api.github.com/licenses/apache-2.0","node_id":"MDc6TGljZW5zZTI="},"forks":770,"open_issues":26,"watchers":4013,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/haifengl/smile/pulls/356"},"html":{"href":"https://github.com/haifengl/smile/pull/356"},"issue":{"href":"https://api.github.com/repos/haifengl/smile/issues/356"},"comments":{"href":"https://api.github.com/repos/haifengl/smile/issues/356/comments"},"review_comments":{"href":"https://api.github.com/repos/haifengl/smile/pulls/356/comments"},"review_comment":{"href":"https://api.github.com/repos/haifengl/smile/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/haifengl/smile/pulls/356/commits"},"statuses":{"href":"https://api.github.com/repos/haifengl/smile/statuses/8eb1e419222d1331aae7c02739ec0a6b5c0e490a"}},"author_association":"CONTRIBUTOR"}}
{"actor":{"display_login":"haifengl"}}