R의 데이터에 부드러운 곡선을 맞추는 방법은 무엇입니까?


87

에서 부드러운 곡선을 그리려고합니다 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.


3
그것은 전적으로 데이터가 무엇이며 왜 그것을 평활화하는지에 달려 있습니다! 데이터가 중요합니까? 밀도? 측정? 어떤 종류의 측정 오류가있을 수 있습니까? 당신의 그래프로 독자들에게 어떤 이야기를하려고하십니까? 이러한 모든 문제는 데이터를 평활화할지 여부와 방법에 영향을줍니다.
Harlan

측정 된 데이터입니다. x 값 1, 2, 3, ..., 10에서 일부 시스템에서 2, 4, 6, ..., 20 개의 오류가 발생했습니다. 이러한 좌표는 피팅 알고리즘에 의해 변경되지 않아야합니다. 하지만 누락 된 x 값에서 오류 (y)를 시뮬레이션하고 싶습니다. 예를 들어 데이터에서 f (4) = 8 및 f (5) = 7이므로 아마도 f (4.5)는 7과 8 사이에 있습니다. 다항식 또는 기타 평활화.
Frank

2
이 경우 x의 각 값에 대해 단일 데이터 포인트를 사용하면 전혀 매끄럽지 않습니다. 측정 된 데이터 포인트에 대한 큰 점이 있고 얇은 선이 연결됩니다. 다른 어떤 것은 당신이 당신보다 당신의 데이터에 대해 더 많이 알고 있다는 것을 시청자에게 제안합니다.
Harlan

이 예에 맞을 수 있습니다. 그래도 방법을 아는 것이 좋습니다. 나중에 다른 데이터에 사용하고 싶을 수도 있습니다. 예를 들어 위아래로 이동하는 수천 개의 매우 뾰족한 데이터 포인트가있는 경우 이치에 맞지만 일반적인 추세가 있습니다. , 예를 들어 다음과 같이 위쪽으로 이동합니다 : plot (seq (1,100) + runif (100, 0,10), type = 'l').
Frank

다음은 좋은 방법입니다. stats.stackexchange.com/a/278666/134555
Belter

답변:


105

나는 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 and Ripley의 MASS 책에는 스플라인과 다항식도 포함하는 평활화에 대한 전체 섹션이 있지만 loess()거의 모든 사람들이 좋아합니다.


이 데이터에 어떻게 적용합니까? 공식을 기대하기 때문에 어떻게해야할지 모르겠습니다. 감사!
Frank

7
예에서 보여 드렸듯이 if xyare 보이는 변수입니다. 이름이라는 foodata=fooloess(y ~ x. data=foo)
data.frame의 열인 경우

4
나는 또한 같은 supsmu()아웃 - 오브 - 박스 부드러운로
apeescape

4
x가 날짜 매개 변수이면 어떻게 작동할까요? 날짜를 숫자에 매핑하는 데이터 테이블로 시도하면 (를 사용하여 lo <- loess(count~day, data=logins_per_day) ) 다음과 같이 표시됩니다.Error: NA/NaN/Inf in foreign function call (arg 2) In addition: Warning message: NAs introduced by coercion
Wichert Akkerman 2011 년

1
@Wichert Akkerman 대부분의 R 함수에서 날짜 형식을 싫어하는 것 같습니다. 나는 일반적으로 new $ date = as.numeric (new $ date, as.Date ( "2015-01-01"), units = "days") ( stat.ethz.ch/pipermail/r- 도움말 / 2008 월 / 162719.html )
감소 활동

58

smooth.spline이 옵션 일 수 있습니다. 여기서 스무딩 매개 변수 (일반적으로 0과 1 사이)를 설정할 수 있습니다.

smoothingSpline = smooth.spline(x, y, spar=0.35)
plot(x,y)
lines(smoothingSpline)

smooth.spline 객체에 예측을 사용할 수도 있습니다. 이 함수는 기본 R과 함께 제공됩니다. 자세한 내용은? smooth.spline을 참조하십시오.


27

정말 매끄럽게하기 위해서 ...

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)

25

ggplot2 패키지 의 qplot () 함수는 사용이 매우 간단하며 신뢰 구간을 포함하는 우아한 솔루션을 제공합니다. 예를 들어

qplot(x,y, geom='smooth', span =0.5)

생산하다 여기에 이미지 설명 입력


질문을 피하지 않으려 고하지만 평활 맞춤에 대한 R ^ 2 (또는 의사 R ^ 2) 값의보고가 모호하다고 생각합니다. 대역폭이 감소함에 따라 부드러움은 반드시 데이터에 더 가깝게 맞습니다.
Underminer

도움이 될 수 있습니다 : stackoverflow.com/questions/7549694/…
Underminer

흠, 마침내 R 3.3.1에서 코드를 실행할 수 없습니다. 데비안 8.5에서 기능을 찾을 수 없기 때문에 ggplot2성공적으로 설치 했습니다 qplot.
Léo Léopold Hertz 준영

14

LOESS는 Dirk가 말했듯이 매우 좋은 접근 방식입니다.

또 다른 옵션은 Bezier 스플라인을 사용하는 것입니다. 데이터 포인트가 많지 않은 경우 경우에 따라 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")

11

다른 대답은 모두 좋은 접근 방식입니다. 그러나, 몇 가지 다른 포함, 언급되지 않은 R의 옵션이 있습니다 lowessapprox더 나은 적합 또는 더 빠른 성능을 제공 할 수 있습니다.

장점은 대체 데이터 세트를 사용하면 더 쉽게 입증됩니다.

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

다음은 그것을 생성 한 시그 모이 드 곡선으로 겹쳐진 데이터입니다.

데이터

이러한 종류의 데이터는 모집단 간의 이진 행동을 볼 때 일반적입니다. 예를 들어, 고객이 구매했는지 여부 (y 축의 이진 1/0)와 사이트에서 보낸 시간 (x 축)의 플롯이 될 수 있습니다.

이러한 기능의 성능 차이를 더 잘 보여주기 위해 많은 포인트가 사용됩니다.

Smooth,, splinesmooth.spline모두 내가 시도한 모든 매개 변수 세트를 사용하여 이와 같은 데이터 세트에서 의미없는 말을 생성합니다.

loess, lowessapprox기능을 모두 생산 가능한 결과, 겨우위한 있지만 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매우 느리며 approx. 여전히 상당히 빠르게 (황토보다 15 배 빠름) 실행하면서 Lowess보다 나은 결과를 생성합니다 approx.

Loess 또한 포인트 수가 증가함에 따라 점점 줄어들어 약 50,000 점에서 사용할 수 없게됩니다.

편집 : 추가 연구에 따르면 loess특정 데이터 세트에 더 적합합니다. 작은 데이터 세트를 다루거나 성능이 고려되지 않는 경우 두 기능을 모두 시도하고 결과를 비교하십시오.


8

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) 

여기에 이미지 설명 입력 여기에 이미지 설명 입력


이 geom_smooth를 추가 프로세스에 사용할 수 있습니까?
Ben

3

이 방법이 표시되지 않았으므로 다른 사람이이 작업을 수행하려는 경우 ggplot 문서 에서 작은 데이터 세트로 작업 gamloess때 와 유사한 결과를 생성 하는 방법 을 사용하는 기술을 제안했음을 발견했습니다 .

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

첫 번째는 황토 법과 자동 공식으로 두 번째는 제안 된 공식을 사용한 감법으로

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.