TD4: Loi normale (RICM4, 2013)

L'objectif de cette fiche est de se familiariser avec la loi normale.

Densité

Commençons par tracer la densité de la la loi normale. Voici une première version avec les outils de base:

plot(dnorm, xlim = c(-5, 5))

plot of chunk unnamed-chunk-1

Et une deuxième version avec ggplot2:

library(ggplot2)
ggplot(data.frame(x = c(-5, 5)), aes(x)) + stat_function(fun = dnorm, args = list(mean = 0, 
    sd = 1)) + theme_bw()

plot of chunk unnamed-chunk-2

J'espère qu'il est bien clair que l'histogramme d'un échantillon est une approximation de la fonction de densité.

Traçon la même chose en ajoutant avec la fonction de répartition (i.e., la cumulative):

ggplot(data.frame(x = c(-5, 5)), aes(x)) + stat_function(fun = dnorm) + stat_function(fun = pnorm, 
    color = "red") + theme_bw()

plot of chunk unnamed-chunk-3

De même l'équivalent de la fonction de répartition pour un échantillon est la fonction ecdf.

Et enfin, l'inverse de la fonction de répartition (notez bien le domaine de définition):

ggplot(data.frame(x = c(0, 1)), aes(x)) + stat_function(fun = qnorm) + theme_bw()

plot of chunk unnamed-chunk-4

Évidemment, pour une loi non bornée, on a deux asymptotes en 0 et en 1…

Maintenant, même si ces variables aléatoires ne sont pas bornées, de grandes déviations de la moyenne restent très très rares:

pnorm(1) - pnorm(-1)
## [1] 0.6827
pnorm(2) - pnorm(-2)
## [1] 0.9545
pnorm(3) - pnorm(-3)
## [1] 0.9973

Wow. Moins de 3 pour mille au delà de 3…

Linéarité et Convolution

x = rnorm(1000)
y = rnorm(1000)

“Vérifions” la linéarité.

ggplot(data.frame(x = c(4 + 3 * x)), aes(x)) + geom_histogram(aes(y = ..density..)) + 
    stat_function(fun = dnorm, args = list(mean = 4, sd = 3)) + theme_bw()
## stat_bin: binwidth defaulted to range/30. Use 'binwidth = x' to adjust this.

plot of chunk unnamed-chunk-7

“Vérifions” la convolution:

ggplot(data.frame(x = c(4 + 3 * x + 2 * y)), aes(x)) + geom_histogram(aes(y = ..density..)) + 
    stat_function(fun = dnorm, args = list(mean = 4, sd = sqrt(9 + 4))) + theme_bw()
## stat_bin: binwidth defaulted to range/30. Use 'binwidth = x' to adjust this.

plot of chunk unnamed-chunk-8

Et tentons une comparaison différente de celle de l'histogramme, la comparaison des quantiles:

ggplot(data.frame(x = c(4 + 3 * x + 2 * y)), aes(sample = x)) + stat_qq() + 
    theme_bw() + coord_fixed() + geom_vline(xintercept = 0) + geom_hline(yintercept = 0)

plot of chunk unnamed-chunk-9

Méthode de génération “historique”

n = 1000
x = seq(0, 0, length.out = n)
for (i in (1:12)) {
    x = x + runif(n)
}
x = x - 6

Regardons l'histogramme:

ggplot(data.frame(x = x), aes(x)) + geom_histogram(aes(y = ..density..)) + stat_function(fun = dnorm) + 
    theme_bw()
## stat_bin: binwidth defaulted to range/30. Use 'binwidth = x' to adjust this.

plot of chunk unnamed-chunk-11

Et comparons les quantiles:

ggplot(data.frame(x = x), aes(sample = x)) + stat_qq() + theme_bw() + coord_fixed() + 
    geom_vline(xintercept = 0) + geom_hline(yintercept = 0)

plot of chunk unnamed-chunk-12

Surprenant, hein ? C'est la magie du théorème central limite que nous verrons la prochaine fois…

Méthode de Box Müller

Tirons donc des points au hasard dans le plan:

x = runif(10000, min = -1, max = 1)
y = runif(10000, min = -1, max = 1)
ggplot(data.frame(x = x, y = y), aes(x = x, y = y)) + stat_bin2d() + coord_fixed() + 
    geom_vline(xintercept = 0) + geom_hline(yintercept = 0)

plot of chunk unnamed-chunk-13

Pas de surprise, c'est uniforme dans le carré \( [0,1]\times[0,1] \). Que se passe-t-il si on fait pareil avec la loi uniforme ?

x = rnorm(10000)
y = rnorm(10000)
df = data.frame(x = x, y = y)
ggplot(df, aes(x = x, y = y)) + stat_bin2d() + coord_fixed() + geom_vline(xintercept = 0) + 
    geom_hline(yintercept = 0)

plot of chunk unnamed-chunk-14

Étonnant, c'est circulaire… C'est donc invariant par rotation! Et donc, l'angle en polaire est uniforme dans \( [0,2\pi] \). Et le carré du rayon, à quoi ressemble-t-il ?

df$r = sqrt(df$x^2 + df$y^2)
ggplot(df, aes(x = r^2)) + geom_histogram(aes(y = ..density..)) + stat_function(fun = dexp, 
    args = list(rate = 1/2)) + theme_bw()
## stat_bin: binwidth defaulted to range/30. Use 'binwidth = x' to adjust this.

plot of chunk unnamed-chunk-15

Donc soient \( U_1 \) et \( U_2 \) deux variables aléatoires indépendantes uniformément distribuées dans [0,1]. Définissons \( Z_0 = R \cos(\Theta) =\sqrt{-2 \ln U_1} \cos(2 \pi U_2)\ \) et \( Z_1 = R \sin(\Theta) = \sqrt{-2 \ln U_1} \sin(2 \pi U_2).\, \). Alors \( Z_0 \) et \( Z_1 \) sont des variables aléatoires indépendantes suivant une loi normale de variance 1.

u1 = runif(10000)
u2 = runif(10000)
df = data.frame(u1 = u1, u2 = u2)
df$r = sqrt(-2 * log(df$u1))
df$theta = 2 * pi * df$u2
df$x = df$r * cos(df$theta)
df$y = df$r * sin(df$theta)

Regardons l'histogramme:

ggplot(data.frame(x = c(df$x, df$y)), aes(x)) + geom_histogram(aes(y = ..density..)) + 
    stat_function(fun = dnorm) + theme_bw()
## stat_bin: binwidth defaulted to range/30. Use 'binwidth = x' to adjust this.

plot of chunk unnamed-chunk-17

Pas mal. Cependant, on utilise peu cette méthode en pratique car elle utilise des fonctions trigonométriques, coûteuses en temps de calcul. On préfère des méthodes de rejet…

Être normal...