Reproduza a figura de “Inferência Estatística da Era do Computador” de Efron e Hastie


8

A versão resumida da minha pergunta

(26 de dezembro de 2018)

Estou tentando reproduzir a Figura 2.2 da Inferência Estatística da Era do Computador de Efron e Hastie, mas por alguma razão que não sou capaz de entender, os números não são correspondentes aos do livro.

Suponha que estamos tentando decidir entre duas funções possíveis de densidade de probabilidade para os dados observados , uma densidade de hipótese nula e uma densidade alternativa . Uma regra de teste diz qual escolha, ou , faremos tendo observado os dados . Qualquer regra desse tipo tem duas probabilidades de erro frequente associadas: escolher quando na verdade gerou vice-versa,xf0(x)f1(x)t(x)0 01xf1f0 0x

α=Prf0 0{t(x)=1},
β=Prf1{t(x)=0 0}.

Seja a razão de verossimilhança ,eu(x)

eu(x)=f1(x)f0 0(x)

Portanto, o lema de Neyman – Pearson diz que a regra de teste da forma é o algoritmo ideal de teste de hipótesetc(x)

tc(x)={1se log eu(x)c0 0se log eu(x)<c.

Para f0 0N(0 0,1),f1N(0,5,1) e tamanho da amostra n=10 quais seriam os valores para α e β para um ponto de corte c=0,4 ?

  • Na Figura 2.2 da Inferência Estatística da Era do Computador por Efron e Hastie, temos:
    • α=0.10 e para um ponto de corteβ=0.38c=0.4
  • Encontrei e para um ponto de corte usando duas abordagens diferentes: A) simulação e B) analiticamente .α=0.15β=0.30c=0.4

Eu apreciaria se alguém pudesse me explicar como obter e para um ponto de corte . Obrigado.α=0.10β=0.38c=0.4

A versão resumida da minha pergunta termina aqui. A partir de agora você encontrará:

  • Na seção A), detalhes e código python completo da minha abordagem de simulação .
  • Na seção B) detalhes e código python completo da abordagem analítica .

A) Minha abordagem de simulação com código python completo e explicações

(20 de dezembro de 2018)

Do livro ...

No mesmo espírito, o lema Neyman – Pearson fornece um algoritmo ideal de teste de hipóteses. Esta é talvez a mais elegante das construções freqüentistas. Em sua formulação mais simples, o lema NP assume que estamos tentando decidir entre duas funções possíveis de densidade de probabilidade para os dados observados , uma densidade de hipótese nula e uma densidade alternativa . Uma regra de teste diz qual escolha, ou , faremos tendo observado os dados . Qualquer regra desse tipo tem duas probabilidades de erro frequente associadas: escolher quando na verdade geradoxf0(x)f1(x)t(x)01xf1f0 0x e vice-versa,

α=Prf0{t(x)=1},
β=Prf1{t(x)=0}.

Seja a razão de verossimilhança , L(x)

L(x)=f1(x)f0(x)

(Fonte: Efron, B., & Hastie, T. (2016). Inferência estatística da era do computador: algoritmos, evidências e ciência de dados. Cambridge: Cambridge University Press. )

Então, eu implementei o código python abaixo ...

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))

Mais uma vez, a partir do livro ...

e defina a regra de teste por tc(x)

tc(x)={1if log L(x)c0if log L(x)<c.

(Fonte: Efron, B., & Hastie, T. (2016). Inferência estatística da era do computador: algoritmos, evidências e ciência de dados. Cambridge: Cambridge University Press. )

Então, eu implementei o código python abaixo ...

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

Finalmente, do livro ...

insira a descrição da imagem aqui

Onde é possível concluir que um ponto de corte c=0.4 implicará α=0.10 e β=0.38 .

Então, eu implementei o código python abaixo ...

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)

e o código ...

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_)

e o código ...

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-')

para obter algo parecido com isto:

insira a descrição da imagem aqui

que se parece com a figura original do livro, mas as três tuplas (c,α,β) da minha simulação têm valores diferentes de α e β quando comparadas com as do livro para o mesmo ponto de corte c . Por exemplo:

  • do livro que temos (c=0.4,α=0.10,β=0.38)
  • da minha simulação, temos:
    • (c=0.4,α=0.15,β=0.30)
    • (c=0.8,α=0.10,β=0.39)

Parece que o ponto de corte c=0.8 da minha simulação é equivalente ao ponto de corte c=0.4 do livro.

Eu apreciaria se alguém pudesse me explicar o que estou fazendo de errado aqui. Obrigado.

B) Minha abordagem de cálculo com código python completo e explicações

(26 de dezembro de 2018)

Ainda tentando entender a diferença entre os resultados da minha simulação ( alpha_simulation(.), beta_simulation(.)) e os apresentados no livro, com a ajuda de uma estatística (Sofia) minha amiga, calculamos α e β analiticamente em vez de via simulação, então ...

Uma vez que

f0N(0,1)
f1N(0.5,1)

então

f(x|μ,σ2)=i=1n12πσ2e(xiμ)22σ2

Além disso,

L(x)=f1(x)f0(x)

tão,

L(x)=f1(x|μ1,σ2)f0(x|μ0,σ2)=i=1n12πσ2e(xiμ1)22σ2i=1n12πσ2e(xiμ0)22σ2

Portanto, realizando algumas simplificações algébricas (como abaixo), teremos:

L(x)=(12πσ2)nei=1n(xiμ1)22σ2(12πσ2)nei=1n(xiμ0)22σ2

=ei=1n(xiμ1)2+i=1n(xiμ0)22σ2

=eEu=1n(xEu2-2xEuμ1+μ12)+Eu=1n(xEu2-2xEuμ0 0+μ0 02)2σ2

=e-Eu=1nxEu2+2μ1Eu=1nxEu-Eu=1nμ12+Eu=1nxEu2-2μ0 0Eu=1nxEu+Eu=1nμ0 022σ2

=e2(μ1-μ0 0)Eu=1nxEu+n(μ0 02-μ12)2σ2

Então se

tc(x)={1se log eu(x)c0 0se log eu(x)<c.

registro eu(x)c

registro (e2(μ1-μ0 0)Eu=1nxEu+n(μ0 02-μ12)2σ2)c

2(μ1μ0)i=1nxi+n(μ02μ12)2σ2c

i=1nxi2cσ2n(μ02μ12)2(μ1μ0)

i=1nxi2cσ22(μ1μ0)n(μ02μ12)2(μ1μ0)

i=1nxicσ2(μ1μ0)n(μ02μ12)2(μ1μ0)

i=1nxicσ2(μ1μ0)+n(μ12μ02)2(μ1μ0)

i=1nxicσ2(μ1μ0)+n(μ1μ0)(μ1+μ0)2(μ1μ0)

i=1nxicσ2(μ1μ0)+n(μ1+μ0)2

(1n)i=1nxi(1n)(cσ2(μ1μ0)+n(μ1+μ0)2)

i=1nxincσ2n(μ1μ0)+(μ1+μ0)2

x¯cσ2n(μ1μ0)+(μ1+μ0)2

x¯k, where k=cσ2n(μ1μ0)+(μ1+μ0)2

resulting in

tc(x)={1if x¯k0if x¯<k., where k=cσ2n(μ1μ0)+(μ1+μ0)2

In order to calculate α and β, we know that:

α=Prf0{t(x)=1},
β=Prf1{t(x)=0}.

so,

α=Prf0{x¯k},β=Prf1{x¯<k}. where k=cσ2n(μ1μ0)+(μ1+μ0)2

For α ...

α=Prf0{x¯k}=Prf0{x¯μ0kμ0}

α=Prf0{x¯μ0σnkμ0σn}

α=Prf0{z-scorekμ0σn} where k=cσ2n(μ1μ0)+(μ1+μ0)2

so, I implemented the python code below:

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)

For β ...

β=Prf1{x¯<k}=Prf1{x¯μ1<kμ1}

β=Prf1{x¯μ1σn<kμ1σn}

β=Prf1{z-score<kμ1σn} where k=cσ2n(μ1μ0)+(μ1+μ0)2

resulting in the python code below:

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)

and the 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_)

and the 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-')

to obtain a figure and values for α and β very similar to my first simulation

insira a descrição da imagem aqui

And finally to compare the results between simulation and calculation side by side ...

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

resulting in

insira a descrição da imagem aqui

This shows that the results of the simulation are very similar (if not the same) to those of the analytical approach.

In short, I still need help figuring out what might be wrong in my calculations. Thanks. :)


3
It seems to me that any question that requires readers to wade through 11 pages of computer code, statistical output, and algebra is unlikely to be read by anybody, much less answered cogently. If you are interested in pursuing this, as you seem to be from the time and attention you have spent on it, might I suggest that you identify the crux of the matter and see if you can explain it and ask your question within the space of one or at most two pages of material?
whuber

1
Hi @whuber, thank you for your suggestion! My intention was to post details (source code and explanations) to allow anyone to reproduce my results, but it seems that this strategy did not work very well as you correctly observed :). Thank you again. Then I edited the question to summarize my doubt at the beginning of the post. I hope this works.
Francisco Fonseca

Respostas:


3

In the website of the book Computer Age Statistical Inference, there is a discussion session where Trevor Hastie and Brad Efron often reply to several questions. So, I posted this question there (as below) and received from Trevor Hastie the confirmation that there is an error in the book that will be fixed (in other words, my simulations and calculations - as implemented in Python in this question - are correct).

enter image description here

When Trevor Hastie replied that "In fact c=.75 for that plot" means that at the figure below (original Figure 2.2 from the book) the cutoff c should be c=0.75 instead of c=0.4:

enter image description here

Assim, usando minhas funções alpha_simulation(.), beta_simulation(.), alpha_calculation(.)e beta_calculation(.)(cujo o código Python completo está disponível em esta pergunta) Eu tenhoα=0,10 e β=0,38 para um ponto de corte c=0,75 como confirmação de que meu código está correto.

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))

enter image description here

Finalmente, quando Trevor Hastie respondeu que "... resultando em um limite para x de 0,4" , significa quek=0,4na equação abaixo (consulte a seção B desta pergunta):

x¯k, Onde k=cσ2n(μ1-μ0 0)+(μ1+μ0 0)2

resultando em

tc(x)={1E se x¯k0 0E se x¯<k., Onde k=cσ2n(μ1-μ0 0)+(μ1+μ0 0)2

Então, em Python podemos obter k=0,4 para um ponto de corte c=0,75 como abaixo:

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))

enter image description here

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.