Reproduire la figure de «l'inférence statistique de l'âge de l'ordinateur» d'Efron et Hastie


8

La version résumée de ma question

(26 décembre 2018)

J'essaie de reproduire la figure 2.2 de l' inférence statistique de l'âge de l' ordinateur par Efron et Hastie, mais pour une raison que je ne peux pas comprendre, les chiffres ne correspondent pas à ceux du livre.

Supposons que nous essayons de décider entre deux fonctions de densité de probabilité possibles pour les données observées , une densité d'hypothèse nulle et une densité alternative . Une règle de test dit quel choix, ou , nous ferons après avoir observé les données . Toute règle de ce type a deux probabilités d'erreur fréquentiste associées: choisir alors que réellement généré , et vice versa,XF0(X)F1(X)t(X)01XF1F0X

α=PrF0{t(X)=1},
β=PrF1{t(X)=0}.

Soit le rapport de vraisemblance ,L(X)

L(X)=F1(X)F0(X)

Ainsi, le lemme de Neyman – Pearson dit que la règle de test de la forme est l'algorithme de test d'hypothèse optimaltc(X)

tc(X)={1si journal L(X)c0si journal L(X)<c.

Pour , et la taille de l'échantillon quelles seraient les valeurs pour et pour une coupure ?F0N(0,1),F1N(0,5,1)n=dixαβc=0,4

  • À partir de la figure 2.2 de l' inférence statistique de l'ère informatique par Efron et Hastie, nous avons:
    • α=0,10 et pour une coupureβ=0,38c=0,4
  • J'ai trouvé et pour un seuil de coupure utilisant deux approches différentes: A) simulation et B) analytiquement .α=0,15β=0,30c=0,4

J'apprécierais que quelqu'un m'explique comment obtenir et pour un seuil de coupure . Merci.α=0,10β=0,38c=0,4

La version résumée de ma question se termine ici. A partir de maintenant, vous trouverez:

  • Dans la section A) les détails et le code python complet de mon approche de simulation .
  • Dans la section B) les détails et le code python complet de l' approche analytique .

A) Mon approche de simulation avec code python complet et explications

(20 décembre 2018)

Du livre ...

Dans le même esprit, le lemme de Neyman – Pearson fournit un algorithme de test d'hypothèse optimal. C'est peut-être la plus élégante des constructions fréquentistes. Dans sa formulation la plus simple, le lemme NP suppose que nous essayons de décider entre deux fonctions de densité de probabilité possibles pour les données observées , une densité d'hypothèse nulle et une densité alternative . Une règle de test dit quel choix, ou , nous ferons après avoir observé les données . Une telle règle a deux probabilités d'erreur fréquentiste associées: choisir lorsque réellement généréXF0(X)F1(X)t(X)01XF1F0X , et vice versa,

α=PrF0{t(X)=1},
β=PrF1{t(X)=0}.

Soit le rapport de vraisemblance , L(X)

L(X)=F1(X)F0(X)

(Source: Efron, B. et Hastie, T. (2016). Computer Age Statistical Inference: Algorithms, Evidence, and Data Science. Cambridge: Cambridge University Press. )

J'ai donc implémenté le code python ci-dessous ...

import numpy as np

def likelihood_ratio(x, f1_density, f0_density):
    return np.prod(f1_density.pdf(x)) / np.prod(f0_density.pdf(x))

Encore une fois, du livre ...

et définir la règle de test par tc(X)

tc(X)={1si journal L(X)c0si journal L(X)<c.

(Source: Efron, B. et Hastie, T. (2016). Computer Age Statistical Inference: Algorithms, Evidence, and Data Science. Cambridge: Cambridge University Press. )

J'ai donc implémenté le code python ci-dessous ...

def Neyman_Pearson_testing_rule(x, cutoff, f0_density, f1_density):
    lr = likelihood_ratio(x, f1_density, f0_density)
    llr = np.log(lr)

    if llr >= cutoff:
        return 1
    else:
        return 0

Enfin, du livre ...

entrez la description de l'image ici

Où il est possible de conclure qu'un seuil de coupure impliquera et .c=0,4α=0,10β=0,38

J'ai donc implémenté le code python ci-dessous ...

def alpha_simulation(cutoff, f0_density, f1_density, sample_size, replicates):
    NP_test_results = []

    for _ in range(replicates):
        x = f0_density.rvs(size=sample_size)
        test = Neyman_Pearson_testing_rule(x, cutoff, f0_density, f1_density)
        NP_test_results.append(test)

    return np.sum(NP_test_results) / float(replicates)

def beta_simulation(cutoff, f0_density, f1_density, sample_size, replicates):
    NP_test_results = []

    for _ in range(replicates):
        x = f1_density.rvs(size=sample_size)
        test = Neyman_Pearson_testing_rule(x, cutoff, f0_density, f1_density)
        NP_test_results.append(test)

    return (replicates - np.sum(NP_test_results)) / float(replicates)

et le code ...

from scipy import stats as st

f0_density = st.norm(loc=0, scale=1)
f1_density = st.norm(loc=0.5, scale=1)

sample_size = 10
replicates = 12000

cutoffs = []
alphas_simulated = []
betas_simulated = []
for cutoff in np.arange(3.2, -3.6, -0.4):
    alpha_ = alpha_simulation(cutoff, f0_density, f1_density, sample_size, replicates)
    beta_ = beta_simulation(cutoff, f0_density, f1_density, sample_size, replicates)

    cutoffs.append(cutoff)
    alphas_simulated.append(alpha_)
    betas_simulated.append(beta_)

et le code ...

import matplotlib.pyplot as plt
%matplotlib inline

# Reproducing Figure 2.2 from simulation results.
plt.xlabel('$\\alpha$')
plt.ylabel('$\\beta$')
plt.xlim(-0.1, 1.05)
plt.ylim(-0.1, 1.05)
plt.axvline(x=0, color='b', linestyle='--')
plt.axvline(x=1, color='b', linestyle='--')
plt.axhline(y=0, color='b', linestyle='--')
plt.axhline(y=1, color='b', linestyle='--')
figure_2_2 = plt.plot(alphas_simulated, betas_simulated, 'ro', alphas_simulated, betas_simulated, 'k-')

pour obtenir quelque chose comme ça:

entrez la description de l'image ici

qui ressemble à la figure originale du livre, mais les 3-tuples de ma simulation ont des valeurs différentes de et par rapport à celles du livre pour la même coupure . Par exemple:(c,α,β)αβc

  • du livre que nous avons(c=0,4,α=0,10,β=0,38)
  • de ma simulation, nous avons:
    • (c=0,4,α=0,15,β=0,30)
    • (c=0,8,α=0,10,β=0,39)

Il semble que le seuil de coupure de ma simulation soit équivalent au seuil de coupure du livre.c=0,8c=0,4

J'apprécierais que quelqu'un m'explique ce que je fais mal ici. Merci.

B) Mon approche de calcul avec code python complet et explications

(26 décembre 2018)

Toujours en essayant de comprendre la différence entre les résultats de ma simulation ( alpha_simulation(.), beta_simulation(.)) et ceux présentés dans le livre, avec l'aide d'un de mes amis statisticien (Sofia), nous avons calculé et analytiquement au lieu de via la simulation, donc .. .αβ

Une fois que

F0N(0,1)
F1N(0,5,1)

puis

F(X|μ,σ2)=je=1n12πσ2e-(Xje-μ)22σ2

De plus,

L(X)=F1(X)F0(X)

donc,

L(X)=F1(X|μ1,σ2)F0(X|μ0,σ2)=je=1n12πσ2e-(Xje-μ1)22σ2je=1n12πσ2e-(Xje-μ0)22σ2

Par conséquent, en effectuant quelques simplifications algébriques (comme ci-dessous), nous aurons:

L(X)=(12πσ2)ne-je=1n(Xje-μ1)22σ2(12πσ2)ne-je=1n(Xje-μ0)22σ2

=e-je=1n(Xje-μ1)2+je=1n(Xje-μ0)22σ2

=e-je=1n(Xje2-2Xjeμ1+μ12)+je=1n(Xje2-2Xjeμ0+μ02)2σ2

=e-je=1nXje2+2μ1je=1nXje-je=1nμ12+je=1nXje2-2μ0je=1nXje+je=1nμ022σ2

=e2(μ1-μ0)je=1nXje+n(μ02-μ12)2σ2
.

Donc si

tc(X)={1si journal L(X)c0si journal L(X)<c.

alors, pour nous aurons:Journal L(X)c

Journal (e2(μ1-μ0)je=1nXje+n(μ02-μ12)2σ2)c

2(μ1-μ0)je=1nXje+n(μ02-μ12)2σ2c

je=1nXje2cσ2-n(μ02-μ12)2(μ1-μ0)

je=1nXje2cσ22(μ1-μ0)-n(μ02-μ12)2(μ1-μ0)

je=1nXjecσ2(μ1-μ0)-n(μ02-μ12)2(μ1-μ0)

je=1nXjecσ2(μ1-μ0)+n(μ12-μ02)2(μ1-μ0)

je=1nXjecσ2(μ1-μ0)+n(μ1-μ0)(μ1+μ0)2(μ1-μ0)

je=1nXjecσ2(μ1-μ0)+n(μ1+μ0)2

(1n)je=1nXje(1n)(cσ2(μ1-μ0)+n(μ1+μ0)2)

je=1nXjencσ2n(μ1-μ0)+(μ1+μ0)2

X¯cσ2n(μ1-μ0)+(μ1+μ0)2

X¯k, où k=cσ2n(μ1-μ0)+(μ1+μ0)2

résultant en

tc(X)={1si X¯k0si X¯<k., où k=cσ2n(μ1-μ0)+(μ1+μ0)2

Afin de calculer et , nous savons que:αβ

α=PrF0{t(X)=1},
β=PrF1{t(X)=0}.

donc,

α=PrF0{X¯k},β=PrF1{X¯<k}. où k=cσ2n(μ1-μ0)+(μ1+μ0)2

Pour ...α

α=PrF0{X¯k}=PrF0{X¯-μ0k-μ0}

α=PrF0{X¯-μ0σnk-μ0σn}

α=PrF0{z-scorek-μ0σn} où k=cσ2n(μ1-μ0)+(μ1+μ0)2

j'ai donc implémenté le code python ci-dessous:

def alpha_calculation(cutoff, m_0, m_1, variance, sample_size):
    c = cutoff
    n = sample_size
    sigma = np.sqrt(variance)

    k = (c*variance)/(n*(m_1-m_0)) + (m_1+m_0)/2.0

    z_alpha = (k-m_0)/(sigma/np.sqrt(n))

    # Pr{z_score >= z_alpha}
    return 1.0 - st.norm(loc=0, scale=1).cdf(z_alpha)

Pour ...β

β=PrF1{X¯<k}=PrF1{X¯-μ1<k-μ1}

β=PrF1{X¯-μ1σn<k-μ1σn}

β=PrF1{z-score<k-μ1σn} où k=cσ2n(μ1-μ0)+(μ1+μ0)2

résultant dans le code python ci-dessous:

def beta_calculation(cutoff, m_0, m_1, variance, sample_size):
    c = cutoff
    n = sample_size
    sigma = np.sqrt(variance)

    k = (c*variance)/(n*(m_1-m_0)) + (m_1+m_0)/2.0

    z_beta = (k-m_1)/(sigma/np.sqrt(n))

    # Pr{z_score < z_beta}
    return st.norm(loc=0, scale=1).cdf(z_beta)

et le code ...

alphas_calculated = []
betas_calculated = []
for cutoff in cutoffs:
    alpha_ = alpha_calculation(cutoff, 0.0, 0.5, 1.0, sample_size)
    beta_ = beta_calculation(cutoff, 0.0, 0.5, 1.0, sample_size)

    alphas_calculated.append(alpha_)
    betas_calculated.append(beta_)

et le code ...

# Reproducing Figure 2.2 from calculation results.
plt.xlabel('$\\alpha$')
plt.ylabel('$\\beta$')
plt.xlim(-0.1, 1.05)
plt.ylim(-0.1, 1.05)
plt.axvline(x=0, color='b', linestyle='--')
plt.axvline(x=1, color='b', linestyle='--')
plt.axhline(y=0, color='b', linestyle='--')
plt.axhline(y=1, color='b', linestyle='--')
figure_2_2 = plt.plot(alphas_calculated, betas_calculated, 'ro', alphas_calculated, betas_calculated, 'k-')

pour obtenir un chiffre et des valeurs pour et très similaires à ma première simulationαβ

entrez la description de l'image ici

Et enfin de comparer côte à côte les résultats entre simulation et calcul ...

df = pd.DataFrame({
    'cutoff': np.round(cutoffs, decimals=2), 
    'simulated alpha': np.round(alphas_simulated, decimals=2),
    'simulated beta': np.round(betas_simulated, decimals=2),
    'calculated alpha': np.round(alphas_calculated, decimals=2),
    'calculate beta': np.round(betas_calculated, decimals=2)
})
df

résultant en

entrez la description de l'image ici

Cela montre que les résultats de la simulation sont très similaires (sinon les mêmes) à ceux de l'approche analytique.

En bref, j'ai encore besoin d'aide pour déterminer ce qui pourrait mal se passer dans mes calculs. Merci. :)


3
Il me semble que toute question qui oblige les lecteurs à parcourir 11 pages de code informatique, de sortie statistique et d'algèbre est peu susceptible d'être lue par quiconque, et encore moins de répondre de manière convaincante. Si vous êtes intéressé à poursuivre cela, comme vous semblez l'être du temps et de l'attention que vous y avez consacrés, puis-je vous suggérer d'identifier le nœud du problème et de voir si vous pouvez l'expliquer et poser votre question dans l'espace de une ou au plus deux pages de matériel?
whuber

1
Salut @whuber, merci pour ta suggestion! Mon intention était de publier des détails (code source et explications) pour permettre à quiconque de reproduire mes résultats, mais il semble que cette stratégie n'ait pas très bien fonctionné comme vous l'avez correctement observé :). Merci encore. J'ai ensuite édité la question pour résumer mon doute au début du post. J'espère que cela fonctionne.
Francisco Fonseca

Réponses:


3

Dans le site Web du livre Computer Age Statistical Inference , il y a une session de discussion où Trevor Hastie et Brad Efron répondent souvent à plusieurs questions. J'ai donc posté cette question (comme ci-dessous) et reçu de Trevor Hastie la confirmation qu'il y a une erreur dans le livre qui sera corrigée (en d'autres termes, mes simulations et calculs - tels qu'implémentés en Python dans cette question - sont corrects ).

entrez la description de l'image ici

Lorsque Trevor Hastie a répondu que "En fait c = 0,75 pour ce graphique" signifie que sur la figure ci-dessous (figure 2.2 originale du livre), le seuil devrait être au lieu de :cc=0,75c=0,4

entrez la description de l'image ici

Ainsi, en utilisant mes fonctions alpha_simulation(.), beta_simulation(.), alpha_calculation(.)et beta_calculation(.)(dont l'intégralité du code Python est disponible dans cette question) Je suis et pour une coupure comme une confirmation que mon code est correct.α=0,10β=0,38c=0,75

alpha_simulated_c075 = alpha_simulation(0.75, f0_density, f1_density, sample_size, replicates)
beta_simulated_c075 = beta_simulation(0.75, f0_density, f1_density, sample_size, replicates)

alpha_calculated_c075 = alpha_calculation(0.75, 0.0, 0.5, 1.0, sample_size)
beta_calculated_c075 = beta_calculation(0.75, 0.0, 0.5, 1.0, sample_size)

print("Simulated: c=0.75, alpha={0:.2f}, beta={1:.2f}".format(alpha_simulated_c075, beta_simulated_c075))
print("Calculated: c=0.75, alpha={0:.2f}, beta={1:.2f}".format(alpha_calculated_c075, beta_calculated_c075))

entrez la description de l'image ici

Enfin, lorsque Trevor Hastie a répondu que "... entraînant un seuil pour x de 0,4", cela signifie que dans l'équation ci-dessous (voir la section B de cette question):k=0,4

X¯k, où k=cσ2n(μ1-μ0)+(μ1+μ0)2

résultant en

tc(X)={1si X¯k0si X¯<k., où k=cσ2n(μ1-μ0)+(μ1+μ0)2

Donc, en Python, nous pouvons obtenir pour un seuil de coupure comme ci-dessous:k=0,4c=0,75

n = 10
m_0 = 0.0
m_1 = 0.5
variance = 1.0
c = 0.75

k = (c*variance)/(n*(m_1-m_0)) + (m_1+m_0)/2.0
threshold_for_x = k

print("threshold for x (when cutoff c=0.75) = {0:.1f}".format(threshold_for_x))

entrez la description de l'image ici

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.