Построение кусочно-регрессионной линии


10

Есть ли способ построения линии регрессии кусочной модели, подобной этой, кроме использования linesдля построения каждого сегмента отдельно или использования geom_smooth(aes(group=Ind), method="lm", fill=FALSE)?

m.sqft <- mean(sqft)
model <- lm(price~sqft+I((sqft-m.sqft)*Ind))
# sqft, price: continuous variables, Ind: if sqft>mean(sqft) then 1 else 0

plot(sqft,price)
abline(reg = model)
Warning message:
In abline(reg = model) :
  only using the first two of 3regression coefficients

Спасибо.

Ответы:


6

Единственный способ, которым я знаю, как это легко сделать, - это прогнозировать по модели во всем диапазоне sqftи строить прогнозы. Там нет общего пути с ablineили аналогичным. Вы также можете взглянуть на сегментированный пакет, который подойдет для этих моделей и предоставит для вас инфраструктуру печати.

Делать это с помощью прогнозов и базовой графики. Сначала несколько фиктивных данных:

set.seed(1)
sqft <- runif(100)
sqft <- ifelse((tmp <- sqft > mean(sqft)), 1, 0) + rnorm(100, sd = 0.5)
price <- 2 + 2.5 * sqft
price <- ifelse(tmp, price, 0) + rnorm(100, sd = 0.6)
DF <- data.frame(sqft = sqft, price = price,
                 Ind = ifelse(sqft > mean(sqft), 1, 0))
rm(price, sqft)
plot(price ~ sqft, data = DF)

Подходит модель:

mod <- lm(price~sqft+I((sqft-mean(sqft))*Ind), data = DF)

Создайте некоторые данные для прогнозирования и прогнозирования:

m.sqft <- with(DF, mean(sqft))
pDF <- with(DF, data.frame(sqft = seq(min(sqft), max(sqft), length = 200)))
pDF <- within(pDF, Ind <- ifelse(sqft > m.sqft, 1, 0))
pDF <- within(pDF, price <- predict(mod, newdata = pDF))

Постройте линии регрессии:

ylim <- range(pDF$price, DF$price)
xlim <- range(pDF$sqft, DF$sqft)
plot(price ~ sqft, data = DF, ylim = ylim, xlim = xlim)
lines(price ~ sqft, data = pDF, subset = Ind > 0, col = "red", lwd = 2)
lines(price ~ sqft, data = pDF, subset = Ind < 1, col = "red", lwd = 2)

Вы можете закодировать это в простую функцию - вам нужны только шаги в двух предыдущих фрагментах кода - которые вы можете использовать вместо abline:

myabline <- function(model, data, ...) {
    m.sqft <- with(data, mean(sqft))
    pDF <- with(data, data.frame(sqft = seq(min(sqft), max(sqft),
                                            length = 200)))
    pDF <- within(pDF, Ind <- ifelse(sqft > m.sqft, 1, 0))
    pDF <- within(pDF, price <- predict(mod, newdata = pDF))
    lines(price ~ sqft, data = pDF, subset = Ind > 0, ...)
    lines(price ~ sqft, data = pDF, subset = Ind < 1, ...)
    invisible(model)
}

Затем:

ylim <- range(pDF$price, DF$price)
xlim <- range(pDF$sqft, DF$sqft)
plot(price ~ sqft, data = DF, ylim = ylim, xlim = xlim)
myabline(mod, DF, col = "red", lwd = 2)

Через сегментированный пакет

require(segmented)
mod2 <- lm(price ~ sqft, data = DF)
mod.s <- segmented(mod2, seg.Z = ~ sqft, psi = 0.5,
                   control = seg.control(stop.if.error = FALSE))
plot(price ~ sqft, data = DF)
plot(mod.s, add = TRUE)
lines(mod.s, col = "red")

С помощью этих данных не оценить точку останова mean(sqft), но plotи linesметоды в этом пакете могут помочь вам реализовать что - то более общее , чем myablineсделать эту работу за вас diretcly от подобранной lm()модели.

Редактировать: если вы хотите, чтобы сегментация оценивала местоположение точки останова, установите для 'psi'аргумента NA:

mod.s <- segmented(mod2, seg.Z = ~ sqft, psi = NA,
                   control = seg.control(stop.if.error = FALSE))

Затем segmentedпопробуем K = 10квантили sqftс Kнастройками seg.control()и настройками по умолчанию 10. Смотрите ?seg.controlбольше.


@Gavin (+1) гораздо более полный ответ, чем мой; Мне просто нравится это.
ЧЛ

@Gavin Раздел «Через сегментированный пакет» не работал для моих данных. После выполнения segmentedкоманды я получил «Нет оценки точки останова» .
Джордж Донтас

@ gd047: Извините, в коде, который я показал, произошла ошибка. Вы должны предоставить аргумент seq.Zс односторонней формулой переменной (переменных), которые имеют сегментированную связь с ответом. Я отредактировал свой ответ, чтобы включить seq.Z = ~ sqftи добавил примечание о необходимости segmentedвыбора значений psiдля вас.
Гэвин Симпсон

@ gd047 Я бы хотел удалить свой ответ, так как этот ответ лучше подходит для вашего первоначального вопроса. Не против принять это вместо моего?
хл

@chl Конечно, хотя я все еще получаю сообщение об ошибке: Ошибка в модели objF if (model) <- mf: условие имеет длину> 1, и будет использоваться только первый элементмоdеL<-ме:aргUмеNTяsNоTяNTерпреTaбLеasLогясaLяNaddяTяоN:WaрNяNгмеssaге:яNяе(моdеL)обJF
Джордж Донтас
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.