{"action":"created","comment":{"url":"https://api.github.com/repos/gonum/stat/pulls/comments/57832910","id":57832910,"diff_hunk":"@@ -0,0 +1,136 @@\n+// Copyright ©2016 The gonum Authors. All rights reserved.\n+// Use of this source code is governed by a BSD-style\n+// license that can be found in the LICENSE file.\n+\n+package stat\n+\n+import \"sort\"\n+\n+// ROC returns paired false positive rate (FPR) and true\n+// positive rate (TPR) values corresponding to n\n+// cutoffs spanning the relative (or receiver)\n+// operator characteristic (ROC) curve obtained when y is\n+// treated as a binary classifier for classes with weights.\n+// Cutoffs are equally spaced from eps less than the minimum value of y\n+// to the maximum value of y, including both endpoints -- this means the\n+// resulting ROC curve will always begin at (0,0) and end at (1,1).\n+// input y must be sorted, and SortWeightedLabelled can be used\n+// in order to sort data y together with classes and weights.\n+// For a given cutoff value, observations corresponding to\n+// entries in y greater than the cutoff are classified as\n+// false, and these assigned class labels are compared to\n+// classes to calculate FPR and TPR.\n+// weights being nil results in the unweighted case.\n+// n of zero results in all possible cutoffs being calculated.\n+// More details about ROC curves are available at\n+// https://en.wikipedia.org/wiki/Receiver_operating_characteristic\n+func ROC(n int, y []float64, classes []bool, weights []float64) (tpr, fpr []float64) {\n+\tif len(y) != len(classes) {\n+\t\tpanic(\"stat: slice length mismatch\")\n+\t}\n+\tif !sort.IsSorted(sort.Float64Slice(y)) {\n+\t\tpanic(\"stat: input must be sorted\")\n+\t}\n+\n+\tvar iw, tol float64\n+\tif n != 0 {\n+\t\tif n < 2 {\n+\t\t\tpanic(\"stat: cannot less than 2 points on a ROC curve\")\n+\t\t}\n+\t\tiw = (y[len(y)-1] - y[0]) / float64(n-1)\n+\t\tif iw <= 0 {\n+\t\t\tpanic(\"stat: y constant or not sorted\")\n+\t\t}\n+\t\ttol = y[0] + iw\n+\t}\n+\n+\tif n > (len(y) + 1) {\n+\t\ttpr = make([]float64, n)\n+\t\tfpr = make([]float64, n)\n+\t} else {\n+\t\ttpr = make([]float64, len(y)+1)\n+\t\tfpr = make([]float64, len(y)+1)\n+\t}\n+\tnewEntry := true\n+\tvar j int\n+\tvar nPositive, nNegative float64\n+\tfor i, u := range classes {\n+\t\tif weights == nil {\n+\t\t\t// unweighted case\n+\t\t\tif u {\n+\t\t\t\tnPositive++\n+\t\t\t\tif newEntry {\n+\t\t\t\t\tnewEntry = false\n+\t\t\t\t\ttpr[j+1] = tpr[j] + 1\n+\t\t\t\t\tfpr[j+1] = fpr[j]\n+\t\t\t\t} else {\n+\t\t\t\t\ttpr[j+1]++\n+\t\t\t\t}\n+\t\t\t} else {\n+\t\t\t\tif newEntry {\n+\t\t\t\t\tnewEntry = false\n+\t\t\t\t\ttpr[j+1] = tpr[j]\n+\t\t\t\t\tfpr[j+1] = fpr[j] + 1\n+\t\t\t\t} else {\n+\t\t\t\t\tfpr[j+1]++\n+\t\t\t\t}\n+\t\t\t}\n+\t\t} else {\n+\t\t\t// weighted case\n+\t\t\tif u {\n+\t\t\t\tnPositive += weights[i]\n+\t\t\t\tif newEntry {\n+\t\t\t\t\tnewEntry = false\n+\t\t\t\t\ttpr[j+1] = tpr[j] + weights[i]\n+\t\t\t\t\tfpr[j+1] = fpr[j]\n+\t\t\t\t} else {\n+\t\t\t\t\ttpr[j+1] += weights[i]\n+\t\t\t\t}\n+\t\t\t} else {\n+\t\t\t\tnNegative += weights[i]\n+\t\t\t\tif newEntry {\n+\t\t\t\t\tnewEntry = false\n+\t\t\t\t\ttpr[j+1] = tpr[j]\n+\t\t\t\t\tfpr[j+1] = fpr[j] + weights[i]\n+\t\t\t\t} else {\n+\t\t\t\t\tfpr[j+1] += weights[i]\n+\t\t\t\t}\n+\t\t\t}\n+\t\t}\n+\t\tif i != (len(y) - 1) {\n+\t\t\tif n == 0 {\n+\t\t\t\tif y[i] != y[i+1] {\n+\t\t\t\t\tj++\n+\t\t\t\t\tnewEntry = true\n+\t\t\t\t}\n+\t\t\t} else {\n+\t\t\t\tif y[i+1] > tol {\n+\t\t\t\t\tnewEntry = true\n+\t\t\t\t\ttol += iw\n+\t\t\t\t\tj++\n+\t\t\t\t\tfor y[i+1] > tol {\n+\t\t\t\t\t\ttpr[j+1] = tpr[j]\n+\t\t\t\t\t\tfpr[j+1] = fpr[j]\n+\t\t\t\t\t\ttol += iw\n+\t\t\t\t\t\tj++\n+\t\t\t\t\t}\n+\t\t\t\t}\n+\t\t\t}\n+\t\t}\n+\n+\t}\n+\tif weights == nil {\n+\t\tnNegative = 1 / (float64(len(y)) - nPositive)\n+\t} else {\n+\t\tnNegative = 1 / nNegative\n+\t}\n+\tnPositive = 1 / nPositive","path":"roc.go","position":127,"original_position":127,"commit_id":"6f0006de4bf6ef856014d32da6174186aa6bb306","original_commit_id":"6f0006de4bf6ef856014d32da6174186aa6bb306","user":{"login":"kortschak","id":275221,"avatar_url":"https://avatars.githubusercontent.com/u/275221?v=3","gravatar_id":"","url":"https://api.github.com/users/kortschak","html_url":"https://github.com/kortschak","followers_url":"https://api.github.com/users/kortschak/followers","following_url":"https://api.github.com/users/kortschak/following{/other_user}","gists_url":"https://api.github.com/users/kortschak/gists{/gist_id}","starred_url":"https://api.github.com/users/kortschak/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/kortschak/subscriptions","organizations_url":"https://api.github.com/users/kortschak/orgs","repos_url":"https://api.github.com/users/kortschak/repos","events_url":"https://api.github.com/users/kortschak/events{/privacy}","received_events_url":"https://api.github.com/users/kortschak/received_events","type":"User","site_admin":false},"body":"This is my approach. Division is more costly that multiplication - in this case is probably doesn't make a great deal of difference, but if I'm dividing by the same value multiple times, I usually multiply by the reciprocal.","created_at":"2016-03-30T03:25:03Z","updated_at":"2016-03-30T03:25:03Z","html_url":"https://github.com/gonum/stat/pull/96#discussion_r57832910","pull_request_url":"https://api.github.com/repos/gonum/stat/pulls/96","_links":{"self":{"href":"https://api.github.com/repos/gonum/stat/pulls/comments/57832910"},"html":{"href":"https://github.com/gonum/stat/pull/96#discussion_r57832910"},"pull_request":{"href":"https://api.github.com/repos/gonum/stat/pulls/96"}}},"pull_request":{"url":"https://api.github.com/repos/gonum/stat/pulls/96","id":63021169,"html_url":"https://github.com/gonum/stat/pull/96","diff_url":"https://github.com/gonum/stat/pull/96.diff","patch_url":"https://github.com/gonum/stat/pull/96.patch","issue_url":"https://api.github.com/repos/gonum/stat/issues/96","number":96,"state":"open","locked":false,"title":"ROC function","user":{"login":"Armadilloa16","id":11642131,"avatar_url":"https://avatars.githubusercontent.com/u/11642131?v=3","gravatar_id":"","url":"https://api.github.com/users/Armadilloa16","html_url":"https://github.com/Armadilloa16","followers_url":"https://api.github.com/users/Armadilloa16/followers","following_url":"https://api.github.com/users/Armadilloa16/following{/other_user}","gists_url":"https://api.github.com/users/Armadilloa16/gists{/gist_id}","starred_url":"https://api.github.com/users/Armadilloa16/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Armadilloa16/subscriptions","organizations_url":"https://api.github.com/users/Armadilloa16/orgs","repos_url":"https://api.github.com/users/Armadilloa16/repos","events_url":"https://api.github.com/users/Armadilloa16/events{/privacy}","received_events_url":"https://api.github.com/users/Armadilloa16/received_events","type":"User","site_admin":false},"body":"Produces a ROC curve.\r\n\r\nI'm pretty new to go, and to software development in general\r\nso I'm in the middle of a pretty steep learning curve -- I thought\r\nI should start with some small, simple contributions as I learn.\r\nAny feedback would be very helpful.\r\n\r\n@kortschak  @btracey please take a look?","created_at":"2016-03-16T06:52:48Z","updated_at":"2016-03-30T03:25:03Z","closed_at":null,"merged_at":null,"merge_commit_sha":"9d34ca3a04f73d62b34651c06aa1d4d268797a4e","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/gonum/stat/pulls/96/commits","review_comments_url":"https://api.github.com/repos/gonum/stat/pulls/96/comments","review_comment_url":"https://api.github.com/repos/gonum/stat/pulls/comments{/number}","comments_url":"https://api.github.com/repos/gonum/stat/issues/96/comments","statuses_url":"https://api.github.com/repos/gonum/stat/statuses/6f0006de4bf6ef856014d32da6174186aa6bb306","head":{"label":"Armadilloa16:master","ref":"master","sha":"6f0006de4bf6ef856014d32da6174186aa6bb306","user":{"login":"Armadilloa16","id":11642131,"avatar_url":"https://avatars.githubusercontent.com/u/11642131?v=3","gravatar_id":"","url":"https://api.github.com/users/Armadilloa16","html_url":"https://github.com/Armadilloa16","followers_url":"https://api.github.com/users/Armadilloa16/followers","following_url":"https://api.github.com/users/Armadilloa16/following{/other_user}","gists_url":"https://api.github.com/users/Armadilloa16/gists{/gist_id}","starred_url":"https://api.github.com/users/Armadilloa16/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Armadilloa16/subscriptions","organizations_url":"https://api.github.com/users/Armadilloa16/orgs","repos_url":"https://api.github.com/users/Armadilloa16/repos","events_url":"https://api.github.com/users/Armadilloa16/events{/privacy}","received_events_url":"https://api.github.com/users/Armadilloa16/received_events","type":"User","site_admin":false},"repo":{"id":54007172,"name":"stat","full_name":"Armadilloa16/stat","owner":{"login":"Armadilloa16","id":11642131,"avatar_url":"https://avatars.githubusercontent.com/u/11642131?v=3","gravatar_id":"","url":"https://api.github.com/users/Armadilloa16","html_url":"https://github.com/Armadilloa16","followers_url":"https://api.github.com/users/Armadilloa16/followers","following_url":"https://api.github.com/users/Armadilloa16/following{/other_user}","gists_url":"https://api.github.com/users/Armadilloa16/gists{/gist_id}","starred_url":"https://api.github.com/users/Armadilloa16/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Armadilloa16/subscriptions","organizations_url":"https://api.github.com/users/Armadilloa16/orgs","repos_url":"https://api.github.com/users/Armadilloa16/repos","events_url":"https://api.github.com/users/Armadilloa16/events{/privacy}","received_events_url":"https://api.github.com/users/Armadilloa16/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/Armadilloa16/stat","description":"Statistics package for Go","fork":true,"url":"https://api.github.com/repos/Armadilloa16/stat","forks_url":"https://api.github.com/repos/Armadilloa16/stat/forks","keys_url":"https://api.github.com/repos/Armadilloa16/stat/keys{/key_id}","collaborators_url":"https://api.github.com/repos/Armadilloa16/stat/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/Armadilloa16/stat/teams","hooks_url":"https://api.github.com/repos/Armadilloa16/stat/hooks","issue_events_url":"https://api.github.com/repos/Armadilloa16/stat/issues/events{/number}","events_url":"https://api.github.com/repos/Armadilloa16/stat/events","assignees_url":"https://api.github.com/repos/Armadilloa16/stat/assignees{/user}","branches_url":"https://api.github.com/repos/Armadilloa16/stat/branches{/branch}","tags_url":"https://api.github.com/repos/Armadilloa16/stat/tags","blobs_url":"https://api.github.com/repos/Armadilloa16/stat/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/Armadilloa16/stat/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/Armadilloa16/stat/git/refs{/sha}","trees_url":"https://api.github.com/repos/Armadilloa16/stat/git/trees{/sha}","statuses_url":"https://api.github.com/repos/Armadilloa16/stat/statuses/{sha}","languages_url":"https://api.github.com/repos/Armadilloa16/stat/languages","stargazers_url":"https://api.github.com/repos/Armadilloa16/stat/stargazers","contributors_url":"https://api.github.com/repos/Armadilloa16/stat/contributors","subscribers_url":"https://api.github.com/repos/Armadilloa16/stat/subscribers","subscription_url":"https://api.github.com/repos/Armadilloa16/stat/subscription","commits_url":"https://api.github.com/repos/Armadilloa16/stat/commits{/sha}","git_commits_url":"https://api.github.com/repos/Armadilloa16/stat/git/commits{/sha}","comments_url":"https://api.github.com/repos/Armadilloa16/stat/comments{/number}","issue_comment_url":"https://api.github.com/repos/Armadilloa16/stat/issues/comments{/number}","contents_url":"https://api.github.com/repos/Armadilloa16/stat/contents/{+path}","compare_url":"https://api.github.com/repos/Armadilloa16/stat/compare/{base}...{head}","merges_url":"https://api.github.com/repos/Armadilloa16/stat/merges","archive_url":"https://api.github.com/repos/Armadilloa16/stat/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/Armadilloa16/stat/downloads","issues_url":"https://api.github.com/repos/Armadilloa16/stat/issues{/number}","pulls_url":"https://api.github.com/repos/Armadilloa16/stat/pulls{/number}","milestones_url":"https://api.github.com/repos/Armadilloa16/stat/milestones{/number}","notifications_url":"https://api.github.com/repos/Armadilloa16/stat/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/Armadilloa16/stat/labels{/name}","releases_url":"https://api.github.com/repos/Armadilloa16/stat/releases{/id}","deployments_url":"https://api.github.com/repos/Armadilloa16/stat/deployments","created_at":"2016-03-16T06:38:02Z","updated_at":"2016-03-16T06:38:04Z","pushed_at":"2016-03-30T01:21:58Z","git_url":"git://github.com/Armadilloa16/stat.git","ssh_url":"git@github.com:Armadilloa16/stat.git","clone_url":"https://github.com/Armadilloa16/stat.git","svn_url":"https://github.com/Armadilloa16/stat","homepage":"","size":363,"stargazers_count":0,"watchers_count":0,"language":"Go","has_issues":false,"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":"gonum:master","ref":"master","sha":"12755f6f34a9f05175a174a7da35c7b5f4d15a8d","user":{"login":"gonum","id":3771091,"avatar_url":"https://avatars.githubusercontent.com/u/3771091?v=3","gravatar_id":"","url":"https://api.github.com/users/gonum","html_url":"https://github.com/gonum","followers_url":"https://api.github.com/users/gonum/followers","following_url":"https://api.github.com/users/gonum/following{/other_user}","gists_url":"https://api.github.com/users/gonum/gists{/gist_id}","starred_url":"https://api.github.com/users/gonum/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/gonum/subscriptions","organizations_url":"https://api.github.com/users/gonum/orgs","repos_url":"https://api.github.com/users/gonum/repos","events_url":"https://api.github.com/users/gonum/events{/privacy}","received_events_url":"https://api.github.com/users/gonum/received_events","type":"Organization","site_admin":false},"repo":{"id":22622955,"name":"stat","full_name":"gonum/stat","owner":{"login":"gonum","id":3771091,"avatar_url":"https://avatars.githubusercontent.com/u/3771091?v=3","gravatar_id":"","url":"https://api.github.com/users/gonum","html_url":"https://github.com/gonum","followers_url":"https://api.github.com/users/gonum/followers","following_url":"https://api.github.com/users/gonum/following{/other_user}","gists_url":"https://api.github.com/users/gonum/gists{/gist_id}","starred_url":"https://api.github.com/users/gonum/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/gonum/subscriptions","organizations_url":"https://api.github.com/users/gonum/orgs","repos_url":"https://api.github.com/users/gonum/repos","events_url":"https://api.github.com/users/gonum/events{/privacy}","received_events_url":"https://api.github.com/users/gonum/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/gonum/stat","description":"Statistics package for Go","fork":false,"url":"https://api.github.com/repos/gonum/stat","forks_url":"https://api.github.com/repos/gonum/stat/forks","keys_url":"https://api.github.com/repos/gonum/stat/keys{/key_id}","collaborators_url":"https://api.github.com/repos/gonum/stat/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/gonum/stat/teams","hooks_url":"https://api.github.com/repos/gonum/stat/hooks","issue_events_url":"https://api.github.com/repos/gonum/stat/issues/events{/number}","events_url":"https://api.github.com/repos/gonum/stat/events","assignees_url":"https://api.github.com/repos/gonum/stat/assignees{/user}","branches_url":"https://api.github.com/repos/gonum/stat/branches{/branch}","tags_url":"https://api.github.com/repos/gonum/stat/tags","blobs_url":"https://api.github.com/repos/gonum/stat/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/gonum/stat/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/gonum/stat/git/refs{/sha}","trees_url":"https://api.github.com/repos/gonum/stat/git/trees{/sha}","statuses_url":"https://api.github.com/repos/gonum/stat/statuses/{sha}","languages_url":"https://api.github.com/repos/gonum/stat/languages","stargazers_url":"https://api.github.com/repos/gonum/stat/stargazers","contributors_url":"https://api.github.com/repos/gonum/stat/contributors","subscribers_url":"https://api.github.com/repos/gonum/stat/subscribers","subscription_url":"https://api.github.com/repos/gonum/stat/subscription","commits_url":"https://api.github.com/repos/gonum/stat/commits{/sha}","git_commits_url":"https://api.github.com/repos/gonum/stat/git/commits{/sha}","comments_url":"https://api.github.com/repos/gonum/stat/comments{/number}","issue_comment_url":"https://api.github.com/repos/gonum/stat/issues/comments{/number}","contents_url":"https://api.github.com/repos/gonum/stat/contents/{+path}","compare_url":"https://api.github.com/repos/gonum/stat/compare/{base}...{head}","merges_url":"https://api.github.com/repos/gonum/stat/merges","archive_url":"https://api.github.com/repos/gonum/stat/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/gonum/stat/downloads","issues_url":"https://api.github.com/repos/gonum/stat/issues{/number}","pulls_url":"https://api.github.com/repos/gonum/stat/pulls{/number}","milestones_url":"https://api.github.com/repos/gonum/stat/milestones{/number}","notifications_url":"https://api.github.com/repos/gonum/stat/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/gonum/stat/labels{/name}","releases_url":"https://api.github.com/repos/gonum/stat/releases{/id}","deployments_url":"https://api.github.com/repos/gonum/stat/deployments","created_at":"2014-08-04T23:07:41Z","updated_at":"2016-03-29T05:05:07Z","pushed_at":"2016-03-30T01:21:58Z","git_url":"git://github.com/gonum/stat.git","ssh_url":"git@github.com:gonum/stat.git","clone_url":"https://github.com/gonum/stat.git","svn_url":"https://github.com/gonum/stat","homepage":"","size":385,"stargazers_count":106,"watchers_count":106,"language":"Go","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":12,"mirror_url":null,"open_issues_count":15,"forks":12,"open_issues":15,"watchers":106,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/gonum/stat/pulls/96"},"html":{"href":"https://github.com/gonum/stat/pull/96"},"issue":{"href":"https://api.github.com/repos/gonum/stat/issues/96"},"comments":{"href":"https://api.github.com/repos/gonum/stat/issues/96/comments"},"review_comments":{"href":"https://api.github.com/repos/gonum/stat/pulls/96/comments"},"review_comment":{"href":"https://api.github.com/repos/gonum/stat/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/gonum/stat/pulls/96/commits"},"statuses":{"href":"https://api.github.com/repos/gonum/stat/statuses/6f0006de4bf6ef856014d32da6174186aa6bb306"}}}}