Как поместить гладкую кривую в мои данные в R?
Я пытаюсь сделать гладкую кривую в R
. У меня есть следующие простые данные о игрушке:
> x
[1] 1 2 3 4 5 6 7 8 9 10
> y
[1] 2 4 6 8 7 12 14 16 18 20
Теперь, когда я рисую его со стандартной командой, он выглядит неуклюжим и резким, конечно:
> plot(x,y, type='l', lwd=2, col='red')
Как сделать кривую гладкой, чтобы 3 края округлились с использованием оценочных значений? Я знаю, что есть много методов, чтобы соответствовать гладкой кривой, но я не уверен, какой из них наиболее подходит для этого типа кривой и как вы напишете ее в R
.
Ответы
Ответ 1
Мне нравится loess()
много для сглаживания:
x <- 1:10
y <- c(2,4,6,8,7,12,14,16,18,20)
lo <- loess(y~x)
plot(x,y)
lines(predict(lo), col='red', lwd=2)
В книге Venables и Ripley MASS имеется целый раздел о сглаживании, который также охватывает сплайны и полиномы, но loess()
- это почти все любимые.
Ответ 2
Возможно, smooth.spline является опцией, здесь вы можете установить параметр сглаживания (обычно между 0 и 1)
smoothingSpline = smooth.spline(x, y, spar=0.35)
plot(x,y)
lines(smoothingSpline)
вы также можете использовать прогноз для объектов smooth.spline. Функция поставляется с базой R, см.
? smooth.spline для деталей.
Ответ 3
Чтобы получить это ДЕЙСТВИТЕЛЬНО smoooth...
x <- 1:10
y <- c(2,4,6,8,7,8,14,16,18,20)
lo <- loess(y~x)
plot(x,y)
xl <- seq(min(x),max(x), (max(x) - min(x))/1000)
lines(xl, predict(lo,xl), col='red', lwd=2)
Этот стиль интерполирует много лишних очков и дает вам кривую, которая очень гладкая. Это также похоже на тот подход, который выполняет ggplot. Если стандартный уровень гладкости прекрасен, вы можете просто использовать.
scatter.smooth(x, y)
Ответ 4
Функция qplot() в пакете ggplot2 очень проста в использовании и представляет собой элегантное решение, которое включает в себя доверительные диапазоны. Например,
qplot(x,y, geom='smooth', span =0.5)
производит
![enter image description here]()
Ответ 5
LOESS - очень хороший подход, как сказал Дирк.
Другой вариант - использовать сплайны Безье, которые в некоторых случаях могут работать лучше, чем LOESS, если у вас мало точек данных.
Здесь вы найдете пример: http://rosettacode.org/wiki/Cubic_bezier_curves#R
# x, y: the x and y coordinates of the hull points
# n: the number of points in the curve.
bezierCurve <- function(x, y, n=10)
{
outx <- NULL
outy <- NULL
i <- 1
for (t in seq(0, 1, length.out=n))
{
b <- bez(x, y, t)
outx[i] <- b$x
outy[i] <- b$y
i <- i+1
}
return (list(x=outx, y=outy))
}
bez <- function(x, y, t)
{
outx <- 0
outy <- 0
n <- length(x)-1
for (i in 0:n)
{
outx <- outx + choose(n, i)*((1-t)^(n-i))*t^i*x[i+1]
outy <- outy + choose(n, i)*((1-t)^(n-i))*t^i*y[i+1]
}
return (list(x=outx, y=outy))
}
# Example usage
x <- c(4,6,4,5,6,7)
y <- 1:6
plot(x, y, "o", pch=20)
points(bezierCurve(x,y,20), type="l", col="red")
Ответ 6
Другие ответы - все хорошие подходы. Однако есть несколько других опций в R, которые не были упомянуты, включая lowess
и approx
, что может дать лучшие возможности или более высокую производительность.
Преимущества легче продемонстрировать с помощью альтернативного набора данных:
sigmoid <- function(x)
{
y<-1/(1+exp(-.15*(x-100)))
return(y)
}
dat<-data.frame(x=rnorm(5000)*30+100)
dat$y<-as.numeric(as.logical(round(sigmoid(dat$x)+rnorm(5000)*.3,0)))
Вот данные, наложенные на сигмовидную кривую, которые сгенерировали ее:
![Данные]()
Подобные данные распространены при рассмотрении бинарного поведения среди населения. Например, это может быть график того, покупает ли покупатель что-то (двоичный код 1/0 по оси Y) и количество времени, которое они потратили на сайт (ось x).
Большое количество точек используется, чтобы лучше продемонстрировать различия в производительности этих функций.
Smooth
, spline
и smooth.spline
все производят тарабарщину в наборе данных, подобном этому, с любым набором параметров, которые я пробовал, возможно, из-за их склонности к сопоставлению с каждой точкой, что не работает для шумных данных.
Функции loess
, lowess
и approx
все дают полезные результаты, хотя и едва для approx
. Это код для каждого, используя слегка оптимизированные параметры:
loessFit <- loess(y~x, dat, span = 0.6)
loessFit <- data.frame(x=loessFit$x,y=loessFit$fitted)
loessFit <- loessFit[order(loessFit$x),]
approxFit <- approx(dat,n = 15)
lowessFit <-data.frame(lowess(dat,f = .6,iter=1))
И результаты:
plot(dat,col='gray')
curve(sigmoid,0,200,add=TRUE,col='blue',)
lines(lowessFit,col='red')
lines(loessFit,col='green')
lines(approxFit,col='purple')
legend(150,.6,
legend=c("Sigmoid","Loess","Lowess",'Approx'),
lty=c(1,1),
lwd=c(2.5,2.5),col=c("blue","green","red","purple"))
![Подходит]()
Как вы можете видеть, lowess
создает почти идеальную подгонку к исходной кривой генерации. loess
близок, но испытывает странное отклонение на обоих хвостах.
Хотя ваш набор данных будет совсем другим, я обнаружил, что другие наборы данных работают аналогично, причем loess
и lowess
способны создавать хорошие результаты. Различия становятся более значительными, когда вы смотрите на тесты:
> microbenchmark::microbenchmark(loess(y~x, dat, span = 0.6),approx(dat,n = 20),lowess(dat,f = .6,iter=1),times=20)
Unit: milliseconds
expr min lq mean median uq max neval cld
loess(y ~ x, dat, span = 0.6) 153.034810 154.450750 156.794257 156.004357 159.23183 163.117746 20 c
approx(dat, n = 20) 1.297685 1.346773 1.689133 1.441823 1.86018 4.281735 20 a
lowess(dat, f = 0.6, iter = 1) 9.637583 10.085613 11.270911 11.350722 12.33046 12.495343 20 b
loess
чрезвычайно медленный, принимая 100x до тех пор, пока approx
. lowess
дает лучшие результаты, чем approx
, но все еще работает довольно быстро (15 раз быстрее, чем лесс).
loess
также становится все более увязшим, поскольку количество очков увеличивается, становясь непригодным для использования около 50 000.
EDIT: дополнительные исследования показывают, что loess
дает лучшие приемы для некоторых наборов данных. Если вы имеете дело с небольшим набором данных или производительности, это не соображение, попробуйте обе функции и сравните результаты.
Ответ 7
В ggplot2 вы можете делать сглаживание несколькими способами, например:
library(ggplot2)
ggplot(mtcars, aes(wt, mpg)) + geom_point() +
geom_smooth(method = "gam", formula = y ~ poly(x, 2))
ggplot(mtcars, aes(wt, mpg)) + geom_point() +
geom_smooth(method = "loess", span = 0.3, se = FALSE)
![enter image description here]()
Ответ 8
Я не видел этот метод, показанный, поэтому, если кто-то еще хочет это сделать, я обнаружил, что в документации ggplot предложен метод использования gam
метода, который дает схожие результаты с loess
при работе с небольшими наборами данных.
library(ggplot2)
x <- 1:10
y <- c(2,4,6,8,7,8,14,16,18,20)
df <- data.frame(x,y)
r <- ggplot(df, aes(x = x, y = y)) + geom_smooth(method = "gam", formula = y ~ s(x, bs = "cs"))+geom_point()
r
Во-первых, с помощью метода Лёсса и авто-формулы. Во-вторых, с помощью метода гам с предложенной формулой