# Area under a ROC Curve after a logistic regression

**URL:** <https://discourse.julialang.org/t/area-under-a-roc-curve-after-a-logistic-regression/121121>\
**Category:** Statistics\
**Tags:** rocanalysisjl\
**Created:** [October 10, 2024, 3:51am UTC](https://discourse.julialang.org/t/area-under-a-roc-curve-after-a-logistic-regression/121121 "2024-10-10T03:51:44Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![mwsohn](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mwsohn/32/2696_2.png) [@mwsohn](https://discourse.julialang.org/u/mwsohn)\
**Post date:** [October 10, 2024, 3:51am UTC](https://discourse.julialang.org/t/area-under-a-roc-curve-after-a-logistic-regression/121121/1 "2024-10-10T03:51:44Z")

</div>

I am trying to compute ROCAnalysis.jl package to compute the AUC value after a logistic regression. When I ran

auc(roc(dep, pred)),

where dep is the vector with original binary dependent variable and pred the predicted values from the logistic regression.

I get a value very different from the AUC value I get from Stata. I am wondering whether there is a good documentation on how to use these functions.

---

<div class="post-metadata">

**Author:** ![eteppo](https://avatars.discourse-cdn.com/v4/letter/e/90db22/32.png) [@eteppo](https://discourse.julialang.org/u/eteppo)\
**Post date:** [February 14, 2025, 9:00pm UTC](https://discourse.julialang.org/t/area-under-a-roc-curve-after-a-logistic-regression/121121/2 "2025-02-14T21:00:54Z")

</div>

The function seems to expect certain kind of scores for targets and non-targets, not truths and predictions. You can find other implementations in different packages. (General caution for beginners such as myself: it’s crucial to pay attention to how mature the packages are, and the more rough and abandoned it looks, the more you need to understand the source code to trust it.)

---

<div class="post-metadata">

**Author:** ![depial](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/depial/32/217523_2.png) [@depial](https://discourse.julialang.org/u/depial)\
**Post date:** [March 26, 2026, 12:14am UTC](https://discourse.julialang.org/t/area-under-a-roc-curve-after-a-logistic-regression/121121/3 "2026-03-26T00:14:43Z")

</div>

I’ve just had a nice needless romp through the finer details of ML implementations in Lux.jl because of my misunderstanding of ROCAnalysis.jl… Turns out I should read about things before using them.

There are some important points about this implementation of the ROC curve:

1. The ROC curve is computed over False Negatives and False Positives, instead of True Positives and False Positives. So, your curve will be upside-down and a lower AUC is better.
2. It takes target and non-target arrays as input. So, if you had `y_hat` as a vector of logits (or probabilities) and `y_true` as the `1`/`0` labels, then you’d use:

```julia
target = y_hat[y_true .== 1]
nontarget = y_hat[y_true .== 0]
roc(target, nontarget)

```

If you reverse the arguments, you’ll get a ROC curve that looks normal, but mirrored. Probably not ideal.

Anyways, after I figured all that out, I gave up on more packages and just used this:

```julia
function rocauc(y_true, y_pred)
    sorted_indices = sortperm(y_pred, rev=true)
    sorted_true, sorted_pred = y_true[sorted_indices], y_pred[sorted_indices]
    total_positive = Int(sum(y_true))
    total_negative = length(y_true) - total_positive

    tpr, fpr, thresholds = [], [], []
    tp, fp = 0, 0
    for i in 1:length(y_true)
        isone(sorted_true[i]) ? (tp += 1) : (fp += 1)
        push!(tpr, tp / total_positive)
        push!(fpr, fp / total_negative)
        push!(thresholds, sorted_pred[i])
    end

    auc = sum((fpr[i] - fpr[i-1]) * (tpr[i] + tpr[i-1]) / 2 for i in 2:length(fpr))
    
    auc, fpr, tpr
end

```

Which will give you the normal AUC with `y_true` as described above and `y_pred` as the associated probabilities. If anyone wants to use it, you can print AUC and plot the ROC curve with:

```julia
using Plots
auc, fpr, tpr = rocauc(y_true, y_pred)
println("AUC: ", auc)
plot(fpr, tpr, 
     label="ROC w/ AUC = $(round(auc, digits=4))", 
     xlabel="False Positive Rate", 
     ylabel="True Positive Rate",
     title="ROC Curve"
)

```

---

<div class="post-metadata">

**Author:** ![mwsohn](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mwsohn/32/2696_2.png) [@mwsohn](https://discourse.julialang.org/u/mwsohn)\
**Post date:** [April 14, 2026, 8:09pm UTC](https://discourse.julialang.org/t/area-under-a-roc-curve-after-a-logistic-regression/121121/4 "2026-04-14T20:09:03Z")

</div>

If you want to compute the AUC after a logistic regression, try LogisticROC. lroc() function will give you both the plot and AUC value. lroc() takes the return value from a GLM model.

---

<div class="post-metadata">

**Author:** ![depial](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/depial/32/217523_2.png) [@depial](https://discourse.julialang.org/u/depial)\
**Post date:** [October 1, 2026, 12:07pm UTC](https://discourse.julialang.org/t/area-under-a-roc-curve-after-a-logistic-regression/121121/5 "2026-10-01T12:07:45Z")

</div>

Just thought I’d come back to leave an implementation that handles ties.

```julia
function rocauc(y_true, y_pred)
    idx = sortperm(y_pred, rev=true)
    y, p = y_true[idx], y_pred[idx]

    P = sum(y_true)
    N = length(y_true) - P

    tpr, fpr = typeof(N)[0], typeof(N)[0]
    thresholds = typeof(N)[Inf]

    tp = fp = 0
    i = 1

    while i ≤ length(y)
        j = i
        while j ≤ length(y) && p[j] == p[i]
            y[j] == 1 ? (tp += 1) : (fp += 1)
            j += 1
        end

        push!(tpr, tp / P)
        push!(fpr, fp / N)
        push!(thresholds, p[i])

        i = j
    end

    auc = sum((fpr[i] - fpr[i-1]) * (tpr[i] + tpr[i-1]) / 2 for i in 2:length(fpr))

    auc, fpr, tpr, thresholds
end

```
