Modelos de Predição | Regressão Linear

Um modelo simples de machine learning para encontrar a reta que melhor explica a relação entre as features e um target contínuo.

Piero Esposito
Turing Talks
9 min readJul 21, 2019

--

Escrito por Fernando Matsumoto, Guilherme Fernandes e Piero Esposito.

No último post, falamos sobre os conceitos básicos de predição. Dando continuidade a esse assunto, essa semana vamos introduzir um primeiro modelo de predição: a regressão linear.

Para acompanhar a parte matemática deste artigo é necessário entender o básico de cálculo (gradiente e derivadas parciais). Para isso, se quiser, recomendamos as aulas do prof. Possani na UNIVESP. Além disso, para a reprodução em código é essencial python e bibliotecas de data science, como pandas, numpy e matplotlib.

Para facilitar a leitura, esse artigo vai seguir a seguinte estrutura: (i) vamos enunciar o problema da regressão linear com a nossa motivação; (ii) depois, vamos pra intuição matemática do que ocorre na regressão linear; (iii) feito isso, vamos implementar um regressor em código com dados simples, para você poder fazer as contas na mão se quiser e ver que faz bastante sentido; (iv) por último, vamos concluir esse Turing Talks.

Dito isso, vamos lá:

1. Motivação

Quando falamos em predizer valores com auxílio de um dataset, estamos dizendo que queremos descrever o target (y) por meio das features (X). Para cumprir essa tarefa vamos usar o conceito matemático de regressão linear, que, em linhas gerais, aproxima o target das features por uma reta (uma função linear). Desse modo, podemos fazer afirmações sobre valores não disponíveis no dataset.

A exemplo, temos os problemas de estimar o salário de um funcionário com base no “tempo de casa” na empresa ou o valor do IPVA de um carro com base no seu preço de venda.

Nesses casos, basicamente plotamos num gráfico pontos correspondentes a várias observações do contexto que estamos estudando, e eles seguem a forma (x, y) sendo x a observação que temos e y a que queremos tornar possível a previsão. No final, fica mais ou menos assim:

Gráfico com variáveis dependentes (y) e independentes (x) no plano cartesiano.

Quando dizemos prever o valor do y com base no x, que acaba sendo meio que o mote do Machine Learning, basicamente, queremos encontrar uma reta que seja a mais adequada e passa com mais “smoothness” pelos pontos, ou seja, a que melhor descreve os dados. O resultado do modelo vai ser uma reta, com equação f(x) = y = ax + b que vai passar por esses pontos. A visualização dela vai ser mais ou menos assim:

Gráfico com modelo de regressão linear ajustado aos pontos

O nosso trabalho vai ser encontrar os coeficientes angular e linear que tornam essa reta ideal — e isso vamos ver com bastante detalhe no tópico 2.

Importante dizer que o y pode ser previsto também com base em vários x’s, o que ocorre quando temos mais de uma feature. Nesse caso, que fica mais difícil de visualizar, a aproximação não se dá por uma reta, mas por planos ou hiperplanos dependendo da quantidade de features.

Para esses casos, o target da predição é calculado de forma que cada feature (x1, x2, x3…, xn) tenha um “peso” associado a si. Veremos isso com mais detalhes a seguir.

2. Explicação matemática da regressão linear com método do gradiente

Partindo para explicação matemática do modelo de regressão linear, nosso objetivo será encontrar uma função cujas variáveis independentes sejam as features e a dependente, o target.

Dessa forma temos:

onde ŷ é a predição do modelo, e Erro o quão longe está da previsão correta. Para cada combinação dos coeficientes (a1, a2, …, an, b), com os dados de treino, temos um Erro, isso é, uma função que determina o quão erradas as previsões do nosso modelo estão. A modelagem da regressão linear consiste em encontrar os valores dos coeficientes da função que minimizam o erro.

No entanto, a função Erro tem um valor diferente para cada observação do dataset. Precisamos então converter essa função em um número que possamos minimizar. Em problemas de regressão, uma boa prática é usar a função do erro quadrático médio (como vimos no último post):

onde m é o número de observações do dataset. Usamos essa equação não somente por apresentar bons resultados, mas porque, se apenas usássemos o erro médio, erros positivos poderiam cancelar os erros negativos. Ao considerar o erro ao quadrado, todos os termos se tornam positivos e não temos mais esse problema. Além disso, temos como efeitos colaterais que:

  1. erros maiores importam muito mais, já que, se maiores que 1, quando elevados ao quadrado aumentam bastante;
  2. nossa função de custo L ganha a forma de parábola (ou paraboloide) com concavidade para cima, de forma que no gráfico de L, todo mínimo local é também mínimo global. Isso está exemplificado na imagem abaixo. O erro quadrático médio na regressão linear se comporta como o gráfico da esquerda, ou seja, é impossível achar um mínimo local que não seja ótimo (isso pode ser falso em outros modelos diferentes da regressão linear).
Os pontos vermelhos são pontos de mínimo global. O ponto azul é um ponto de mínimo local, mas não global.

2.1. Método do Gradiente

Para encontrar a função f(x1, x2, … , xn) que minimiza o erro, usamos o método do gradiente, também conhecido como gradient descent. Para entender esse método, precisamos primeiro entender o que é o gradiente de uma função. De forma simplificada, ele é um vetor que aponta na direção em que uma função aumenta mais rapidamente.

Por exemplo, considere a imagem abaixo, que mostra o gradiente de uma função de duas variáveis. O gradiente aponta para fora da região azul (que corresponde a valores pequenos de f) e para dentro da região vermelha (que corresponde a valores grandes de f).

Gráfico do gradiente de uma função y = f(x1, x2). A cor azul corresponde a valores pequenos de y e a cor vermelha, a valores altos. As setas representam o gradiente de f em alguns pontos do gráfico. Fonte: https://commons.wikimedia.org/wiki/File:Gradient_of_a_Function.tif.

Sabendo disso, se encontrarmos o vetor gradiente para determinado ponto da função, é só ir na direção oposta dele para diminuir o y. Vale lembrar que isso só vale para variações muito pequenas.

Para ilustrar, vamos pensar em uma função de duas variáveis f(x1, x2). Se olharmos o gráfico dessa função de cima, veremos algo que se parece com a figura abaixo. Cada linha azul é uma “fatia horizontal” do gráfico, ou seja, uma curva na qual o valor de f é constante. Conforme chegamos nas curvas mais internas, o valor de f diminui.

Começando em algum ponto qualquer, podemos calcular o gradiente e variar os parâmetros x1 e x2 no sentido oposto. O método do gradiente consiste em fazer isso várias vezes até chegarmos no mínimo da função, como ilustrado abaixo.

Gráfico de uma função de custo de duas variáveis, ilustrando gradient descent. (fonte: https://www.neuraldesigner.com/blog/5_algorithms_to_train_a_neural_network)

2.2. O Algoritmo

No nosso caso, o custo é o erro quadrático médio L:

Dado que os valores do target são constantes (são parte do nosso dataset) e ŷ é uma função dos pesos, a função de custo pode ser escrita como L(a1, a2, …, an, b).

Antes de partirmos para o algoritmo, vamos explicar a notação que usaremos:

X = vetor de features com dimensões 1×n; sendo n = numero de features. X pode também ser uma matriz m×n em que cada uma das m linhas é uma observação diferente. Nesse caso, x1, x2, …, xm são as linhas de X.

w = (a1, a2, …, an) = vetor de coeficientes da função, com dimensões n×1.

b = escalar, conhecido como viés. É o termo constante na função f.

ŷ = Xw + b, previsão do target do dado X ou, se X for uma matriz, vetor com os previsões para os dados integrantes da matriz.

L = Σ(ŷ - y)², a função de custo que queremos minimizar.

α = taxa de aprendizado, ou seja, o quanto, a cada iteração do modelo, vamos mexer nossos W e b na direção do gradiente.

Um pseudocódigo desse modelo pode ser:

- Cria W e b aleatórios- Para cada iteração:    - Calcula ŷ = Xw+ b    - Calcula Erro    - Calcula gradiente do custo em relação a w e b    - w = w − α * derivada parcial do custo em relação a w    - b = b − α * derivada parcial do custo em relação a b

Se você tiver bastante interesse na matemática por trás do modelo, vamos explicar agora como calculamos os gradientes de Erro em relação a w e b. Vale dizer que essas contas valem pra uma só variável de saída (uma feature), caso contrario complica bastante e sai do escopo deste artigo. Para cada iteração, temos:

2.3. Os 3 tipos de Gradient Descent

No algoritmo descrito acima, que chamamos de Batch Gradient Descent, para calcular o gradiente de f, precisamos calcular o erro da função em todas as observações do dataset. Isso significa que para atualizar uma única vez os pesos (realizar uma iteração de gradient descent), é necessário calcular m erros (onde m é número de observações do dataset), o que pode ser muito custoso.

Um modo de consertar esse problema é usando o algoritmo de Stochastic Gradient Descent. Nesse algoritmo, em cada iteração, calculamos o gradiente do custo considerando apenas uma das observações. Ou seja, para cada iteração, realizamos:

- Calcular ŷ = Xw+ b- Calcular Erro- Selecionar uma observação xi do - Calcular o gradiente da função custo considerando apenas xi- w = w − α * derivada parcial do custo em relação a W- b = b − α * derivada parcial do erro em relação a b

Nesse algoritmo, temos o problema oposto: atualizar os pesos também é computacionalmente caro. Um meio termo entre batch e stochastic gradient descente é Mini-Batch Gradient Descent. Nesse terceiro caso, usamos algumas observações a cada iteração, ou seja, ao invés de selecionar uma observação xi, selecionamos várias observações xi1, xi2, …, xik (onde k é chamado de batch size).

Na figura abaixo, podemos ver uma comparação dos 3 métodos de gradient descent.

Comparação dos 3 tipos de gradient descent. Fonte: https://medium.com/@lucasoliveira_56505/regress%C3%A3o-linear-do-zero-com-python-ef74a81c4b84

O método estocástico (em roxo) se move de uma forma que parece “aleatória”. Isso ocorre porque usamos apenas 1 observação para estimar o gradiente, o que significa que a estimativa é muito ruim. No caso de mini-batch (em verde), como usamos mais observações, a estimativa melhora um pouco e o algoritmo se move de forma que parece “mais correta”. Por último, o batch (em azul) é o método que chega ao mínimo em menos iterações. No entanto, é necessário lembrar que uma iteração de batch gradient descent demora muito mais do que uma iteração de stochastic gradient descent.

Observando que os métodos batch e stochastic são casos especiais de mini-batch (com batch size = m e 1, respectivamente), podemos concluir que o batch size do gradient descent afeta a velocidade de convergência do algoritmo.

3. Implementação em código

Para nossa sorte, não precisamos codar esse algoritmo na unha, graças a biblioteca “Scikit-learn” de Python. Esta disponibiliza vários modelos de machine learning incluindo a regressão linear. É importante se familiarizar com essa biblioteca, pois muitos modelos de predição são acessíveis por ela, já otimizados.

No exemplo de código vamos fazer regressão linear em dois datasets:

  1. No primeiro vamos tentar calcular o peso de uma pessoa (Y) em função de sua altura (X).
  2. E no segundo vamos predizer os valores de preço de uma casa em Boston, utilizando o dataset Boston Housing.

5. Conclusão

No Turing Talks de hoje pudemos entender mais sobre regressão linear e gradiente descendente, os quais certamente serão muito úteis na sua jornada em ciência de dados. Além disso, agora você sabe como é feito um modelo de machine learning na prática.

Esse modelo ainda pode ser melhorado com técnicas de feature-engineering e funções de erro (ou custo) diferentes, mas isso fica pra uma outra hora!

Nas próximas semanas seguiremos com os Turing Talks com mais modelos de predição. Caso queira saber mais sobre o mundo de IA, siga nossa página no Facebook e confira o que postamos por lá também.

Por hoje é só, até mais!

--

--