Alessandro Morita Enjoying the thermodynamic limit

Variance of the ROC AUC: a full derivation

Variance of the ROC AUC: a full derivation

AUC status quo

The ROC AUC is the most used statistic to assess the predictive power of a classification model. However, few working data scientists know theoretical results about its statistical fluctuations. Here, we show in detail a derivation of a commonly found result on the variance of the ROC AUC.

We have not found this demonstration done in length in any references, and so write it here for pedagogical reasons.

We further study the case of the random classifier under extreme imbalance, which demonstrates interesting statistical results regarding asymptotic independence.

Originally presented at the DataLab Journal Club on September 2022.

Recap: the probabilistic interpretation of the ROC AUC

Let (X,Y)(X,Y) be jointly distributed with YY taking values in {0,1}\{0,1\}. This is the standard binary classification problem.

The ROC AUC measures the likelihood that a point in class 1 is scored higher than a point in class 0:

A:=P(f(X)f(X)Y=1,Y=0).\boxed{A := \mathbb P(f(X) \geq f(X') \vert Y=1, Y'=0).}

If we write P=[f(X)Y=1]P = [f(X)\vert Y=1] and Q=[f(X)Y=0]Q = [f(X)\vert Y=0], this can be rephrased as

A=P(PQ)A = \mathbb P(P \geq Q)

The Mann-Whitney-Wilcoxon estimator

This can be estimated via the Mann-Whitney-Wilcoxon statistic

A^=1n0n1i=1n1j=1n01PiQj\boxed{\hat A = \frac{1}{n_0 n_1} \sum_{i=1}^{n_1} \sum_{j=1}^{n_0} 1_{P_i \geq Q_j}}

where PiP_i refers to the score of a point in class 1, and QjQ_j of one in class 0:

Pif(Xi)Yi=1,Qjf(Xj)Yj=0P_i \equiv f(X_i)\vert Y_i=1,\qquad Q_j \equiv f(X_j)\vert Y_j=0

via the fact that E[A^]=A\mathbb E[\hat A] = A.

Numerical example (to show that this is true)

import numpy as np
from sklearn.datasets import make_classification
from sklearn.metrics import roc_auc_score
from sklearn.linear_model import LogisticRegression
X, y = make_classification(2000, n_features=20, class_sep=0.6, 
                           weights=(0.8,),
                           random_state=2)
model = LogisticRegression().fit(X, y)
# As an area
y_probs = model.predict_proba(X)[:,1]
auc_area = roc_auc_score(y, y_probs)
# As a probability
n0, n1 = np.bincount(y)
total_sum = 0
for pi in y_probs[y==1]:
    for pj in y_probs[y==0]:
        if pi >= pj:
            total_sum += 1
auc_estimator = total_sum/(n0*n1)
print("ROC AUC calculated as an area:", round(auc_area,5))
print("ROC AUC calculated a statistic:", round(auc_estimator,5))
    ROC AUC calculated as an area: 0.93089
    ROC AUC calculated a statistic: 0.93089

Notice how both results are identical.

Statistics of the ROC AUC

It is easily seen that E[A^]=A\mathbb E[\hat A] = A, and thus one might ask what is the variance of this estimator. We will prove the following result (eq. (2) of [1] and eq. (6) of [2]):

Theorem. Under the hypothesis that all points in a given class are independent (ie. PP’s are iid among themselves, as are the QQ’) then the variance of the Mann-Whitney-Wilcoxon statistic is

Var  A^=A(1A)+(n01)(PXYYA2)+(n11)(PXXYA2)n0n1,\boxed{\mathrm{Var}\; \hat A = \frac{A(1-A) + (n_0 - 1)(P_{XYY} - A^2) + (n_1 - 1)(P_{XXY} - A^2)}{n_0 n_1},}

where

PXXY=P(PQ,PQ)P_{XXY} = \mathbb P (P \geq Q, P' \geq Q)

for any P,PP, P', and similarly

PXYY=P(PQ,PQ)P_{XYY} = \mathbb P(P \geq Q, P \geq Q')

for any Q,QQ, Q'.

Proof:

In what follows,

1ij1PiQj1_{ij} \equiv 1_{P_i \geq Q_j}

will be a shorthand notation.

By definition,

Var(n0n1A^)=Var(ij1ij)=ijklcov(1ij,1kl)=ijklcov(1ij,1kl)[1i=kj=l+1i=kjl+1ikj=l+1ikjl]=ijVar(1ij)+ijlcov(1ij,1il)+jikcov(1ij,1kj)+ikjlcov(1ij,1kl)\begin{align*} \mathrm{Var}\, (n_0 n_1 \hat A) &= \mathrm{Var}\, \left( \sum_{ij} 1_{ij} \right)\\ &= \sum_{ij} \sum_{kl} \mathrm{cov}\,(1_{ij}, 1_{kl})\\ &= \sum_{ij} \sum_{kl} \mathrm{cov}\,(1_{ij}, 1_{kl}) \left[ 1_{i=k\\ j= l} + 1_{i=k\\ j \neq l}+ 1_{i\neq k\\ j= l}+ 1_{i\neq k\\ j \neq l} \right]\\ &= \sum_{ij} \mathrm{Var} (1_{ij}) + \sum_i \sum_{j\neq l} \mathrm{cov}\,(1_{ij}, 1_{il}) + \sum_j \sum_{i\neq k} \mathrm{cov}\,(1_{ij}, 1_{kj}) + \sum_{i\neq k} \sum_{j\neq l} \mathrm{cov}\,(1_{ij}, 1_{kl}) \end{align*}

Now, we can simplify a bit by noting that

cov(1ij,1kl)E[1ij1kl]E[1ij]E[1kl]=E[1ij,kl]A2\begin{align*} \mathrm{cov}\,(1_{ij}, 1_{kl}) &\equiv \mathbb E[1_{ij} 1_{kl}] - \mathbb E[1_{ij}] \mathbb E[1_{kl}]\\ &= \mathbb E[1_{ij, kl}] - A^2 \end{align*}

where we used the shorthand

1ij,kl1PiQj,PkQl1_{ij,kl} \equiv 1_{P_i \geq Q_j, P_k \geq Q_l}

and we see the AUC AA appear since

E[1ij]=E[1PiQj]=P(PiQj)=A.\mathbb E[1_{ij}] = \mathbb E[1_{P_i \geq Q_j}] = \mathbb P(P_i \geq Q_j) = A.

Hence,

n02n12VarA^=ijVar(1ij)+ijl(E[1ij,il]A2)+jik(E[1ij,kj]A2)+ikjl(E[1ij,kl]A2)\begin{align*} n_0^2 n_1^2 \mathrm{Var}\, \hat A = \sum_{ij} \mathrm{Var} (1_{ij}) + \sum_i \sum_{j\neq l} \left( \mathbb E[1_{ij, il}] - A^2 \right) + \sum_j \sum_{i\neq k} \left( \mathbb E[1_{ij, kj}] - A^2 \right) + \sum_{i \neq k} \sum_{j\neq l} \left( \mathbb E[1_{ij, kl}] - A^2 \right) \end{align*}

Now, the summand in the last term is (explicitly) E[1PiQj,PkQl]\mathbb E[1_{P_i \geq Q_j,P_k \geq Q_l}].

But since iki \neq k and jlj \neq l, the events PiQjP_i \geq Q_j is completely independent from PkQlP_k \geq Q_l, and we can split the expectation into

E[1PiQj]E[1PkQl]=A2,\mathbb E[1_{P_i \geq Q_j}] \mathbb E[1_{P_k \geq Q_l}] = A^2,

which cancels the other A2A^2 term.

Furthermore, it is easy to see that

E[1ij,il]=PXYY;\mathbb E[1_{ij,il}] = P_{XYY};

it is exactly the term PXYYP_{XYY} term defined above: it is the probability that a single score in class 1 (the P) is greater than two random scores from class 0 (the Q’s). An analogous reasoning shows that

E[1ij,jk]=PXXY.\mathbb E[1_{ij, jk}] = P_{XXY}.

Putting these together, we are left with

VarA^=1n02n12[ijVar(1ij)+ijl(PXYYA2)+jik(PXXYA2)]()\begin{align*} \mathrm{Var}\, \hat A = \frac{1}{n_0^2 n_1^2} \left[ \sum_{ij} \mathrm{Var} (1_{ij}) + \sum_i \sum_{j\neq l} \left( P_{XYY} - A^2 \right) + \sum_j \sum_{i\neq k} \left( P_{XXY} - A^2 \right) \right] \qquad (\star) \end{align*}

To go further, we need an intermediate result:

Lemma 1: Var1PQ=A(1A)\boxed{\mathrm{Var}\, 1_{P\geq Q} = A(1-A)}

Proof: we will need the expression for conditional variance: if X,YX, Y are random variables,

VarX=E[Var(XY)]+Var(E[XY])\mathrm{Var}\, X = \mathbb E[\mathrm{Var}\,(X\vert Y)] + \mathrm{Var}\,(\mathbb E[X\vert Y])

For any PP and QQ, it then follows that

Var1PQ=E[Var(1PQQ)]+Var(E[1PQQ])\mathrm{Var}\, 1_{P \geq Q} = \mathbb E[\mathrm{Var}\,(1_{P \geq Q}\vert Q)] + \mathrm{Var}\,(\mathbb E[1_{P\geq Q}\vert Q])

Now, it is not too hard to see how the variable 1PQQ1_{P\geq Q}\vert Q is distributed. Since it takes values on {0,1}\{0,1\} is is in the Bernoulli familly; recall that XBernoulli(p)X \sim \mathrm{Bernoulli}(p) means that P(X=1)=1P(X=0)=p\mathbb P(X=1) = 1-\mathbb P(X=0) = p. In our case,

P(1PQ=1Q)=P(PQQ)=1P(PQQ)1FP(Q)\begin{align*} \mathbb P(1_{P\geq Q} = 1\vert Q) &= \mathbb P(P \geq Q\vert Q)\\ &= 1 - \mathbb P(P \leq Q\vert Q)\\ &\equiv 1 - F_P(Q) \end{align*}

where FPF_P is the CDF of PP. Hence,

1PQQBernoulli(1FP(Q))1_{P\geq Q}\vert Q \,\sim\,\mathrm{Bernoulli}(1 - F_P(Q))

Now, a Bernoulli(p)\mathrm{Bernoulli}(p) variable has expectation pp and variance p(1p)p(1-p). It follows that

E[1PQQ]=1FP(Q),Var(1PQQ)=FP(Q)(1FP(Q))\mathbb E[1_{P\geq Q}\vert Q] = 1 - F_P(Q),\qquad \mathrm{Var}\, (1_{P\geq Q}\vert Q) = F_P(Q) (1 - F_P(Q))

and plugging these into the original expression for the variance we get

Var1PQ=E[Var(1PQQ)]+Var(E[1PQQ])=E[FP(Q)(1FP(Q))]+Var(1FP(Q))=E[FP(Q)]E[FP2(Q)]+Var(FP(Q)); but VarX=E[X2]E[X]2=E[FP(Q)]E[FP2(Q)]+E[FP2(Q)](E[FP(Q)])2=E[FP(Q)](1E[FP(Q)])\begin{align*} \mathrm{Var}\, 1_{P \geq Q} &= \mathbb E[\mathrm{Var}\,(1_{P \geq Q}\vert Q)] + \mathrm{Var}\,(\mathbb E[1_{P\geq Q}\vert Q])\\ &= \mathbb E[F_P(Q) (1 - F_P(Q))] + \mathrm{Var}\,(1 - F_P(Q))\\ &= \mathbb E[F_P(Q)] - \mathbb E[F_P^2(Q)] + \mathrm{Var}\,(F_P(Q));\qquad \text{ but } \mathrm{Var}\, X = \mathbb E[X^2] - \mathbb E[X]^2\\ &= \mathbb E[F_P(Q)] - \mathbb E[F_P^2(Q)] + \mathbb E[F_P^2(Q)] - (\mathbb E[F_P(Q)])^2\\ &= \mathbb E[F_P(Q)] (1 - \mathbb E[F_P(Q)]) \end{align*}

How much is E[FP(Q)]\mathbb E[F_P(Q)]? This is indeed EQ[FP(Q)]\mathbb E_Q[F_P(Q)]; let fP,fQf_P, f_Q denote the respective PDFs of PP and QQ. Then

E[FP(Q)]=01FP(q)fQ(q)dq=01dq  fQ(q)0qdp  fP(p)=[0,1]2fP(p)fQ(q)1pqdpdq=E[1PQ]=1P(PQ)=1A.\begin{align*} \mathbb E[F_P(Q)] &= \int_0^1 F_P(q) f_Q(q) dq\\ &= \int_0^1 dq\;f_Q(q) \int_0^q dp \;f_P(p)\\ &= \int_{[0,1]^2} f_P(p) f_Q(q) 1_{p \leq q}\, dp dq\\ &= \mathbb E[1_{P\leq Q}] = 1 - \mathbb P(P\geq Q)\\ &= 1- A. \end{align*}

Finally,

Var1PQ=A(1A)\mathrm{Var}\, 1_{P \geq Q} = A(1-A)\qquad \Box

This means that, for any i,ji,j, Var1ij=A(1A)\mathrm{Var}\, 1_{ij} = A(1-A). Thus the first term above will be simplified.

Using this result in ()(\star) we get

VarA^=1n02n12[ijA(1A)+ijl(PXYYA2)+jik(PXXYA2)],\begin{align*} \mathrm{Var}\, \hat A = \frac{1}{n_0^2 n_1^2} \left[ \sum_{ij} A(1-A) + \sum_i \sum_{j\neq l} \left( P_{XYY} - A^2 \right) + \sum_j \sum_{i\neq k} \left( P_{XXY} - A^2 \right) \right], \end{align*}

or, writing the sums explicitly,

VarA^=1n02n12[i=1n1j=1n0A(1A)+i=1n1j=1n0l=1ljn0(PXYYA2)+j=1n0i=1n1k=1kin1(PXXYA2)],\begin{align*} \mathrm{Var}\, \hat A = \frac{1}{n_0^2 n_1^2} \left[ \sum_{i=1}^{n_1} \sum_{j=1}^{n_0} A(1-A) + \sum_{i=1}^{n_1} \sum_{j=1}^{n_0} \sum_{l=1\\ l \neq j}^{n_0} \left( P_{XYY} - A^2 \right) + \sum_{j=1}^{n_0} \sum_{i=1}^{n_1} \sum_{k =1\\ k \neq i}^{n_1} \left( P_{XXY} - A^2 \right) \right], \end{align*}

None of the terms depend on the indices i,j,k,li,j,k,l anymore. The first term will output a factor of n0n1n_0 n_1; the second one, n1n0(n01)n_1 n_0 (n_0-1), and the third one n0n1(n11)n_0 n_1 (n_1-1), hence

VarA^=1n0n1[A(1A)+(n01)(PXYYA2)+(n11)(PXXYA2)]\mathrm{Var}\, \hat A = \frac{1}{n_0 n_1} \left[ A(1-A) + (n_0-1)(P_{XYY} - A^2) + (n_1 - 1)(P_{XXY} - A^2) \right]

as we wanted to prove. \Box

Special case: random classifier

In the case of a random classifier, ie. where PUnif([0,1])P \sim \mathrm{Unif}([0,1]) and similarly for QQ, we have A=1/2A = 1/2 and

PXXY=PYXX=13,P_{XXY} = P_{YXX} = \frac 13,

since

PXXY=P(P1Q,P2Q)=01P(P1Q,P2QQ=q)p(q)dq\begin{align*} P_{XXY} &= \mathbb P(P_1 \geq Q, P_2 \geq Q)\\ &= \int_0^1 \mathbb P(P_1 \geq Q, P_2 \geq Q \vert Q=q) p(q) dq \end{align*}

where p(q)=1p(q) = 1 is the uniform PDF. Now, conditioned on QQ, the two events above are independent and we have

PXXY=01P(P1q)P(P2q)dq=01(1q)2dq=13.\begin{align*} P_{XXY} &= \int_0^1 \mathbb P(P_1 \geq q) \mathbb P(P_2 \geq q) dq\\ &= \int_0^1 (1-q)^2 dq\\ &= \frac 13. \end{align*}

Plugging this into the variance equation we get

(VarA^)randomclassifier=1n0n1[14+(n01+n11)(1314)]=n0+n1+112n0n1\begin{align*} (\mathrm{Var}\, \hat A)_\mathrm{random\, classifier} &= \frac{1}{n_0 n_1} \left[ \frac 14 + (n_0-1 + n_1-1) \left (\frac 13 - \frac 14\right)\right]\\ &= \frac{n_0+n_1+1}{12 n_0 n_1} \end{align*}

If either n0n_0 or n1n_1 is sufficiently large,

A^randomclassifierN(12,n0+n1+112n0n1)\boxed{\hat A _\mathrm{random\, classifier} \approx \mathcal N \left( \frac 12, \frac{n_0+n_1+1}{12 n_0 n_1}\right)}

as we have already seen!

Experimental test

Let us simulate a classification problem. We will:

  • Train a model on a training set
  • Create bootstrap samples of the test set and calculate the ROC AUC in each of them
  • Use these samples to compare to the theoretical results
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import roc_auc_score
from tqdm.notebook import tqdm
X, y = make_classification(n_samples=5000, weights=(0.7,), 
                           class_sep=0.8, flip_y=0.1, random_state=2 )
X_train, X_test, y_train, y_test = train_test_split(X, y,
                                                    test_size=0.4,
                                                    stratify=y, 
                                                    random_state=42)
model = LogisticRegression(random_state=1)
model.fit(X_train, y_train);

It seems the model is not too overfitted:

print("Train AUC:", round(roc_auc_score(y_train, model.predict_proba(X_train)[:,1]),3))
print("Test AUC:", round(roc_auc_score(y_test, model.predict_proba(X_test)[:,1]),3))
    Train AUC: 0.876
    Test AUC: 0.869

Use theoretical formulas

def calculate_pxxy(X, y, model, seed=None, n_samples=10000):
    scores = model.predict_proba(X)[:,1]
    
    p, q = scores[y==1], scores[y==0]
    
    if seed is not None:
        np.random.seed(seed)

    samples = [np.all(np.random.choice(p, size=2) >= np.random.choice(q, size=1))
               for _ in range(n_samples)]
    
    return np.mean(samples)

def calculate_pxyy(X, y, model, seed=None, n_samples=10000):
    scores = model.predict_proba(X)[:,1]
    
    p, q = scores[y==1], scores[y==0]
    
    if seed is not None:
        np.random.seed(seed)

    samples = [np.all(np.random.choice(p, size=1) >= np.random.choice(q, size=2))
               for _ in range(n_samples)]
    return np.mean(samples)

Theoretical variance:

pxxy = calculate_pxxy(X_test, y_test, model, seed=1)
pxxy
    0.7883
pxyy = calculate_pxxy(X_test, y_test, model, seed=2)
pxyy
    0.7857
A = roc_auc_score(y_test, model.predict_proba(X_test)[:,1])
n0, n1 = np.bincount(y_test)
def variance(n0, n1, A, pxxy, pxyy):
    return (1/(n0*n1)) * (A*(1-A) + (n0-1)*(pxyy-A**2) + (n1-1)*(pxxy - A**2))
theoretical_var = variance(n0, n1, A, pxxy, pxyy)
print("Theoretical variance:", round(theoretical_var,7))
    Theoretical variance: 7.21e-05

Use bootstrapping:

def bootstrap_X_y(X, y, seed=None):
    n = len(X)
    if seed is not None:
        np.random.seed(seed)
        
    indices = np.random.randint(0, high=len(X), size=len(X))
    return X[indices], y[indices]
n_samples = 10000
aucs = []
for seed in tqdm(range(n_samples)):
    X_bs, y_bs = bootstrap_X_y(X_test, y_test, seed=seed)
    auc = roc_auc_score(y_bs, model.predict_proba(X_bs)[:,1])
    aucs.append(auc)

Calculate variance:

plt.hist(aucs, bins=100)
plt.show()

png

exp_var = np.std(aucs)**2
#Comparison:
print("Theoretical variance:", round(theoretical_var,7))
print("Bootstrap variance:", round(exp_var,7))
    Theoretical variance: 7.21e-05
    Bootstrap variance: 7.85e-05

They are very similar, as we expected!

A practical example: finding backtest sample size

In Experian, it is common for us to develop models and then backtest them with client data, as a free test before clients purchase the models. Assume we run backtests of a specific credit model with clients.

We need to ask them for a dataset to prove our product’s performance. The dataset must:

  • not be too small (so we avoid small data issues)
  • not be too big (complex, might have legal issues to share)

What is an optimal range for the sample size?

  • Let us assume the population imbalance ratio is α<1\alpha < 1

  • Assume we want the ROC AUC to be precise to ϵ\epsilon, an absolute number such as 0.01 (ie. a variance of 10410^{-4}).

From the formula for a (random) classifier’s AUC,

σ2n1+n012n1n0\sigma^2 \approx \frac{n_1+n_0}{12 n_1 n_0}

if we write n1=αNn_1 = \alpha N, n0=(1α)Nn_0 = (1-\alpha) N we get

σ2=N12N2α(1α)=112Nα(1α)\sigma^2 = \frac{N}{12 N^2 \alpha(1-\alpha)} = \frac{1}{12 N \alpha(1-\alpha)}

Setting σϵ\sigma \leq \epsilon we find NN to be

N112ϵ2α(1α)\boxed{N \geq \frac{1}{12 \epsilon^2 \alpha(1-\alpha)}}

Example: for α=0.10\alpha = 0.10 and ϵ=0.01\epsilon = 0.01, we find

alpha = 0.10
epsilon = 0.01
print("Sample size:",int(1/(12*alpha*(1-alpha)*epsilon**2)))
    Sample size: 9259

Thus, it is reasonable to ask clients for a dataset with around 10,000 points for a backtest if we want to report AUC to 1 percentage point error.

The (beautiful & useless) extreme-imbalance, random classifier

Lett us get the simplest possible estimator: a random one, where all scores are uniformly sampled from [0,1][0,1]. In this context, how likely are we to get a spuriously large AUC?

In particular, we want to consider an extreme imbalance scenario where

  1. nn is small (say, less than 100)

  2. The ratio n/Nn/N is small: n/N1n/N \ll 1 (say, 1% or less)

Our intuition tells us that this case should be more interesting than the big-data, balanced one: since one has only a few (nn) points in class 1, if we are “lucky” to get high scores for all of them, the AUC will end up being high.

We will use the AUC estimator as defined above:

A^=1n(Nn)i=1nj=1Nn1PiQj\hat A = \frac{1}{n(N-n)} \sum_{i=1}^{n} \sum_{j=1}^{N-n} 1_{P_i \geq Q_j}

First, we have a trivial result: for all iIi \in I, jJj \in J, if Pi,QjP_i, Q_j iid distributed as Uniform([0,1])\mathrm{Uniform}([0,1]) then

1PiQjPi    Bernoulli(Pi)1_{P_i \geq Q_j} \vert P_i \; \sim \;\mathrm{Bernoulli}(P_i)

Since a binomial variable is built from a sum of independent Bernoulli ones, we have a corollary: for all iIi \in I,

jJ1PiQjPi    Binomial(Nn,Pi)\sum_{j \in J}\left. 1_{P_i \geq Q_j} \right\vert P_i \; \sim \; \mathrm{Binomial}(N-n, P_i)

Now, for large NnN-n, we may use the normal approximation to the binomial, namely a Binomial(n,p)\mathrm{Binomial}(n,p) variable converges to a N(μ=np,σ2=np(1p))\mathcal N(\mu=np, \sigma^2 = np(1-p)) variable as nn grows. Hence

jJ1PiQjPi    N((Nn)Pi,(Nn)Pi(1Pi))\sum_{j \in J}\left. 1_{P_i \geq Q_j} \right\vert P_i \; \sim \; \mathcal N\left( (N-n)P_i, (N-n)P_i (1-P_i) \right)

It follows that, for all iIi\in I,

ZiPi:=1NnjJ1PiQjPi    N(Pi,Pi(1Pi)Nn)Z_i \vert P_i := \frac{1}{N-n} \sum_{j \in J} \left.1_{P_i \geq Q_j}\right\vert \, P_i \;\sim \; \mathcal N \left(P_i, \frac{P_i (1-P_i)}{N-n}\right)

This defines a set of nn variables ZiZ_i. To obtain their marginal distribution, notice that for any ZiZ_i its PDF is given by

pZi(z)=p(zPi=p)p(Pi=p)dp;p_{Z_i}(z) = \int p(z\vert P_i=p) p(P_i=p) dp;

but Pi    Uniform([0,1])P_i \; \sim \; \mathrm{Uniform}([0,1]), and hence its PDF is just the identity on [0,1][0,1]. Letting

f(xμ,σ2)12πσ2exp[(xμ)22σ2]f(x \vert \mu,\sigma^2) \equiv \frac{1}{\sqrt{2\pi \sigma^2}} \exp \left[- \frac{(x-\mu)^2}{2\sigma^2} \right]

be the Gaussian PDF, we obtain

pZi(z)=01f(zp,p(1p)Nn)dpp_{Z_i}(z) = \int_0^1 f \left(\left. z \right\vert \, p, \frac{p(1-p)}{N-n} \right) dp

For NnN-n large (as is our hypothesis), the integrand (as a function of pp) is basically a very sharp peak centered at p=zp=z. In fact, we may approximate it as a Dirac delta function

f(zp,p(1p)Nn)δ(zp)f\left(z \left. \right\vert \, p, \frac{p(1-p)}{N-n} \right) \approx \delta(z-p)

to obtain

pZi(z)=1z[0,1]Zi    Uniform([0,1])p_{Z_i}(z) = 1_{z \in [0,1]} \quad \Rightarrow \quad Z_i \; \sim \; \mathrm{Uniform}([0,1])

We have also tested this numerically - even for n/Nn/N not that small this holds surprisingly well.

If we assume all ZiZ_i‘s are independent among themselves, the it means that nAUC^n \widehat{\mathrm{AUC}} is the sum of nn independent uniform variables: it follows the so-called Irwin-Hall distribution, and we have our most important result below.

Notice: we have not proven this independence assumption - it is not obvious, and we prove it below.

Theorem. Let AUC^random\widehat{\mathrm{AUC}}_\mathrm{random} denote the ROC AUC estimator for a uniformly random scoring function. Let there be nn instances of class 1 and NnN-n instances of class 0, where NnN\geq n. Then

nAUC^random    IrwinHall(n);\boxed{n \widehat{\mathrm{AUC}}_\mathrm{random} \; \sim \; \mathrm{IrwinHall}(n)};

notice that this result does not depend on NN explicitly; we’ve only used that NN is large and also much larger than nn.

As Wikipedia can tell us, if AIrwinHall(n)A \sim \mathrm{IrwinHall}(n) then

E[A]=n2;Var(A)=n12;\mathbb E[A] = \frac{n}{2};\qquad \mathrm{Var}(A) = \frac{n}{12};

for the AUC, this gives

E[AUC^random]=12;Var[AUC^random]=112n\boxed{\mathbb E[\widehat{\mathrm{AUC}}_{\mathrm{random}}] = \frac{1}{2};\qquad \mathrm{Var}[\widehat{\mathrm{AUC}}_{\mathrm{random}}] = \frac{1}{12 n}}

The first result is not surprising: we know that for a random scoring function the AUC should be 1/2. The second one is more surprising, and shows that as we increase nn, we get an increasingly more precise AUC at 0.5 with a standard deviation that goes as 1/n1/\sqrt{n}.

We can now use this result to calculate how likely a statistical fluke is to happen: recall Chebyshev’s inequality for any (square-integrable) random variable XX:

P(Xμt)VarXt2\mathbb P(\vert X - \mu\vert \geq t) \leq \frac{\mathrm{Var} \, X}{t^2}

for our random AUC, this gives

P(AUC^random12t)112nt2\boxed{\mathbb P \left(\left\vert \, \widehat{\mathrm{AUC}}_\mathrm{random} - \frac 12 \right\vert \geq t \right) \leq \frac{1}{12 n t^2}}

Examples:

n = 20
print(f"{n=}")
for t in [0.1, 0.2, 0.3, 0.4]:
    print(f"Probability of AUC > {0.5+t} is less than {round(100/(12*n*t**2), 2)}%")
    n=20
    Probability of AUC > 0.6 is less than 41.67%
    Probability of AUC > 0.7 is less than 10.42%
    Probability of AUC > 0.8 is less than 4.63%
    Probability of AUC > 0.9 is less than 2.6%

Proof that ROC AUC becomes the sum of scores for class 1

Recall that, above, we defined ZiZ_i as

A^=1n(Nn)i=1nj=1Nn1PiQj=1ni=1nZi\hat A = \frac{1}{n(N-n)} \sum_{i=1}^{n} \sum_{j=1}^{N-n} 1_{P_i \geq Q_j} = \frac{1}{n} \sum_{i=1}^n Z_i

where

ZiZi(N)=1NnjJ1PiQj.Z_i \equiv Z_i^{(N)} = \frac{1}{N-n} \sum_{j\in J} 1_{P_i \geq Q_j}.

We have shown that as NN grows this variable becomes uniform. We can actually prove something stronger: that ZiZ_i essentially becomes PiP_i itself!

The intuition here is that, as NN grows large, the QjQ_j‘s basically cover the whole [0,1][0,1] interval, and since ZiZ_i cares only about their aggregated values, it essencially becomes independent of them.

More precisely: let QJ{Qj:jJ}Q_J \equiv \{Q_j: j \in J\} be a shorthand for all the scores in class 0. We will show three results:

  • Proposition 1: ZiQJZ_i\vert Q_J converges on the mean to PiP_i, ie.

    limNE[Zi(N)Pi  QJ]=0\lim_{N\to\infty} \mathbb E\left[\left.Z_i^{(N)} - P_i \;\right\vert Q_J\right] = 0
  • Corollary: ZiQJZ_i\vert Q_J converges in probability to PiP_i, ie.

    limNP(Zi(N)Pia  QJ)=0,a>0\lim_{N\to\infty} \mathbb P\left(\left.\vert Z_i^{(N)} - P_i\vert \geq a \;\right\vert Q_J\right) = 0,\qquad \forall a > 0
  • Proposition 2: ZiQJZ_i\vert Q_J converges in the mean-squared sense to PiP_i, ie.

    limNE[(Zi(N)Pi)2  QJ]=0\boxed{\lim_{N\to\infty} \mathbb E\left[\left. \left(Z_i^{(N)} - P_i \right)^2\;\right\vert Q_J\right] = 0}

Proposition 2 alone implies Proposition 1 and the Corollary. We leave them here for completeness, and because the machinery is basically the same.

Since PiP_i is independent of QJQ_J, this shows that the (conditional on QJQ_J) variable ZiZ_i converges to the (unconditional on QJQ_J) variable PiP_i. The problem is so unbalanced that the probabilities of the majority class are essentially “integrated out”, and only the scores of the minority class remain.

In practice, this means that

AUC^1ni:yi=1Pi(very high imbalance, random scoring)\boxed{\widehat{\mathrm{AUC}} \approx \frac{1}{n} \sum_{i: y_i=1} P_i} \quad \text{(very high imbalance, random scoring)}

In what follows, we write NnMN-n \equiv M to unclutter notation.

Proof of Proposition 1: by direct evaluation, using that the variable 1PiQjQj1_{P_i \geq Q_j} \, \vert Q_j is Bernoulli with parameter 1Qj1-Q_j, we get

E[Zi(N)Pi  QJ]=1MjE[1PiQjQj]E[Pi]=1Mj(1Qj)12=121MjJQj\begin{align*} \mathbb E\left[\left.Z_i^{(N)} - P_i \;\right\vert Q_J\right] &= \frac{1}{M} \sum_j \mathbb E[1_{P_i \geq Q_j}\,\vert Q_j]- \mathbb E[P_i]\\ &=\frac 1M \sum_j (1-Q_j) - \frac 12\\ &= \frac 12 - \frac 1M \sum_{j\in J} Q_j \end{align*}

As MM (thus NN) grows larger, intuitively, the QjQ_j cover [0,1][0,1] and so the sum above becomes a Riemann sum. We get

limNE[Zi(N)Pi  QJ]=1201qdq=1212=0\begin{align*} \lim_{N\to\infty}\mathbb E\left[\left.Z_i^{(N)} - P_i \;\right\vert Q_J\right] &= \frac 12 - \int_0^1 q\, dq \\ &=\frac 12 - \frac 12\\ &= 0 \end{align*}

as we wanted to prove.

Proof of Corollary. Recall Markov’s inequality: if XX is an integrable, non-negative random variable, then

P(Xt)E[X]t\mathbb P(X \geq t) \leq \frac{\mathbb E[X]}{t}

Setting X=(Zi(N)Pi)  QJX = (\left.Z_i^{(N)} - P_i )\;\right\vert Q_J and taking the limit gives the proof.

Proof of Proposition 2: we want to prove that

limNE[(Zi(N)Pi)2  QJ]=0.\lim_{N\to\infty} \mathbb E\left[\left. \left(Z_i^{(N)} - P_i \right)^2\;\right\vert Q_J\right] = 0.

To do that, we compute the square

E[(Zi(N)Pi)2  QJ]=E[(Zi(N))2QJ]()2E[PiZi(N)QJ]()+E[Pi2QJ]()\mathbb E\left[\left. \left(Z_i^{(N)} - P_i \right)^2\;\right\vert Q_J\right] = \underbrace{\mathbb E\left[\left.(Z_i^{(N)})^2\,\right\vert Q_J\right]}_{(\star)} - 2 \underbrace{\mathbb E\left[\left. P_i Z_i^{(N)} \,\right\vert Q_J\right]}_{(\star \star)} + \underbrace{\mathbb E\left[\left.P_i^2\,\right\vert Q_J\right]}_{(\star \star \star)}

We compute one term at a time. (){(\star \star \star)} is the easiest: since PiUniform([0,1])P_i \,\sim\,\mathrm{Uniform}([0,1]) is independent of QJQ_J, this is just

E[Pi2QJ]=13\mathbb E\left[\left.P_i^2\,\right\vert Q_J\right] = \frac 13

For ()(\star \star), we need to explicitly compute the expectation; then, taking the limit, we will find a Riemann sum. We have

E[PiZi(N)QJ]=1MjE[Pi1PiQjQj]=1Mj01p1pQjdp=1MjQj1pdp=1Mj(1Qj22)N011q22dq=13\begin{align*} \mathbb E\left[\left. P_i Z_i^{(N)} \,\right\vert Q_J\right] &= \frac 1M \sum_j \mathbb E\left[\left. P_i 1_{P_i \geq Q_j}\,\right\vert Q_j\right] \\ &= \frac 1M \sum_j \int_0^1 p 1_{p \geq Q_j} \, dp = \frac 1M \sum_j \int_{Q_j}^1 p\, dp \\ &= \frac 1M \sum_j \left( \frac{1-Q_j^2}{2}\right)\\ &\xrightarrow[N \to \infty]{} \int_0^1 \frac{1 - q^2}{2} dq\\ &= \frac 13 \end{align*}

Finally, for ()(\star), the procedure is technically more involved but basically identical:

E[(Zi(N))2QJ]=E[1M2jJkJ1PiQj1PiQk  QJ]=1M2E[jJ1PiQj+2jk<j1PiQj1PiQk  QJ]\begin{align*} \mathbb E\left[\left.(Z_i^{(N)})^2\,\right\vert Q_J\right] &= \mathbb E \left[\left. \frac{1}{M^2} \sum_{j \in J} \sum_{k\in J} 1_{P_i \geq Q_j} 1_{P_i \geq Q_k} \;\right\vert Q_J\right]\\ &=\frac{1}{M^2} \mathbb E \left[\left.\sum_{j \in J} 1_{P_i \geq Q_j} + 2 \sum_j \sum_{k < j} 1_{P_i \geq Q_j} 1_{P_i \geq Q_k} \;\right\vert Q_J\right]\\ \end{align*}

With no loss of generality, order the QjQ_j‘s in an ascending order, so that QjQkQ_j \geq Q_k if j>kj > k. We can then simplify the second sum by considering that PiP_i must be larger than max(Qj,Qk)=Qj\max(Q_j, Q_k) = Q_j. Hence

E[(Zi(N))2QJ]=1M2[jE[1PiQjQj]+2jk<jE[1PiQjQj]]=1M2[j(1Qj)+2jk<j(1Qj)]=1M[1Mj(1Qj)]+2M2jk<j(1Qj)\begin{align*} \mathbb E\left[\left.(Z_i^{(N)})^2\,\right\vert Q_J\right] &= \frac{1}{M^2}\left[ \sum_j \mathbb E\left[\left.1_{P_i \geq Q_j}\,\right\vert Q_j\right] + 2 \sum_j \sum_{k < j} \mathbb E\left[\left.1_{P_i \geq Q_j}\,\right\vert Q_j\right] \right]\\ &= \frac{1}{M^2}\left[\sum_j (1-Q_j) + 2 \sum_j \sum_{k < j} (1-Q_j)\right]\\ &= \frac{1}{M} \left[\frac{1}{M}\sum_j (1-Q_j)\right] + \frac{2}{M^2} \sum_j \sum_{k < j} (1-Q_j) \end{align*}

Upon taking the limit, the first term will be killed by the excess 1/M1/M term in front; the second one becomes the double sum

E[(Zi(N))2QJ]N0+201dq0qdx(1q)=201dqq(1q)=13.\begin{align*} \mathbb E\left[\left.(Z_i^{(N)})^2\,\right\vert Q_J\right] &\xrightarrow[N \to \infty]{} 0 + 2 \int_0^1 dq \int_0^q dx \, (1-q)\\ &= 2 \int_0^1 dq \, q(1-q)\\ &= \frac 13. \end{align*}

Hence, putting all results ()(\star) to ()(\star \star \star) together, we get

limNE[(Zi(N)Pi)2  QJ]=13213+13=0\lim_{N\to\infty} \mathbb E\left[\left. \left(Z_i^{(N)} - P_i \right)^2\;\right\vert Q_J\right] = \frac 13 - 2 \cdot \frac 13 + \frac 13 = 0

This proves Proposition 2.

Simulating this result

Below, we test

AUC^1ni:yi=1Pi(very high imbalance, random scoring)\widehat{\mathrm{AUC}} \approx \frac{1}{n} \sum_{i: y_i=1} P_i \quad \text{(very high imbalance, random scoring)}

basically by creating a highly imbalanced dataset with only 15 points of class 1, and comparing the ROC AUC calculation with the average of the scores predicted for class 1.

from sklearn.metrics import roc_auc_score, roc_curve

def fixed_imbalanced_dataset(total_samples=20000, 
                            class_1_samples=15):
    import pandas as pd
    from sklearn.datasets import make_classification
    
    X, y = make_classification(n_samples=total_samples,
                               weights=(0.8,),
                               random_state=4)

    df = pd.DataFrame(X)
    df['y'] = y
    df0 = df[df['y']==0]
    df1 = df[df['y']==1]

    df1_red = df1.sample(n=class_1_samples)

    df_new = pd.concat([df1_red, df0]).sample(frac=1)
    X, y = df_new.drop('y', axis=1).values, df_new['y'].values
    
    return X, y
X, y = fixed_imbalanced_dataset()
np.bincount(y)
    array([15947,    15])
# create random prediction
for i, seed in enumerate([12,51,25,62]):
    np.random.seed(seed)
    y_pred = np.random.rand(*y.shape)
    
    roc_auc = roc_auc_score(y, y_pred)
    mean_prediction = y_pred[y==1].mean()
    print(f"Trial {i+1}:")
    print(f"  - ROC AUC           : {round(roc_auc,3)}")
    print(f"  - Mean score class 1: {round(mean_prediction,3)}")
    Trial 1:
      - ROC AUC           : 0.594
      - Mean score class 1: 0.593
    Trial 2:
      - ROC AUC           : 0.557
      - Mean score class 1: 0.558
    Trial 3:
      - ROC AUC           : 0.549
      - Mean score class 1: 0.551
    Trial 4:
      - ROC AUC           : 0.457
      - Mean score class 1: 0.456

We see everything works: in this extremely imbalanced case, indeed the ROC AUC matches the mean predicted probabilities for the minority class!

References

[1] Cortes, Corinna and Mohri, Mehryar, Confidence Intervals for the Area Under the ROC Curve. Advances in Neural Information Processing Systems, 17 (2004).

[2] S. Shirahata, Estimate of variance of Wilcoxon-Mann-Whitney statistic. J. Japanese Soc. Comp. Statist. 6.2(1993), 1-10.