Remastered: Interpolação
Este é mais um post que já foi feito faz tempo, mas eu quero repetir mais pra mostrar um truque que eu aprendi, além de deixar a programação mais clara (com um pouco de sorte).
Imagina que você conhece a função em alguns pontos. A gente teve um exemplo disso no post passado de programação dinâmica: a gente calcula o valor da função valor ou da função política em alguns pontos. A interpolação garante que na hora de otimizar a gente vai poder visitar valores da função valor entre esses pontos.
O problema é como conectar esses pontos. Os que entre vocês já fizeram análise sabem que sempre podemos arranjar um polinômio “próximo” de uma função qualquer se o espaço é compacto. Se você tem n pontos, você poderia se sentir tentado a buscar um polinômio de ordem que passe por todos os pontos.
Isso nem sempre é razoável e a função super inocente mostra porque não. Primeiro, vamos dar uma olhada nela:
É uma função não muito maluca. Eu vou usar o pacote polynomials pra gerar um polinômio de grau 50, a partir de 50 pontos equiespaçados:
A interpolação gera uma função que oscila malucamente entre os pontos. O mais curioso é que aumentar o número de pontos piora a situação. Com 50 pontos:
Isso serve como exemplo de como interpolações podem dar profundamente erradas. Nós estamos acostumados a pensar em overfitting quando a gente extrapola os dados, mas mesmo interpolações podem ser “do mal”. A interpolação claramente está fazendo um overfitting: nos pontos observados a aproximação é exata, mas fora deles é completamente maluco.
No post original eu sugeria fazer interpolação por pedaços, ligando cada pedaço por uma reta: eu vou usar o pacote Interpolations e o comando LinearInterpolation
pra isso:
Veja que ficou bem feio porque tem só 10 pedaços. Com mais pedaços a interpolação fica indistinguível da função verdadeira:
Você pode conectar os pontos por coisas que não são lineares - por exemplo, polinômios. Usar polinômios tem a vantagem que as derivadas de ordem mais alta existem - splines fazem isso e evitam o problema de oscilarem malucamente.
Mas mais interessante é que o grande problema aqui não é simplesmente o método de interpolação: é como o grid é gerado. Via de regra o grid é gerado com pontos equiespaçados - que é a maneira mais normal de pensar no problema. A gente não precisa necessariamente gerar pontos assim. Uma maneira totalmente maluca de gerar pontos é:
Que gera pontos entre . Esse grid se deve ao Chebyschev. Veja que podemos pensar em maneiras de mover e encolher/crescer o intervalo para ficar entre . Vamos criar uma função que pega uma sequência de pontos e gera o grid:
Escrevendo o post eu me dei conta que era mais simples passar e criar a sequência depois. Eu podia muito bem ter usado um for
, mas o map
é brutalmente mais conciso. Vamos ver a qualidade da interpolação:
A coisa realmente legal aqui é que aumentar a quantidade de pontos melhora a qualidade da interpolação:
Eu nunca pensaria que gerar um grid usando cosseno seria uma boa ideia!
Alguns de vocês podem ter notado que eu gerei dois grids, um para gerar a interpolação e outro para avaliar a interpolação. Se vocês ainda não sacaram, o plot é gerado conectando os pontos por segmentos de reta, então se eu fizesse o gráfico da função original com o grid da interpolação os dois iam ser indistinguíveis.
Este post basicamente deve a sua existência ao Numerical Methods in Economics do Kenneth Judd - aparentemente uma segunda edição sairá em breve.