Processing math: 100%

O que é uma Piecewise Regression?

Quando analisamos o relacionamento entre uma resposta, y, e uma covariável, x, pode ser aparente que para diferentes intervalos de x, diferentes relações lineares ocorram. Nesses casos, um único modelo linear pode não fornecer uma adequada descrição e um modelo não linear pode também não ser apropriado.

Piecewise linear regression (ou Regressão Linear por Partes) é uma forma de regressão que permite o ajuste de múltiplos modelos lineares aos dados para diferentes intervalos de x.

Pontos de quebra (breakpoints) são os valores de x onde a inclinação da função linear muda. O valor do ponto de quebra pode ou não ser conhecido antes da análise, tipicamente sendo desconhecido e consequentemente, estimado.1

Na figura abaixo temos um comportamento que exemplifica a necessidade da utilização deste tipo de modelo.

pkg <- c("segmented",
         "latticeExtra",
         "RSADBE")
sapply(pkg, require,
       character.only = TRUE)
Loading required package: segmented
Loading required package: latticeExtra
Loading required package: RColorBrewer
Loading required package: lattice
Loading required package: RSADBE
   segmented latticeExtra       RSADBE 
        TRUE         TRUE         TRUE 
data(down)
xyplot(log(cases/births) ~ age,
       pch = 16,
       jitter.x = TRUE,
       type = c("p", "g"),
       scales = list(x = list(draw = FALSE),
                     y = list(draw = FALSE)),
       xlab = "x",
       ylab = list(label = "y",
                   rot = 0),
       down)

Ilustração de comportamento condizente com o ajuste de um modelo de regressão por partes

Qual é a cara do modelo?

Existem diversas formas de escrever o modelo, ao percorrer este documento você irá se deparar com mais algumas.

Usualmente o modelo é escrito da seguinte maneira (considerando um único ponto de quebra, θ):

y=β0+β1x,xθy=β0+β2x+θ(β1β2),x>θ

Quando a covariável, x, é menor ou igual ao ponto de quebra, θ, temos uma reta, β0+β1x. Quando a covariável é maior que θ, temos uma nova reta, β0+β2x+θ(β1β2), começando no ponto de quebra e com uma nova inclinação.


Ponto de quebra conhecido:

Um ponto de quebra, o que fazer?

Como exemplo é utilizado um conjunto de dados2.

Uma companhia de eletrônicos periodicamente realiza grandes importações de peças utilizadas em seus produtos. O tamanho dos carregamentos varia de acordo com a produção/demanda. O conjunto de dados contém informações do custo (y) de manejo dos carregamentos até um depósito (em milhares de dólares) e o tamanho (x1) dos carregamentos (em milhares de peças).

Com base numa gráfico de dispersão foi escolhido como ponto de quebra x=250.

Quando o ponto de quebra é conhecido, o modelo de regressão linear por partes pode ser formulado da seguinte maneira:

yi=β0+β1x1i+β2(x1i250)x2i+ϵi,alternativamente:yi=β0+β1x1i+β2x2i+ϵi,onde

Foram ajustados dois modelos, um modelo de regressão linear simples é um modelo de regressão linear por partes.

path <- "~/Dropbox/CE092 - 2015-2/Alunos/Henrique/Piecewise Regression/shipment.txt"
data <- read.table(path,
                   header = TRUE)
m0 <- lm(y ~ x1,
         data)
coef.m0 <- coefficients(m0)
attr(coef.m0, "names") <- c("beta0", "beta1")
data$x2 <- with(data,
                ifelse(x1 <= 250, 0, x1 - 250))
m1 <- lm(y ~ x1 + x2,
         data)
coef.m1 <- coefficients(m1)
attr(coef.m1, "names") <- c("beta0", "beta1", "beta2")
xyplot(y ~ x1,
       pch = 16,
       jitter.x = TRUE,
       type = c("p", "g"),
       xlab = expression(x[1]),
       ylab = list(label = "y",
                   rot = 0),
       scales = list(y = list(tick.number = 8)),
       xlim = c(100, 425),
       ylim = c(7, 16),
       key = list(space = "right",
                  title = "Regressão Linear",
                  cex.title = 1.15, 
                  text = list(c("Simples", "por Partes")), 
                  lines = list(col = c(3, 6), 
                               lwd = 2)),
       data) +
  layer(with(as.list(coef.m0),
             panel.curve(beta0+beta1*x,
                         col = 3,
                         lwd = 2))) +
  layer(with(as.list(coef.m1),
             panel.curve(beta0+{beta1*x}*(x <= 250)+{beta1*x+beta2*(x-250)}*(x > 250),
                         col = 6,
                         lwd = 2)))

Ajuste do modelo de regressão linear simples e do modelo de regressão linear por partes ao conjunto de dados dos carregamentos

Pela retas ajustadas, a impressão que fica é que o ajuste da regressão por partes se saiu muito melhor, dado sua proximidade aos pontos observados.

r.m0 <- residuals(m0,
               type = "pearson")
f.m0 <- fitted(m0)
ar.1 <- xyplot(r.m0 ~ f.m0,
               type = c("p", "g"),
               pch = 16,
               jitter.x = TRUE,
               xlab = "Valores ajustados",
               ylab = list(label = "Resíduos \n de Pearson",
                           rot = 0),
               main = "(a) Ajuste do modelo",
               panel = function(...){
                 panel.xyplot(...)
                 panel.loess(f.m0, r.m0,
                             lwd = 2,
                             col = 2)})
ar.2 <- xyplot(sqrt(abs(r.m0)) ~ f.m0,
               type = c("p", "g"),
               pch = 16,
               jitter.x = TRUE,
               xlab = "Valores ajustados",
               ylab = list(label = expression(sqrt(abs(atop("Resíduos", "de Pearson")))),
                           rot = 0),
               main = "(b) Relação média - variância",
               panel = function(...){
                 panel.xyplot(...)
                 panel.loess(f.m0, sqrt(abs(r.m0)),
                             lwd = 2,
                             col = 2)})
ar.3 <- qqmath(r.m0,
               type = c("p", "g"),
               pch = 16,
               xlab = "Quantis teóricos",
               ylab = list(label = "Quantis \n amostrais",
                           rot = 0),
               main = "(c) Normalidade")
print(ar.1,
      position = c(0, 0,
                   1/3, 1),
      more = TRUE)
print(ar.2,
      position = c(1/3, 0,
                   2/3, 1),
      more = TRUE)
print(ar.3,
      position = c(2/3, 0,
                   1, 1))

Análise de resíduos do modelo de regressão linear simples. (a) Verificação da qualidade do ajuste do modelo; (b) Verificação do pressuposto de ausência de relação média - variância; (c) Verificação do pressuposto de normalidade

Pelos três gráficos acima mostrados, vemos uma clara não adequação aos pressupostos (a) e (b).

Nos três gráficos abaixo temos a análise de resíduos para o modelo de regressão por partes. Ela também não se mostra muito boa, contudo, está bem melhor do que no caso da regressão linear simples. Também deve ser levado em consideração o tamanho da amostra, que é composta por apenas 10 observações.

r.m1 <- residuals(m1,
               type = "pearson")
f.m1 <- fitted(m1)
ar.1 <- xyplot(r.m1 ~ f.m1,
               type = c("p", "g"),
               pch = 16,
               jitter.x = TRUE,
               xlab = "Valores ajustados",
               ylab = list(label = "Resíduos \n de Pearson",
                           rot = 0),
               main = "(a) Ajuste do modelo",
               panel = function(...){
                 panel.xyplot(...)
                 panel.loess(f.m1, r.m1,
                             lwd = 2,
                             col = 2)})
ar.2 <- xyplot(sqrt(abs(r.m1)) ~ f.m1,
               type = c("p", "g"),
               pch = 16,
               jitter.x = TRUE,
               xlab = "Valores ajustados",
               ylab = list(label = expression(sqrt(abs(atop("Resíduos", "de Pearson")))),
                           rot = 0),
               main = "(b) Relação média - variância",
               panel = function(...){
                 panel.xyplot(...)
                 panel.loess(f.m1, sqrt(abs(r.m1)),
                             lwd = 2,
                             col = 2)})
ar.3 <- qqmath(r.m1,
               type = c("p", "g"),
               pch = 16,
               xlab = "Quantis teóricos",
               ylab = list(label = "Quantis \n amostrais",
                           rot = 0),
               main = "(c) Normalidade")
print(ar.1,
      position = c(0, 0,
                   1/3, 1),
      more = TRUE)
print(ar.2,
      position = c(1/3, 0,
                   2/3, 1),
      more = TRUE)
print(ar.3,
      position = c(2/3, 0,
                   1, 1))

Análise de resíduos do modelo de regressão linear por partes. (a) Verificação da qualidade do ajuste do modelo; (b) Verificação do pressuposto de ausência de relação média - variância; (c) Verificação do pressuposto de normalidade

Mais de um ponto de quebra, o que fazer?

Exemplo

Quando existe mais de um ponto de quebra, o procedimento empregado é o mesmo.

No exemplo aqui considerado existem dois pontos de quebra, 15 e 30. O modelo fica expresso da seguinte forma:

yi=β0+β1xi+β2(xi15)++β3(xi30)++ϵi,ϵiiidN(0,σ2)

data("PW_Illus")
data <- PW_Illus
names(data) <- c("x1", "y")
data$x2 <- with(data,
                ifelse(x1 <= 15, 0, x1 - 15))
data$x3 <- with(data,
                ifelse(x1 <= 30, 0, x1 - 30))
m0 <- lm(y ~ x1+x2+x3,
         data)
coef.m0 <- coefficients(m0)
attr(coef.m0, "names") <- c("beta0", "beta1", "beta2", "beta3")
xyplot(y ~ x1,
       pch = 16,
       jitter.x = TRUE,
       type = c("p", "g"),
       xlab = expression(x[1]),
       ylab = list(label = "y",
                   rot = 0),
       scales = list(x = list(tick.number = 11),
                     y = list(tick.number = 9)),
       data) +
  layer(with(as.list(coef.m0),
             panel.curve(beta0+{beta1*x}*(x <= 15)+
                         {beta1*x+beta2*(x-15)}*(x > 15 & x <= 30)+
                         {beta1*x+beta2*(x-15)+beta3*(x-30)}*(x > 30),
                         col = 6,
                         lwd = 2)))

Ajuste do modelo de regressão linear por partes ao conjunto de dados

No intervalo [.5;15] temos o modelo:

yi=β0+β1xi+ϵi.

No intervalo (15;30] temos o modelo:

yi=β0+β1xi+β2(xi15)+ϵi.

No intervalo (30;50] temos o modelo:

yi=β0+β1xi+β2(xi15)+β3(xi30)+ϵi.

r.m0 <- residuals(m0,
               type = "pearson")
f.m0 <- fitted(m0)
ar.1 <- xyplot(r.m0 ~ f.m0,
               type = c("p", "g"),
               pch = 16,
               jitter.x = TRUE,
               xlab = "Valores ajustados",
               ylab = list(label = "Resíduos \n de Pearson",
                           rot = 0),
               main = "(a) Ajuste do modelo",
               panel = function(...){
                 panel.xyplot(...)
                 panel.loess(f.m0, r.m0,
                             lwd = 2,
                             col = 2)})
ar.2 <- xyplot(sqrt(abs(r.m0)) ~ f.m0,
               type = c("p", "g"),
               pch = 16,
               jitter.x = TRUE,
               xlab = "Valores ajustados",
               ylab = list(label = expression(sqrt(abs(atop("Resíduos", "de Pearson")))),
                           rot = 0),
               main = "(b) Relação média - variância",
               panel = function(...){
                 panel.xyplot(...)
                 panel.loess(f.m0, sqrt(abs(r.m0)),
                             lwd = 2,
                             col = 2)})
ar.3 <- qqmath(r.m0,
               type = c("p", "g"),
               pch = 16,
               xlab = "Quantis teóricos",
               ylab = list(label = "Quantis \n amostrais",
                           rot = 0),
               main = "(c) Normalidade")
print(ar.1,
      position = c(0, 0,
                   1/3, 1),
      more = TRUE)
print(ar.2,
      position = c(1/3, 0,
                   2/3, 1),
      more = TRUE)
print(ar.3,
      position = c(2/3, 0,
                   1, 1))

Análise de resíduos do modelo de regressão linear por partes. (a) Verificação da qualidade do ajuste do modelo; (b) Verificação do pressuposto de ausência de relação média - variância; (c) Verificação do pressuposto de normalidade

Pelos três gráficos de análise de resíduos acima mostrados, vemos uma adequação razoável aos pressupostos.

Mais um exemplo3

O conjunto de dados aqui estudo é do livro do Montgomery, Peck e Vining, 2001, Seção 7.2.24.

O dado consiste num experimento em que a queda de tensão da bateria (em voltagem) de um motor de míssil guiado é observada ao longo do tempo (em segundos). A queda de tensão da bateria foi observada em 41 instantes da trajetória do míssil.

Foi considerado dois pontos de quebra, 6.5 e 30 segundos. O modelo fica expresso da seguinte forma:

yi=β0+β1xi+β2x2i+β3x3i+β4(xi6.5)3++β5(xi13)3++ϵi,ϵiiidN(0,σ2)

data("VD")
data <- VD
data$x2 <- with(data,
                ifelse(Time <= 6.5, 0, Time - 6.5))
data$x3 <- with(data,
                ifelse(Time <= 13, 0, Time - 13))
m0 <- lm(Voltage_Drop ~ Time+I(Time**2)+I(Time**3)+I(x2**3)+I(x3**3),
         data) 
coef.m0 <- coefficients(m0)
attr(coef.m0, "names") <- c("beta0", "beta1", "beta2", "beta3", "beta4", "beta5")
xyplot(Voltage_Drop ~ Time,
       pch = 16,
       jitter.x = TRUE,
       type = c("p", "g"),
       xlab = "Tempo",
       ylab = list(label = "Queda \n de \n voltagem",
                   rot = 0),
       scales = list(x = list(tick.number = 11),
                     y = list(tick.number = 9)),
       data) +
  layer(with(as.list(coef.m0),
             panel.curve(beta0+beta1*x+beta2*x**2+{beta3*x**3}*(x <= 6.5)+
                         {beta3*x**3+beta4*(x-6.5)**3}*(x > 6.5 & x <= 13)+
                         {beta3*x**3+beta4*(x-6.5)**3+beta5*(x-13)**3}*(x > 13),
                         col = 6,
                         lwd = 2)))

Ajuste do modelo de regressão linear por partes ao conjunto de dados de queda de voltagem

No intervalo [0;6.5] temos o modelo:

yi=β0+β1xi+β2x2i+β3x3i+ϵi.

No intervalo (6.5;13] temos o modelo:

yi=β0+β1xi+β2x2i+β3x3i+β4(xi6.5)3+ϵi.

No intervalo (30;50] temos o modelo:

yi=β0+β1xi+β2x2i+β3x3i+β4(xi6.5)3+β5(xi13)3+ϵi.

r.m0 <- residuals(m0,
               type = "pearson")
f.m0 <- fitted(m0)
ar.1 <- xyplot(r.m0 ~ f.m0,
               type = c("p", "g"),
               pch = 16,
               jitter.x = TRUE,
               xlab = "Valores ajustados",
               ylab = list(label = "Resíduos \n de Pearson",
                           rot = 0),
               main = "(a) Ajuste do modelo",
               panel = function(...){
                 panel.xyplot(...)
                 panel.loess(f.m0, r.m0,
                             lwd = 2,
                             col = 2)})
ar.2 <- xyplot(sqrt(abs(r.m0)) ~ f.m0,
               type = c("p", "g"),
               pch = 16,
               jitter.x = TRUE,
               xlab = "Valores ajustados",
               ylab = list(label = expression(sqrt(abs(atop("Resíduos", "de Pearson")))),
                           rot = 0),
               main = "(b) Relação média - variância",
               panel = function(...){
                 panel.xyplot(...)
                 panel.loess(f.m0, sqrt(abs(r.m0)),
                             lwd = 2,
                             col = 2)})
ar.3 <- qqmath(r.m0,
               type = c("p", "g"),
               pch = 16,
               xlab = "Quantis teóricos",
               ylab = list(label = "Quantis \n amostrais",
                           rot = 0),
               main = "(c) Normalidade")
print(ar.1,
      position = c(0, 0,
                   1/3, 1),
      more = TRUE)
print(ar.2,
      position = c(1/3, 0,
                   2/3, 1),
      more = TRUE)
print(ar.3,
      position = c(2/3, 0,
                   1, 1))

Análise de resíduos do modelo de regressão linear por partes. (a) Verificação da qualidade do ajuste do modelo; (b) Verificação do pressuposto de ausência de relação média - variância; (c) Verificação do pressuposto de normalidade

Pelos três gráficos de análise de resíduos acima mostrados, vemos uma adequação razoável aos pressupostos.


Como ajustar uma Piecewise Regression no R?5

No R, o ajuste de uma Piecewise Regression pode ser feita com o package segmented (relacionamentos segmentados em modelos de regressão com estimação de pontos de quebra/pontos de mudança).

Com este package, somos capazes de estimar modelos de regressão com relacionamentos lineares por partes com um número fixo de pontos de quebra.

O objetivo do package segmented é estimar modelos lineares e modelos lineares generalizados (e praticamente qualquer modelo de regressão) com um ou mais relacionamentos segmentados no preditor linear. Estimação das inclinações e dos possíveis múltiplos pontos de quebra são providas. O package incluí funções de teste/estimação e métodos para retornar, resumir e imprimir gráficos dos resultados.

O algoritmo utilizado pela segmented não é uma busca num grid (grid-search). É um procedimento iterativo (Muggeo, 2003)6 que precisa de valores (chutes) iniciais apenas para o parâmetro correspondente ao ponto de quebra e por este motivo ele é bastante eficiente mesmo com vários pontos de quebra a serem estimados.

Como funciona o algoritmo de estimação?

Uma outra forma de representar o modelo com uma única covariável é a seguinte:

β1xi+β2(xiθ)+,onde(xiθ)+=(xiθ)I(xi>θ),e

Da forma como o modelo está acima representado, temos um modelo não linear. Muggeo (2003) mostra uma aproximada representação linear intrínseca que, até certo ponto, nos permite traduzir o problema em uma estrutura linear padrão: dado um chute inicial para o ponto de quebra, ˜θ, sucessivos segmentos são tentados para estimar o modelo pelo ajuste iterativo do modelo linear com o seguinte preditor linear:

β1xi+β2(xi˜θ)++γI(xi>˜θ),onde

A cada iteração, um modelo linear padrão é ajustado, e o valor do ponto de quebra é atualizado via ˆθ=˜θ+ˆγ/ˆβ2; perceba que ˆγ representa o intervalo, na atual estimativa de θ, entre as duas retas ajustadas oriundas do modelo descrito. Quando o algoritmo converge, o ‘intervalo’ se torna menor, i.e., ˆγ0, e o erro padrão (standard error) de ˆθ pode ser obtido via método Delta para a razão ˆγ/ˆβ2 que se reduz em SE(ˆγ)/|ˆβ2| se ˆγ=0.

A ideia pode ser utilizada para ajustar múltiplos relacionamentos segmentados, apenas pela inclusão no preditor linear de apropriadas variáveis construídas para que os adicionais pontos de quebra possam ser estimados: em cada passo, todo ponto de quebra estimado é atualizado através dos importantes coeficientes de ‘intervalo’ e ‘diferença na inclinação’. Devido a facilidade computacional, o algoritmo é capaz de executar a estimação de múltiplos pontos de quebra de uma maneira bem eficiente.

Outras maneiras de lidar com pontos de quebra

Um outro package do R que lida com pontos de quebra é o strucchange de Zeileis et al. (2002)7. O package trabalha com modelos de regressão tendo um diferente conjunto de parâmetros para cada ‘pedaço’ da variável segmentada, tipicamente, o tempo; strucchange realiza a estimação dos pontos de quebra via um algoritmo de grid de busca dinâmico e possibilita o teste da instabilidade do parâmetro.


Modelos não lineares8

Alguns modelos não lineares são segmentados, tendo em alguns aspectos vantagens e facilidades em sua utilização.

Reparametrizações podem ser feitas com o intuito de facilitar a interpretabilidade dos parâmetros9. O procedimento de reparametrização pode ser sistematizado em três etapas:

  1. Expressar o parâmetro de interesse ϑ, como função dos elementos de θ, ou seja, ϑ=g(θ);
  2. Escolher um dos elementos θi de θ=(θi,θi1) para ser colocado em função de ϑ de tal forma a obter θi=h(θi,ϑ);
  3. Substituir θi na equação do modelo não linear pela expressão obtida no passo anterior, h(θi,ϑ), fazendo as simplificações convenientes. Assim o modelo f(x,θ) pode ser expresso como f(x,θi,ϑ).

A função h é a inversa de g em θi.

Alguns modelos

Modelo segmentado conhecido como linear-platô

Trata-se da junção de dois segmentos de reta no qual um deles é horizontal. O modelo pode ser escrito da seguinte forma:

{θ0+θ1x,xθbθ0+θ1θb,x>θb

  • A função é crescente (decrescente) para θ1>0 (θ1<0) até o valor 0<x<θb, e para x>θb a função é constante;
  • O intercepto é representado por θ0;
  • θ1 corresponde à taxa de variação antes do ponto de quebra θb>0.

Reparametrização

ϑ=g(θ)ϑb=θ0+θ1θb

θi=g1(ϑ,θ1)θ0=ϑbθ1θb

Resultando em:

{ϑb+θ1(xθb),xθbϑb,x>θb

  • ϑb representa o valor da função no ponto de quebra θb que é o máximo (mínimo) valor da função se θ1>0 (θ1<0).
xyplot(1:50 ~ 1:50,
       pch = 16,
       jitter.x = TRUE,
       type = c("n", "g"),
       scales = list(x = list(draw = FALSE),
                     y = list(draw = FALSE)),
       xlab = "x",
       ylab = list(label = "y",
                   rot = 0),
       key = list(space = "right",
                  title = expression(theta[1]),
                  cex.title = 1.15, 
                  text = list(c("> 0", "< 0")), 
                  lines = list(col = c(3, 6), 
                               lwd = 2))) +
  layer(with(list(vthB = 35,
                  th1 = 1,
                  thB = 30),
             panel.curve(vthB+{th1*(x-thB)}*(x <= thB),
                         col = 3,
                         lwd = 2))) +
  layer(with(list(vthB = 15,
                  th1 = -1,
                  thB = 30),
             panel.curve(vthB+{th1*(x-thB)}*(x <= thB),
                         col = 6,
                         lwd = 2)))

Curvas do modelo segmentado conhecido como linear-platô

Modelo segmentado conhecido como bi-linear segmentado

Trata-se da junção de dois segmentos de reta. O modelo pode ser escrito da seguinte forma:

{θ0+θ1x,xθbθ0+θ1θb+θ2(xθb),x>θb

A função assume diversas formas dependendo dos valores dos parâmetros.

  • O intercepto é representado por θ0;
  • θ1 e θ2 são os coeficientes ou taxas do primeiro e segundo segmentos de reta, respectivamente, que se encontram no ponto θb, denominado de ponto de quebra.

Reparametrização

ϑb=θ0+θ1θb

θ0=ϑbθ1θb

Resultando em:

{ϑb+θ1(xθb),xθbϑb+θ2(xθb),x>θb

  • O ponto de quebra foi priorizado e representado de tal modo que ϑb é o valor da função no ponto de quebra θb.
  • Se θ2=0 o modelo reduz-se ao linear-platô;
  • Se θ1=0 reduz-se ao modelo platô-linear;
  • Se θ1=θ2 reduz-se ao modelo linear simples.
xyplot(1:50 ~ 1:50,
       pch = 16,
       jitter.x = TRUE,
       type = c("n", "g"),
       scales = list(x = list(draw = FALSE),
                     y = list(draw = FALSE)),
       xlab = "x",
       ylab = list(label = "y",
                   rot = 0),
       key = list(space = "right",
                  text = list(c(expression(theta[1]!=0),
                                expression(theta[1]!=theta[2]),
                                expression(theta[2]!=0),
                                expression(theta[2]==0),
                                expression(theta[1]==0),
                                expression(theta[1]==theta[2]))), 
                  lines = list(col = c("white", "green3", "white", "magenta", "red", "blue"), 
                               lwd = 2))) +
  layer(with(list(vthB = 30,
                  th1 = 1,
                  thB = 20,
                  th2 = 2),
             panel.curve(vthB+{th1*(x-thB)}*(x <= thB)+th2*(x-thB),
                         col = 3,
                         lwd = 2))) +
  layer(with(list(vthB = 30,
                  th1 = 1,
                  thB = 20,
                  th2 = 0),
             panel.curve(vthB+{th1*(x-thB)}*(x <= thB)+th2*(x-thB),
                         col = 6,
                         lwd = 2))) +
  layer(with(list(vthB = 30,
                  th1 = 0,
                  thB = 20,
                  th2 = 4),
             panel.curve(vthB+{th1*(x-thB)}*(x <= thB)+th2*(x-thB),
                         col = 2,
                         lwd = 2))) +
  layer(with(list(vthB = 30,
                  th1 = 1,
                  thB = 20,
                  th2 = 1),
             panel.curve(vthB+{th1*(x-thB)}*(x <= thB)+th2*(x-thB),
                         col = 4,
                         lwd = 2)))

Curvas do modelo segmentado conhecido como bi-linear segmentado

Modelo segmentado conhecido como modelo quadrático-platô

Trata-se da junção de reta horizontal com o ponto crítico de modelo quadrático. O modelo pode ser escrito da seguinte forma:

{θ0+θ1x+θ2x2,xθ1/(2θ2)θ0+θ1(θ12θ2)+θ2(θ12θ2)2,x>θ1/(2θ2)

  • A função pode ser crescente ou decrescente na porção representada pelo modelo quadrático e constante para x>θb.
  • O intercepto é θ0;
  • θ1 é coeficiente angular que representa a taxa na origem;
  • θ2 é a curvatura.

A junção das funções é no ponto crítico do modelo quadrático e é calculada por θ1/(2θ2).

Reparametrização

ϑx=θ12θ2ϑy=θ0+θ1ϑx+θ2ϑ2x

θ1=2θ2ϑxθ0=ϑyθ1ϑxθ2ϑ2x

Resultando em:

{ϑy+θ2(xϑx)2,xϑxϑy,x>ϑx

  • O ponto crítico foi priorizado e representado de tal modo que ϑy é o valor máximo (θ2<0) ou mínimo (θ2>0) da função no ponto de junção ϑx.
xyplot(1:50 ~ 1:50,
       pch = 16,
       jitter.x = TRUE,
       type = c("n", "g"),
       scales = list(x = list(draw = FALSE),
                     y = list(draw = FALSE)),
       xlab = "x",
       ylab = list(label = "y",
                   rot = 0),
       key = list(space = "right",
                  title = expression(theta[2]),
                  cex.title = 1.15,
                  text = list(c("> 0", "< 0")), 
                  lines = list(col = c(3, 6), 
                               lwd = 2))) +
  layer(with(list(vthY = 30,
                  th2 = -1,
                  vthX = 20),
             panel.curve(vthY+{th2*(x-vthX)**2}*(x <= vthX),
                         col = 3,
                         lwd = 2))) +
  layer(with(list(vthY = 20,
                  th2 = 1,
                  vthX = 20),
             panel.curve(vthY+{th2*(x-vthX)**2}*(x <= vthX),
                         col = 6,
                         lwd = 2)))

Curvas do modelo segmentado conhecido como modelo quadrático-platô

Modelos com parâmetros condicionalmente lineares

Quando temos modelos não lineares mas com parâmetros condicionalmente lineares, podemos fazer o ajuste com a função nls e com o algoritmo plinear.

Mas o que são parâmetros condicionalmente lineares?

Um modelo é linear baseado na forma como seus parâmetros aparecem. Um modelo pode ser dito linear se toda derivada parcial

μy|xβi,i=0,1,2,...,p

não depender de qualquer parâmetro. (μy|x=β0+β1x1+β2x2, por exemplo).

No caso dos modelos não lineares, derivamos parcialmente nossa função f(x,θ) em relação a cada parâmetro de θ.

Suponha um modelo com três parâmetros, θT=[θ1 θ2 θ3]. Se dado o conhecimento do valor do parâmetro θ1, a derivada parcial de f(x,θ1) em relação a θ2 não depender de parâmetros, então dizemos que θ2 é um parâmetro condicionalmente linear.

Mostramos dois exemplos utilizando o mesmo conjunto de dados da seção Um ponto de quebra, o que fazer?

Exemplo: Modelo bi-linear segmentado

Este modelo já foi mostrado na seção Modelo segmentado conhecido como bi-linear segmentado. Reparametrizado ele é dado da seguinte forma:

{ϑb+θ1(xθb),xθbϑb+θ2(xθb),x>θb

  • ϑb é o valor da função no ponto de quebra θb.
  • θ1 e θ2 são os coeficientes ou taxas do primeiro e segundo segmentos de reta, respectivamente, que se encontram no ponto θb.

Temos um modelo linear a partir do momento em que conhecemos o ponto de quebra θb. Logo, os demais parâmetros do modelo são condicionalmente lineares. Veja as derivadas parciais:

f(x,θ)=ϑb+θ1(xθb)(xθb)+θ2(xθb)

f(x,θ)ϑb=1f(x,θ)θ1=xθbf(x,θ)θ2=xθbf(x,θ)θb={θ1,xθbθ2,x>θb

  • ϑb é linearmente independentemente;
  • Conhecendo θb, θ1 e θ2 são lineares.

Basicamente qualquer modelo não linear pode ser ajustado no R com a função nls.

Com o algoritmo plinear os parâmetros condicionalmente lineares não são ajustados. Para que isso aconteça devem ser passadas para a função as derivadas parciais e chutes iniciais são dados apenas para os demais parâmetros, θb neste caso.

path <- "~/Dropbox/CE092 - 2015-2/Alunos/Henrique/Piecewise Regression/shipment.txt"
data <- read.table(path,
                   header = TRUE)
m2 <- nls(y ~ cbind(1, {x1-thB}*(x1 <= thB), {x1-thB}*(x1 > thB)),
          start = list(thB = 250),
          algorithm = "plinear",
          data)
coef <- coefficients(m2)
attr(coef, "names")[2:4] <- c("vthB", "th1", "th2")
xyplot(y ~ x1,
       pch = 16,
       jitter.x = TRUE,
       type = c("p", "g"),
       xlab = expression(x[1]),
       ylab = list(label = "y",
                   rot = 0),
       scales = list(y = list(tick.number = 8)),
       xlim = c(100, 425),
       ylim = c(7, 16),
       data) +
  layer(with(as.list(coef),
             panel.curve(vthB+{th1*(x-thB)}*(x <= thB)+th2*(x-thB),
                         col = 3,
                         lwd = 2)))

Ajuste do modelo de regressão não linear com algoritmo plinear ao conjunto de dados dos carregamentos

m0 <- lm(y ~ x1,
         data)
coef.m0 <- coefficients(m0)
attr(coef.m0, "names") <- c("beta0", "beta1")
data$x2 <- with(data,
                ifelse(x1 <= 250, 0, x1 - 250))
m1 <- lm(y ~ x1 + x2,
         data)
coef.m1 <- coefficients(m1)
attr(coef.m1, "names") <- c("beta0", "beta1", "beta2")
xyplot(y ~ x1,
       pch = 16,
       jitter.x = TRUE,
       type = c("p", "g"),
       xlab = expression(x[1]),
       ylab = list(label = "y",
                   rot = 0),
       scales = list(y = list(tick.number = 8)),
       xlim = c(100, 425),
       ylim = c(7, 16),
       key = list(space = "right",
                  title = "Regressão",
                  cex.title = 1.15, 
                  text = list(c("Linear Simples", "Linear por Partes", "Não Linear - plinear")), 
                  lines = list(col = c(3, 4, 2), 
                               lwd = 2)),
       data) +
  layer(with(as.list(coef.m0),
             panel.curve(beta0+beta1*x,
                         col = 3,
                         lwd = 2))) +
  layer(with(as.list(coef.m1),
             panel.curve(beta0+{beta1*x}*(x <= 250)+{beta1*x+beta2*(x-250)}*(x > 250),
                         col = 4,
                         lwd = 2))) +
  layer(with(as.list(coef),
             panel.curve(vthB+{th1*(x-thB)}*(x <= thB)+th2*(x-thB),
                         col = 2,
                         lwd = 2)))

Ajuste do modelo de regressão linear simples, do modelo de regressão linear por partes e do modelo de regressão não linear com algoritmo plinear ao conjunto de dados dos carregamentos

Exemplo: Modelo Michaelis-Menten

O modelo Michaelis-Menten reparametrizado é dado da seguinte forma:

f(x,θ)=θaxϑq1qq+x

  • θa é a assíntota;
  • 0<q<1 é uma constante que representa uma fração de para o qual ϑq>0 é o valor correspondente na abscissa.

Aqui consideramos q=0.5.

Temos um modelo linear a partir do momento em que conhecemos ϑq. Logo, θa é condicionalmente linear. Veja as derivadas parciais:

f(x,θ)θa=xϑq+xf(x,θ)ϑq=θax(ϑq+x)2

  • Conhecendo ϑq, θa é linear;
  • ϑq é não linear.
m0 <- nls(y ~ x1/(vthQ+x1),
          start = list(vthQ = 110),
          algorithm = "plinear",
          data)
coef <- coefficients(m0)
attr(coef, "names")[2] <- "thA"
xyplot(y ~ x1,
       pch = 16,
       jitter.x = TRUE,
       type = c("p", "g"),
       xlab = expression(x[1]),
       ylab = list(label = "y",
                   rot = 0),
       scales = list(y = list(tick.number = 8)),
       xlim = c(100, 425),
       ylim = c(7, 16),
       data) +
  layer(with(as.list(coef),
             panel.curve(thA*x/(vthQ+x),
                         col = 3,
                         lwd = 2)))

Ajuste do modelo de regressão não linear Michaelis-Menten (reparametrizado) com algoritmo plinear ao conjunto de dados dos carregamentos


  1. Informações traduzidas de: A Tutorial on the Piecewise Regression Approach Applied to Bedload Transport Data

  2. O conjunto de dados analisado está disponível na seguinte página da Penn State University

  3. Este exemplo foi retirado do material Exempo Regressão por Partes do Professor Gilberto A. Paula

  4. Montgomery, D. C.; Peck, E. A. e Vining, G. G. (2001). Introduction to Linear Regression Analysis, Third Edition. Hoboken: Wiley.

  5. As informações contidas nesta seção foram retiradas do artigo de Muggeo (2003)

  6. Muggeo, V.M.R. (2003) Estimating regression models with unknown break-points. Statistics in Medicine 22, 3055-3071.

  7. A. Zeileis, F. Leisch, K. Hornik, and C. Kleiber. strucchange: An R package for testing for struc-tural change in linear regression models. Journal of Statistical Software, 7(2):1-38, 2002.

  8. Informações retiradas da Tese de Doutorado de Walmes Marques Zeviani. Parametrizações interpretáveis em modelos não lineares, 2013

  9. Este não é o único intuito e objetivo das reparametrizações, longe disso. Contudo, neste material, este é o intuito abordado