Nous pouvons d'abord réduire cela pour ne dépendre que de certains moments de distributions normales tronquées univariées / bivariées: notons bien sûr que
E[ Z+] = [ E[ ( Zje)+]]jeCov( Z+) = [ Cov( ( Zje)+, ( Zj)+)]je j,
et parce que nous faisons des transformations coordonnées de certaines dimensions d'une distribution normale, nous ne besoin de s'inquiéter de la moyenne et de la variance d'une normale 1d censurée et de la covariance de deux normales 1d censurées.
Nous utiliserons quelques résultats de
S Rosenbaum (1961). Moments d'une distribution normale bivariée tronquée . JRSS B, vol 23 pp 405-408. ( jstor )
Rosenbaum considère
et considère la troncature à l'événement .V={˜X≥aX,˜Y≥aY}
[ X~Oui~] ∼ N( [ 00] , [ 1ρρ1] ) ,
V= { X~≥ aX, Y~≥ aOui}
Plus précisément, nous utiliserons les trois résultats suivants, ses (1), (3) et (5). Définissez d'abord les éléments suivants:
qX= ϕ ( aX)qy= ϕ ( ay)QX= Φ ( - aX)Qy= Φ ( - ay)Rx y= Φ ( ρ aX- uny1 - ρ2-----√)RyX= Φ ( ρ ay- unX1 - ρ2-----√)rx y= 1 - ρ2-----√2 π--√ϕ ( h2- 2 ρ h k + k21 - ρ2-------------√)
Maintenant, Rosenbaum montre que:
Pr ( V) E[ X~∣ V]Pr ( V) E[ X~2∣ V]Pr ( V) E[ X~Oui~∣ V]= qXRx y+ ρ qyRyX= Pr ( V) + aXqXRx y+ ρ2uneyqyRyX+ ρ rx y= ρ Pr ( V) + ρ aXqXRx y+ ρ ayqyRyX+ rx y.(1)(3)(5)
Il sera utile de considérer également le cas particulier de (1) et (3) avec , c'est-à-dire une troncature 1d:
uney= - ∞
Pr(V)E[X~∣V]Pr(V)E[X~2∣V]=qx=Pr(V)=Qx.(*)(**)
Nous voulons maintenant considérer
[XY]=[μxμy]+[σx00σy][X~Y~]∼N([μXμY],[σ2xρσxσyρσxσyσ2y])=N(μ,Σ).
Nous utiliserons
qui sont les valeurs de et lorsque , .
ax=−μxσxay=−μyσy,
X~Y~X=0Y=0
Maintenant, en utilisant (*), nous obtenons
et en utilisant à la fois (*) et (**) donne
afin que
E[X+]=Pr(X+>0)E[X∣X>0]+Pr(X+=0)0=Pr(X>0)(μx+σxE[X~∣X~≥ax])=Qxμx+qxσx,
E[X2+]=Pr(X+>0)E[X2∣X>0]+Pr(X+=0)0=Pr(X~≥ax)E[(μx+σxX~)2∣X~≥ax]=Pr(X~≥ax)E[μ2x+μxσxX~+σ2xX~2∣X~≥ax]=Qxμ2x+qxμxσx+Qxσ2x
Var[X+]=E[X2+]−E[X+]2=Qxμ2x+qxμxσx+Qxσ2x−Q2xμ2x−q2xσ2x−2qxQxμxσx=Qx(1−Qx)μ2x+(1−2Qx)qxμxσx+(Qx−q2x)σ2x.
Pour trouver , nous aurons besoin
Cov(X+,Y+)
E[X+Y+]=Pr(V)E[XY∣V]+Pr(¬V)0=Pr(V)E[(μx+σxX~)(μy+σyY~)∣V]=μxμyPr(V)+μyσxPr(V)E[X~∣V]+μxσyPr(V)E[Y~∣V]+σxσyPr(V)E[X~Y~∣V]=μxμyPr(V)+μyσx(qxRxy+ρqyRyx)+μxσy(ρqxRxy+qyRyx)+σxσy(ρPr(V)−ρμxqxRxy/σx−ρμyqyRyx/σy+rxy)=(μxμy+σxσyρ)Pr(V)+(μyσx+μxσyρ−ρμxσy)qxRxy+(μyσxρ+μxσy−ρμyσx)qyRyx+σxσyrxy=(μxμy+Σxy)Pr(V)+μyσxqxRxy+μxσyqyRyx+σxσyrxy,
puis en soustrayant nous obtenons
E[X+]E[Y+]Cov(X+,Y+)=(μxμy+Σxy)Pr(V)+μyσxqxRxy+μxσyqyRyx+σxσyrxy−(Qxμx+qxσx)(Qyμy+qyσy).
Voici du code Python pour calculer les moments:
import numpy as np
from scipy import stats
def relu_mvn_mean_cov(mu, Sigma):
mu = np.asarray(mu, dtype=float)
Sigma = np.asarray(Sigma, dtype=float)
d, = mu.shape
assert Sigma.shape == (d, d)
x = (slice(None), np.newaxis)
y = (np.newaxis, slice(None))
sigma2s = np.diagonal(Sigma)
sigmas = np.sqrt(sigma2s)
rhos = Sigma / sigmas[x] / sigmas[y]
prob = np.empty((d, d)) # prob[i, j] = Pr(X_i > 0, X_j > 0)
zero = np.zeros(d)
for i in range(d):
prob[i, i] = np.nan
for j in range(i + 1, d):
# Pr(X > 0) = Pr(-X < 0); X ~ N(mu, S) => -X ~ N(-mu, S)
s = [i, j]
prob[i, j] = prob[j, i] = stats.multivariate_normal.cdf(
zero[s], mean=-mu[s], cov=Sigma[np.ix_(s, s)])
mu_sigs = mu / sigmas
Q = stats.norm.cdf(mu_sigs)
q = stats.norm.pdf(mu_sigs)
mean = Q * mu + q * sigmas
# rho_cs is sqrt(1 - rhos**2); but don't calculate diagonal, because
# it'll just be zero and we're dividing by it (but not using result)
# use inf instead of nan; stats.norm.cdf doesn't like nan inputs
rho_cs = 1 - rhos**2
np.fill_diagonal(rho_cs, np.inf)
np.sqrt(rho_cs, out=rho_cs)
R = stats.norm.cdf((mu_sigs[y] - rhos * mu_sigs[x]) / rho_cs)
mu_sigs_sq = mu_sigs ** 2
r_num = mu_sigs_sq[x] + mu_sigs_sq[y] - 2 * rhos * mu_sigs[x] * mu_sigs[y]
np.fill_diagonal(r_num, 1) # don't want slightly negative numerator here
r = rho_cs / np.sqrt(2 * np.pi) * stats.norm.pdf(np.sqrt(r_num) / rho_cs)
bit = mu[y] * sigmas[x] * q[x] * R
cov = (
(mu[x] * mu[y] + Sigma) * prob
+ bit + bit.T
+ sigmas[x] * sigmas[y] * r
- mean[x] * mean[y])
cov[range(d), range(d)] = (
Q * (1 - Q) * mu**2 + (1 - 2 * Q) * q * mu * sigmas
+ (Q - q**2) * sigma2s)
return mean, cov
et un test de Monte Carlo que cela fonctionne:
np.random.seed(12)
d = 4
mu = np.random.randn(d)
L = np.random.randn(d, d)
Sigma = L.T.dot(L)
dist = stats.multivariate_normal(mu, Sigma)
mn, cov = relu_mvn_mean_cov(mu, Sigma)
samps = dist.rvs(10**7)
mn_est = samps.mean(axis=0)
cov_est = np.cov(samps, rowvar=False)
print(np.max(np.abs(mn - mn_est)), np.max(np.abs(cov - cov_est)))
ce qui donne 0.000572145310512 0.00298692620286
, indiquant que l'espérance et la covariance revendiquées correspondent aux estimations de Monte Carlo (sur la base de échantillons).10,000,000