Como estimar numericamente os estimadores de MLE em python quando os gradientes são muito pequenos longe da solução ideal?

7

Estou explorando como modelar um conjunto de dados usando distribuições normais com média e variância definidas como funções lineares de variáveis ​​independentes.

Algo como N ~ (f (x), g (x)).

Eu gero uma amostra aleatória como esta:

def draw(x):
    return norm(5 * x + 2, 3 *x + 4).rvs(1)[0]

Então, eu quero recuperar 5, 2 e 4 como os parâmetros para minha distribuição.

Eu gero minha amostra:

smp = np.zeros ((100,2))

for i in range(0, len(smp)):
    smp[i][0] = i
    smp[i][1] = draw(i)

A função de probabilidade é:

def lh(p):
    p_loc_b0 = p[0]
    p_loc_b1 = p[1]
    p_scl_b0 = p[2]
    p_scl_b1 = p[3]

    l = 1
    for i in range(0, len(smp)):
        x = smp[i][0]
        y = smp[i][1]
        l = l * norm(p_loc_b0 + p_loc_b1 * x, p_scl_b0 + p_scl_b1 * x).pdf(y)

    return -l

Portanto, os parâmetros para as funções lineares usadas no modelo são dados no vetor variável de p 4.

Usando scipy.optimize, posso resolver os parâmetros do MLE usando um xtol extremamente baixo e já fornecendo a solução como ponto de partida:

fmin(lh, x0=[2,5,3,4], xtol=1e-35)

O que não funciona muito bem:

Warning: Maximum number of function evaluations has been exceeded.
array([ 3.27491346,  4.69237042,  5.70317719,  3.30395462])

Elevar o xtol a valores mais altos não é bom.

Então, eu tento usar uma solução inicial longe da solução real:

>>> fmin(lh, x0=[1,1,1,1], xtol=1e-8)
Optimization terminated successfully.
         Current function value: -0.000000
         Iterations: 24
         Function evaluations: 143
array([ 1.,  1.,  1.,  1.])

O que me faz pensar:

O PDF está amplamente agrupado em torno da média e possui gradientes muito baixos, apenas a alguns desvios padrão da média, o que não deve ser bom demais para métodos numéricos.

Então, como se faz esse tipo de estimativa numérica em funções em que o gradiente está muito próximo de zero da solução?

Rodrigo Stv
fonte

Respostas:

7

Existem várias razões pelas quais você está obtendo resultados incorretos. Primeiro, considere usar a probabilidade do log em vez da probabilidade. Existem problemas numéricos com a multiplicação de muitos números pequenos (imagine se você tivesse milhões de amostras, você teria que multiplicar milhões de números pequenos para o lhd). Também é fácil fazer gradientes para métodos de otimização que exigem gradientes quando você está lidando com a probabilidade do log. Em geral, é bom ter um objetivo que é uma soma e não um produto de variáveis ​​ao lidar com problemas de otimização.

Segundo, o fmin está usando o algoritmo simplex Nelder-Mead, que não tem garantias de convergência, de acordo com a documentação do scipy . Isso significa que a convergência é totalmente aleatória e você não deve esperar encontrar parâmetros próximos aos originais. Para contornar isso, sugiro que você use um método baseado em gradiente, como descida de gradiente estocástico ou BFGS. Como você conhece o modelo generativo (os RVs são gaussianos distribuídos), você pode escrever a probabilidade e a probabilidade do log como: equações

Onde a, b, c e d são os parâmetros do seu modelo 5,2,3 e 4, respectivamente. Então pegue o gradiente com relação a [a, b, c, d] e alimente-o na entrada principal de fmin_bfgs. Observe que, devido à variação variável, o que poderia ser resolvido apenas por regressão linear agora é um problema mais desagradável.

Por fim, convém verificar os mínimos quadrados generalizados em http://en.wikipedia.org/wiki/Linear_regression#Least-squares_estimation_and_related_techniques e http://en.wikipedia.org/wiki/Heteroscedasticity , que falam sobre seu problema e oferece várias soluções disponíveis.

Boa sorte!

magicharp
fonte