So glätten Sie Daten und erzwingen Monotonie

14

Ich habe einige Daten, die ich glätten möchte, damit die geglätteten Punkte monoton abnehmen. Meine Daten nehmen stark ab und beginnen dann ein Plateau. Hier ist ein Beispiel mit R

df <- data.frame(x=1:10, y=c(100,41,22,10,6,7,2,1,3,1))
ggplot(df, aes(x=x, y=y))+geom_line()

Plot von Daten zu glätten

Was ist eine gute Glättungstechnik, die ich verwenden könnte? Außerdem wäre es schön, wenn ich den 1. geglätteten Punkt so einstellen könnte, dass er meinem beobachteten Punkt nahe kommt.

Ben
quelle
1
Ich stelle fest, dass Ihre Beispielwerte ganzzahlig sind. Sind Ihre wahren Werte von Bedeutung? Wenn dies der Fall ist (obwohl dies keine Garantie für Monotonie ist, wird es für solche Daten im Allgemeinen trotzdem plot(y~x,data=df); f=fitted( glm( y~ns(x,df=4), data=df,family=quasipoisson)); lines(df$x,f)
angezeigt
Ähnliche Q mit Antwort: stats.stackexchange.com/questions/206073/…
kjetil b halvorsen

Antworten:

17

Sie können dies mithilfe von bestraften Splines mit Monotonieeinschränkungen über die Funktionen mono.con()und pcls()im mgcv- Paket tun . Es muss ein wenig herumgespielt werden, da diese Funktionen nicht so benutzerfreundlich sind gam(), aber die folgenden Schritte basieren hauptsächlich auf dem Beispiel von ?pcls, das an die von Ihnen angegebenen Beispieldaten angepasst wurde:

df <- data.frame(x=1:10, y=c(100,41,22,10,6,7,2,1,3,1))

## Set up the size of the basis functions/number of knots
k <- 5
## This fits the unconstrained model but gets us smoothness parameters that
## that we will need later
unc <- gam(y ~ s(x, k = k, bs = "cr"), data = df)

## This creates the cubic spline basis functions of `x`
## It returns an object containing the penalty matrix for the spline
## among other things; see ?smooth.construct for description of each
## element in the returned object
sm <- smoothCon(s(x, k = k, bs = "cr"), df, knots = NULL)[[1]]

## This gets the constraint matrix and constraint vector that imposes
## linear constraints to enforce montonicity on a cubic regression spline
## the key thing you need to change is `up`.
## `up = TRUE` == increasing function
## `up = FALSE` == decreasing function (as per your example)
## `xp` is a vector of knot locations that we get back from smoothCon
F <- mono.con(sm$xp, up = FALSE)   # get constraints: up = FALSE == Decreasing constraint!

Jetzt müssen wir das Objekt ausfüllen, an das pcls()die Details des bestraften beschränkten Modells übergeben werden, das angepasst werden soll

## Fill in G, the object pcsl needs to fit; this is just what `pcls` says it needs:
## X is the model matrix (of the basis functions)
## C is the identifiability constraints - no constraints needed here
##   for the single smooth
## sp are the smoothness parameters from the unconstrained GAM
## p/xp are the knot locations again, but negated for a decreasing function
## y is the response data
## w are weights and this is fancy code for a vector of 1s of length(y)
G <- list(X = sm$X, C = matrix(0,0,0), sp = unc$sp,
          p = -sm$xp, # note the - here! This is for decreasing fits!
      y = df$y,
          w = df$y*0+1)
G$Ain <- F$A    # the monotonicity constraint matrix
G$bin <- F$b    # the monotonicity constraint vector, both from mono.con
G$S <- sm$S     # the penalty matrix for the cubic spline
G$off <- 0      # location of offsets in the penalty matrix

Jetzt können wir endlich die Anprobe machen

## Do the constrained fit 
p <- pcls(G)  # fit spline (using s.p. from unconstrained fit)

penthält einen Koeffizientenvektor für die Basisfunktionen, die dem Spline entsprechen. Um den angepassten Spline zu visualisieren, können wir aus dem Modell 100 Positionen über den Bereich von x vorhersagen. Wir machen 100 Werte, um eine schöne glatte Linie auf dem Plot zu bekommen.

## predict at 100 locations over range of x - get a smooth line on the plot
newx <- with(df, data.frame(x = seq(min(x), max(x), length = 100)))

Um vorhergesagte Werte zu generieren, verwenden wir Predict.matrix()eine Matrix, die bei multiplen Koeffizienten pvorhergesagte Werte aus dem angepassten Modell ergibt:

fv <- Predict.matrix(sm, newx) %*% p
newx <- transform(newx, yhat = fv[,1])

plot(y ~ x, data = df, pch = 16)
lines(yhat ~ x, data = newx, col = "red")

Dies erzeugt:

Bildbeschreibung hier eingeben

Ich überlasse es Ihnen, die Daten in ein ordentliches Formular für das Plotten mit ggplot zu bringen ...

Sie können eine engere Anpassung erzwingen (um Ihre Frage nach der Anpassung des Glätters an den ersten Datenpunkt teilweise zu beantworten), indem Sie die Dimension der Basisfunktion von vergrößern x. Wenn Sie zum Beispiel kgleich 8( k <- 8) setzen und den obigen Code erneut ausführen, erhalten Sie

Bildbeschreibung hier eingeben

Sie können kfür diese Daten nicht viel mehr tun, und Sie müssen vorsichtig sein, wenn Sie übermäßig anpassen. Alles, pcls()was Sie tun müssen, ist, das Problem der bestraften kleinsten Fehlerquadrate zu lösen, da die Einschränkungen und die bereitgestellten Basisfunktionen vorhanden sind.

Wenn Sie eine Interpolation wünschen, sehen Sie sich die Basis-R-Funktion an, ?splinefundie Hermite-Splines und kubische Splines mit Monotonizitätsbeschränkungen enthält. In diesem Fall können Sie dies jedoch nicht verwenden, da die Daten nicht streng monoton sind.

Setzen Sie Monica - G. Simpson wieder ein
quelle
Vielen Dank. Ich bin mir sicher, dass Ihre Lösung angemessen ist, aber sie ist so komplex und verschleiert, dass ich sie einfach nicht verwenden kann. splinefunwar mein erster Gedanke auch (ich interpoliere), aber spline(x=df$x, y=df$y, n=nrow(df), method="monoH.FC")und spline(x=df$x, y=df$y, n=nrow(df), method="hyman")beide werfen Fehler
Ben
Wenn Sie es einfach versuchen, können Sie es sicher verwenden. Ich habe keine Ahnung, was hier unter der Haube vor sich geht, aber ich habe es ausgearbeitet und die Stellen angegeben, an denen Sie Änderungen vornehmen müssen. Vorausgesetzt, Sie kennen ein R natürlich . Der größte Teil der Details ist implementierungsbezogen und kann ignoriert werden, wenn alles, was Sie tun möchten, in einen monoton beschränkten Spline passt. Möchten Sie, dass ich den Code ein bisschen mehr beschrifte, um mehr über die einzelnen Schritte hervorzuheben? Der Verweis in ?mono.conenthält weitere Einzelheiten zu dem Verfahren.
Setzen Sie Monica - G. Simpson
Warum splinefunwird ein Fehler ausgelöst? Ich habe gerade festgestellt, dass Sie einen monotonen Spline anpassen können, der Daten interpoliert, die selbst nicht monoton sind. Die Beobachtung bei x = 6ist größer yals die Beobachtungen bei x = 5. Sie müssen nur diesen Teil der Antwort ignorieren :-)
Setzen Sie Monica - G. Simpson
Ich habs. Und keine Notwendigkeit - ich bin ein ziemlich erfahrener R-Benutzer. Ich verstehe nur gerne die Mathematik hinter dem, was ich benutze, und diese Lösung scheint ziemlich viel unter der Haube zu haben. Danke nochmal für deine Hilfe.
Ben
Ich habe einige Notizen hinzugefügt, um zu erklären, was die einzelnen Dinge sind oder tun. Der wichtigste zu beachtende Punkt ist, dass die Monotonie-Einschränkungen durch eine bestimmte Menge von Ungleichheits-Einschränkungen auferlegt werden, mono.condie für einen kubischen Spline zurückgegeben werden. ?pclsEs gibt Beispiele für dünne Plattensplines und additive Modelle, die weniger benutzerfreundlich sind als die oben genannten, die jedoch möglicherweise mehr Rechenaufwand bedeuten, wenn Sie mit den Mathematiken für diese Spline-Typen vertraut sind (ich bin selbst nicht so vertraut).
Setzen Sie Monica - G. Simpson
13

Das kürzlich erschienene Betrugspaket von Natalya Pya, das auf dem Artikel "Shape constrained additive models" von Pya & Wood (2015) basiert, kann einen Teil des in Gavins exzellenter Antwort erwähnten Prozesses erheblich vereinfachen.

library(scam)
con <- scam(y ~ s(x, k = k, bs = "mpd"), data = df)
plot(con)

Es gibt eine Reihe von bs-Funktionen, die Sie verwenden können - im obigen Beispiel habe ich mpd für "monoton abnehmenden P-Spline" verwendet, aber es hat auch Funktionen, die Konvexität oder Konkavität entweder separat oder neben den monotonen Bedingungen erzwingen.

srepho
quelle