Zeichnen einer stückweisen Regressionslinie

10

Gibt es eine Möglichkeit, die Regressionslinie eines solchen stückweisen Modells lineszu zeichnen , außer jedes Segment einzeln zu zeichnen oder zu verwenden 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

Vielen Dank.

George Dontas
quelle

Antworten:

6

Der einzige Weg, wie ich dies leicht tun kann, besteht darin, aus dem Modell über den gesamten Bereich hinweg sqftVorhersagen zu treffen und die Vorhersagen zu zeichnen. Es gibt keinen allgemeinen Weg mit ablineoder ähnlich. Sie können sich auch das segmentierte Paket ansehen , das zu diesen Modellen passt, und die Plotinfrastruktur für Sie bereitstellen.

Dies geschieht über Vorhersagen und Basisgrafiken. Zunächst einige Dummy-Daten:

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)

Passen Sie das Modell an:

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

Generieren Sie einige Daten, um sie vorherzusagen und vorherzusagen:

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))

Zeichnen Sie die Regressionslinien:

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)

Sie können dies in eine einfache Funktion zerlegen - Sie benötigen nur die Schritte in den beiden vorhergehenden Codeblöcken -, die Sie anstelle von 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)
}

Dann:

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)

Über das segmentierte Paket

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")

Mit diesen Daten wird der Haltepunkt nicht geschätzt mean(sqft), aber die Methoden plotund linesin diesem Paket können Ihnen dabei helfen, etwas Allgemeineres myablinezu implementieren, als diesen Job direkt vom angepassten lm()Modell aus für Sie zu erledigen .

Bearbeiten: Wenn Sie segmentieren möchten, um die Position des Haltepunkts zu schätzen, setzen Sie das 'psi'Argument auf NA:

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

Dann segmentedwerden K = 10Quantile von versucht sqft, Kwobei gesetzt wird seg.control()und welche standardmäßig verwendet werden 10. Weitere ?seg.controlInformationen finden Sie hier.

Stellen Sie Monica wieder her - G. Simpson
quelle
@ Gavin (+1) Weitaus umfassendere Antwort als meine; Ich mag es einfach.
Chl
@ Gavin Der Abschnitt "Über das segmentierte Paket" funktionierte für meine Daten nicht. Nach dem Ausführen des segmentedBefehls wurde "Kein Haltepunkt geschätzt" angezeigt.
George Dontas
@ gd047: Entschuldigung, es gab einen Fehler in dem Code, den ich gezeigt habe. Sie müssen das Argument seq.Zmit einer einseitigen Formel der Variablen angeben, die eine segmentierte Beziehung zur Antwort haben. Ich habe meine Antwort so bearbeitet, dass sie seq.Z = ~ sqfteinen Hinweis enthält, dass segmentedSie Werte psifür Sie ausgewählt haben.
Stellen Sie Monica wieder her - G. Simpson
@ gd047 Ich möchte meine Antwort entfernen, da diese Ihre ursprüngliche Frage besser anspricht. Würde es etwas ausmachen, diesen anstelle von mir zu akzeptieren?
Chl
@chl Natürlich, obwohl ich immer noch einen Fehler erhalte: Fehler in if (Modell) objF Modell <- mf: die Bedingung hat eine Länge> 1 und nur das erste Element wird verwendetmodel<mf:argumentisnotinterpretableaslogicalInaddition:Warningmessage:Inif(model)objF
George Dontas