Ajuste de Curvas por Mínimos Quadrados
Objetivos de Aprendizagem
- Montar um ajuste de curva como para qualquer modelo linear nos parâmetros, com a hipótese de posto que ele exige.
- Mostrar que e medir quantos dígitos as equações normais perdem contra QR num ajuste mal condicionado.
- Resolver um problema de mínimos quadrados por QR, à mão e em código, e conferi-lo contra
numpy.linalg.lstsq. - Explicar como o tamanho do resíduo muda a precisão de cada método.
- Escolher uma base e uma escala que deixem o ajuste bem condicionado, e reconhecer quando nenhuma base resolve.
Contexto e Motivação
least-squares-via-linear-algebra deduziu as equações normais duas vezes, por projeção e por gradiente, e linear-regression-as-least-squares escreveu a forma fechada para um modelo linear. Essas lições resolvem qual é a resposta. Esta pergunta como calculá-la em float64, e a fórmula acaba sendo um algoritmo ruim. É a versão de ajuste da história da matriz de Hilbert em the-matrix-condition-number.
O ajuste também termina o que a interpolação começou. polynomial-interpolation-lagrange-and-newton e splines forçam a curva a passar por todos os pontos, o que é o objetivo errado quando os dados têm ruído. Com menos parâmetros que pontos, a curva suaviza.
Teoria Central
O problema
Tome um modelo , linear nos coeficientes e possivelmente não linear em , e dados para com . Com e , ache o que minimiza . Hipótese: tem posto coluna completo. Então o minimizador é único. Sem isso há infinitos (Exemplo 6).
Por que as equações normais perdem dígitos
Da SVD vem , então com posto coluna completo
Formar e resolver por Cholesky custa cerca de flops. É barato, mas o problema entregue ao solver é condicionado como o quadrado do original, e o erro escala junto. Com , está no limite do que o float64 consegue distinguir de uma matriz singular.
QR
Escreva na forma reduzida: é com colunas ortonormais e é triangular superior. O posto coluna completo torna invertível. Substituir nas equações normais e cancelar deixa
Nada é elevado ao quadrado neste passo: , porque multiplicar por preserva a norma 2. QR de Householder custa cerca de flops, aproximadamente o dobro das equações normais quando . numpy.linalg.lstsq vai além e trabalha com os valores singulares, que também revelam o posto numérico.
O que o resíduo faz
A sensibilidade dos mínimos quadrados não é simplesmente . Ela tem um termo perto de e um termo em , onde é o ângulo entre e a imagem de . O segundo termo domina quando chega a cerca de , que é para , então um resíduo que parece minúsculo já pode acioná-lo. Assim, QR nem sempre escapa de : ele acompanha a sensibilidade verdadeira do problema, enquanto as equações normais pagam de qualquer jeito (Exemplo 3).
A base
Os polinômios de grau no máximo formam um único espaço, mas cada base dá uma diferente. Uma base de monômios em tem colunas quase coincidentes, e a matriz de Gram tende à matriz de Hilbert quando cresce. Polinômios de Chebyshev no intervalo dos dados mantêm as colunas longe de paralelas, embora não sejam ortogonais em dados equiespaçados: em com 100 pontos equiespaçados, o maior cosseno entre duas colunas é , contra dos monômios em . Trocar de base muda o condicionamento do problema; trocar de solver não muda.
Exemplos Resolvidos
Exemplo 1: QR à mão num ajuste conhecido
Use os quatro pontos de least-squares-via-linear-algebra, , que deram . As colunas de são e . Gram-Schmidt dá , , . Então , logo . Com , , e a substituição regressiva em
dá , , a mesma reta. numpy.linalg.qr devolve com as duas entradas da diagonal negativas e a mesma solução. Aqui e .
Exemplo 2: equações normais contra QR num ajuste real
Ajuste monômios de grau a pontos equiespaçados em , com mais ruído Normal de desvio padrão (semente 42). A referência é o minimizador exato dos e guardados, calculado com 250 dígitos, então a tabela mede só o erro do solver.
plaintextQ, R = np.linalg.qr(A) x_qr = scipy.linalg.solve_triangular(R, Q.T @ y) c = scipy.linalg.cho_factor(A.T @ A, lower=True) x_ne = scipy.linalg.cho_solve(c, A.T @ y)
Erros relativos nos coeficientes e nos valores ajustados (NE = equações normais):
textd kappa(A) kappa(A^T A) coef NE coef QR curva NE curva QR 4 6.65e+02 4.42e+05 3.90e-12 4.90e-15 1.87e-13 1.07e-15 6 2.07e+04 4.27e+08 2.91e-10 5.47e-14 5.78e-13 9.33e-16 8 6.56e+05 4.31e+11 6.48e-06 5.38e-12 8.03e-09 2.31e-14 10 2.12e+07 4.47e+14 4.35e-03 4.08e-10 7.70e-06 1.36e-12 12 6.90e+08 4.76e+17 2.64e-01 8.68e-08 7.63e-05 2.46e-11 14 2.27e+10 5.16e+20 falha 3.26e-07 falha 9.13e-10
Em , QR mantém cerca de 9 dígitos nos coeficientes e as equações normais cerca de 2. Em , Cholesky informa que a matriz não é definida positiva. Recorrer a LU ali dá erro nos coeficientes. A norma do resíduo calculado denuncia a falha: em esse recurso informa , mais que os de , o que é impossível para um minimizador verdadeiro num espaço maior. QR dá .
numpy.linalg.lstsq concorda com o código de QR: em os coeficientes diferem em em termos relativos. Concordância não é precisão: os dois ficam a do minimizador exato, e só a referência de alta precisão mostra isso. Os dígitos das equações normais também são ruído: com o padrão lower=False, o erro em é em vez de . Repare que as curvas são mais precisas que os coeficientes. Os erros vão principalmente para combinações de colunas quase dependentes, que mal mudam .
A ligação com a matriz de Hilbert é mensurável. Para e pontos médios, difere de em no máximo por entrada, e os números de condição são e .
Exemplo 3: o resíduo muda o quadro
Mantenha e construa . Aqui é numpy.random.default_rng(0).normal(size=100) sem sua projeção na imagem de , removida em alta precisão, e depois normalizado, repetido em 40 sorteios sucessivos. A norma do resíduo é , e . Erros nos coeficientes:
textresíduo t NE mediana QR mediana QR mín QR máx QR pior que NE 0 7.17e-03 5.01e-10 (sem r, um caso) 0 1e-03 6.33e-03 6.56e-09 1.37e-10 2.93e-08 0 de 40 1e-01 6.15e-03 6.44e-07 2.54e-08 2.95e-06 0 de 40 1 5.71e-03 6.44e-06 2.59e-07 2.95e-05 0 de 40 1e+02 4.82e-03 6.44e-04 2.60e-05 2.95e-03 3 de 40 1e+04 6.19e-02 6.44e-02 2.60e-03 2.95e-01 18 de 40
O erro de QR cresce linearmente com : é o termo em ação, e lstsq tem as mesmas medianas de em diante. Já em a mediana é 13 vezes o valor de . A inclinação depende da direção de , por um fator de cerca de 100 nesses sorteios. As equações normais ficam perto de até o resíduo superar de longe o ajuste. A vantagem de QR encolhe de cerca de sete ordens de grandeza até sumir: em ele perde em 18 dos 40 sorteios.
Exemplo 4: a base é o conserto de verdade
para os mesmos 100 pontos e o mesmo espaço de polinômios:
textd monômios em [0,1] monômios em [-1,1] Chebyshev em [-1,1] 4 6.65e+02 1.85e+01 2.33 8 6.56e+05 5.31e+02 2.81 12 6.90e+08 1.63e+04 2.92 16 7.56e+11 5.24e+05 2.94
Com a base de Chebyshev em , até as equações normais chegam a erro de coeficientes , contra de QR, e numpy.polynomial.Chebyshev.fit coincide com os coeficientes de QR até . Portanto, as equações normais não estão sempre erradas. Numa matriz de Chebyshev (), elas levaram s contra s de lstsq e s de qr numa máquina, com respostas diferindo em . Essa distância é maior que a razão de flops de 2, em parte porque qr também forma explicitamente. também pode ser acumulada linha a linha com memória , o que serve para fluxos longos demais para guardar.
Uma boa base tem limites. Com pontos equiespaçados, o de Chebyshev é em , em , em e em . Em a curva ajustada chega a cerca de entre as amostras de dados limitados a cerca de 1. O fenômeno de Runge está de volta, num problema em que nenhuma base ajuda.
Manter bem abaixo de evita isso. Erros máximos para a função de Runge amostrada em pontos equiespaçados:
textm d=10 d=20 d=30 d=40 d=60 41 1.03e-01 6.39e-02 4.75e+00 1.05e+05 101 1.02e-01 1.39e-02 5.60e-03 1.53e-02 5.51e+00 401 1.01e-01 1.39e-02 1.91e-03 2.61e-04 1.70e-05
O caso , é interpolação, e reproduz a explosão da lição anterior. O melhor grau sobe com , ficando bem abaixo dele.
Exemplo 5: ajustando uma tendência em timestamps Unix
Tome 720 amostras horárias de latência a partir de s, uma série ilustrativa com média perto de 135 ms e tendência quadrática. Ajuste uma parábola ao bruto.
plaintextt = 1.7e9 + 3600 * np.arange(720.0) days = (t - 1.7e9) / 86400 y = 120 + 0.6 * days + 0.02 * days**2 + np.random.default_rng(7).normal(0, 1.5, 720) c, _, rank, _ = np.linalg.lstsq(np.vander(t, 3), y, rcond=None) # rank == 2 p = np.polynomial.Polynomial.fit(t, y, 2) # mapeia t para [-1, 1]
A matriz bruta tem . O corte padrão, , remove o menor valor singular sem nenhum aviso, e o posto devolvido é 2. A curvatura volta como ms por dia$^2$ em vez de , a norma do resíduo é em vez de , e a previsão uma semana depois dos dados é ms em vez de . Mapear para dá . Polynomial.fit coincide com o ajuste exato até ms. numpy.polyfit escala as colunas internamente e chega a ms.
Exemplo 6: quando as hipóteses falham
Deficiência de posto. Tome e com uma cúbica: quatro coeficientes, três abscissas distintas, posto 3. Infinitas cúbicas têm os mesmos valores ajustados ótimos. Cholesky falha, QR sem pivoteamento dá e coeficientes de até , e lstsq informa posto 3 e devolve a solução de norma mínima, em potências crescentes, . numpy.polyfit avisa que o ajuste pode estar mal condicionado.
Um modelo não linear nos parâmetros. não tem a forma acima. Tirar logaritmos o torna linear, mas exige e minimiza outra soma. Para x = np.linspace(0, 4, 30) e y = 2 * np.exp(0.8 * x) + np.random.default_rng(11).normal(0, 1, 30), o ajuste em log dá , com erro quadrático . Um ajuste direto com scipy.optimize.curve_fit dá , com erro quadrático .
Equívocos Comuns e Armadilhas
- " é como se calcula o ajuste." Isso define a resposta. O Exemplo 2 mostra essa conta perdendo cerca do dobro dos dígitos de QR quando é grande.
- "Equações normais são sempre ruins." Com bem condicionada elas empatam com QR e custam menos (Exemplo 4).
- "QR sempre dá erro ." Quando passa de cerca de , o termo domina, mesmo com um resíduo que parece minúsculo (Exemplo 3).
- "Qualquer QR serve." Em a perda de ortogonalidade é para Gram-Schmidt clássico, para Gram-Schmidt modificado e para Householder. Resolver por dá erros de coeficientes de , e .
- "
lstsqavisa quando algo está errado." Ele devolveranke não emite aviso. O Exemplo 5 perdeu um grau de liberdade inteiro em silêncio, então comparerankcom o número de colunas. - "Resíduo menor significa modelo melhor." O resíduo mínimo só pode cair quando sobe, enquanto o ajuste de no Exemplo 4 oscila até cerca de entre as amostras.
- "Livro vs hoje." A documentação do NumPy marca
numpy.polyfitcomo parte da API antiga de polinômios e preferenumpy.polynomial, cujos métodosfitmapeiam os dados para uma janela padrão.
Resumo
Minimizar tem solução única quando tem posto coluna completo, e as equações normais a caracterizam sem ser o jeito certo de calculá-la, porque . Num ajuste de monômios com , as equações normais deixaram erro de coeficientes e QR deixou . QR resolve com cerca do dobro de flops, lstsq acrescenta a detecção de posto pelos valores singulares, e um resíduo com acima de cerca de degrada os dois via . A ferramenta mais forte é a base: mapear os dados para e usar polinômios de Chebyshev levou de a em , e depois disso até as equações normais funcionam. Mantenha o grau bem abaixo de e confira rank.
Documentation Links
- Driscoll and Braun: Fundamentals of Numerical Computation, 3.2 The normal equations
- Driscoll and Braun: Fundamentals of Numerical Computation, 3.3 The QR factorization
- Driscoll and Braun: Fundamentals of Numerical Computation, 3.4 Computing QR factorizations
- MIT OpenCourseWare 18.335J (2019): Week 4
- NumPy documentation: numpy.linalg.lstsq
- NumPy documentation: numpy.linalg.qr
- NumPy documentation: numpy.polyfit
- NumPy documentation: Polynomial.fit
- NumPy documentation: Chebyshev.fit
- SciPy documentation: scipy.optimize.curve_fit