Накреслення кускової регресійної лінії


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робити цю роботу для вас прямо з пристосованої 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) Набагато повніша відповідь, ніж моя; Мені просто подобається.
chl

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

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

@ gd047 Я хотів би видалити свою відповідь, оскільки цей вирішує ваше первісне запитання ще кращим чином. Був би проти прийняття цього замість мого?
чл

@chl Звичайно, незважаючи на те, що я все-таки отримую помилку: Помилка if (модель) objF модель <- mf: умова має довжину> 1, і буде використано лише перший елементмогел<-мf:аrгументiснотiнтеrprетаблеаслогicалЯнаггiтiон:Wаrнiнгмессаге:Янif(могел)обjЖ
Джордж Донтас
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.