Sábado, 12 de Julho de 2008

Regressão linear

Em meu trabalho ora me envolvo em projetos de frontend – aplicações web –, ora me envolvo em projetos de backend. Ora trabalho em projetos de uma frente a outra.

No entanto sou fascinado por problemas conceituais e soluções matemáticas, portanto gosto muito mais de backend do que de frontend.

Em problemas conceituais, uma coisa magnífica é poder prever estados de um sistema por meio de regressão.

Há alguns tipos de regressão: regressão linear, regressão por potência, regressão logarítmica e regressão exponencial, mas todas podem ser reduzidas à regressão linear.

A função da regressão linear é simples:
ŷ=α + βx

Ou seja, a ordenada estimada é igual à intercepção (α) mais a inclinação (β) vezes a abscissa. O problema real é calcular α e β.

Há muitas e muitas formas de calcular esses, umas mais simples, outras mais interessantes. =)

Uma forma legal é usando o produto de uma matriz quadrada pelo vetor de coeficientes.
--

Assim sendo, o primeiro procedimento deve ser montar as matrizes. Hoje vamos trabalhar com Python.
from __future__ import division
__metaclass__ = type

class LinearRegression:
def __init__(self, pointset):
# pointset deve ser uma lista de pares x, y
self.__set = pointset

self.__createMatrices()
self.__calculateAlpha()
self.__calculateBeta()

def __createMatrices(self):
s = self.__set

m11 = len(s)
m21 = sum([e[0] for e in s])
m12 = m21
m22 = sum([e[0] ** 2 for e in s])

self.__m = [m11, m21, m12, m22]

self.__rvector = [
sum([e[1] for e in s]),
sum ([e[0] * e[1] for e in s])
]


Agora é preciso resolver o produto de matriz por vetor. Podemos traduzir isso por meio de determinantes:
--

Daí:
    def __calculateAlpha(self):
r = self.__rvector
m = self.__m

num = r[0] * m[3] - r[1] * m[2]
den = m[0] * m[3] - m[1] * m[2]

self.__alpha = num / den


Também é possível calcular β através de determinantes:
--

Daí:
    def __calculateBeta(self):
r = self.__rvector
m = self.__m

num = m[0] * r[1] - m[1] * r[0]
den = m[0] * m[3] - m[1] * m[2]

self.__beta = num / den


Falta somente agora o método para prever um estado estrapolado:
    def predict(self, x):
return self.__alpha + (self.__beta * x)


Esta mesma lógica pode ser implementada em outras linguagens. Há ainda outros algoritmos mais simples para calcular regressão linear, mas o apresentado é o mais didático.

[]'s
Cacilhas, La Batalema

10 comentários:

Sergio F. Lima disse...

Opa Cacilhas!

Nem entendi toda a álgebra linear... mas achei legal a aplicação do Latex aqui... (via mimetex.cgi?)

abraços

La Batalema Pitonisto disse...

É…

Realmente passei correndo pela álgebra. =)

Pode ser uma boa escrever algo mais profundo sobre o assunto, mas isso já é assunto pras Reflexões de Monte Gasppa e Giulia C..

Ah! Sim… usei mimetex.cgi.

Adoro TeX e LaTeX.

[]'s
Cacilhas, La Batalema

Eduardo Willians disse...

Cara, se eu entedesse o problema talvez entedesse a solução...

La Batalema Pitonisto disse...

Olá Eduardo!

Regressão linear é um dos recursos mais interessantes da Estatística. Se você fizer uma busca no Google, provavelmente vai encontrar a página na Wikipédia, inclusive com outras soluções diferentes da que usei.

Dica: a página em inglês está mais completa.

A solução que usei foi a regra de Cramer.

Se quiser, depois tento me aprofundar mais na questão matemática nas Reflexões de Monte Gasppa e Giulia C., pois o enfoque aqui foi a programação.

[]'s
Cacilhas, La Batalema

La Batalema Pitonisto disse...

Gente,

Tentei explicar melhor o problema nas Reflexões de Monte Gasppa e Giulia C..

[]'s
Cacilhas, La Batalema

Henrique Bastos disse...

Show de artigo!!! Parabéns!

La Batalema Pitonisto disse...

Obrigado, Henrique.

Se tiver algum comentário que possa melhorar ou complementar o artigo ou sua versão nas Reflexões de Monte Gasppa e Giulia C., por favor, sinta-se a vontade!

[]'s
Cacilhas, La Batalema

Claudio disse...

Cacilhas, parabéns pelo artigo. Você e Walter estão fazendo muito bem em manter o Kodumaro vivo e interessante.

La Batalema Pitonisto disse...

Oxe Torcato,

Achei que estavamos devagar demais…

Valeu pelo elogio. =)

[]'s
Cacilhas, La Batalema

tecggualberto disse...

poxa eu fiz algumas implentações em fortran pois tem algumas funções implicitas que ajuda bastante na implementação e não ficam tão complicadas como matimul(matrx,matry) que faz multiplicação de matrizes
sum(matrx) bem se alguem quiser testar:
program regresslinera
implicit none
character (len =25):: atribponto,n
integer :: unitl = 10
read (*,*)atribponto, n
!atribponto deve ser uma arquivo de pares x, y
open(unit = unitl,FILE = atribponto,status ='old',action ='read',form = 'formatted',err=10)
call lermatriz(unitl,n)
close(unitl)
call calculateAlpha()
call calculateBeta()
stop
10 write(*,*)'erro na leitura do arquivo'
stop
end program

subroutine lermatriz(unitl,n):
implicit none
integer:: i,j
integer ::unitl,n
real ,dimension(:,:),allocatable::matrizdeXY
real ,dimension(:,:),allocatable::Matrizresposta
allocate(matrizdeXY(n,2))
allocate(Matrizresposta(n,2))
do i=1, n
read(unitl,'(i8)')(matrizdeXY(i,j),j=1,2)
enddo

endsubroutine

subroutine somax()

endsubroutine
complemente o codigo rsrsrsrsrsrs
tecgg[:)];