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
でどのように書くかはわかりません。
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()
はほぼすべての人のお気に入りです。
おそらくsmooth.splineはオプションです。ここでスムージングパラメータを設定できます(通常0〜1)。
smoothingSpline = smooth.spline(x, y, spar=0.35)
plot(x,y)
lines(smoothingSpline)
smooth.splineオブジェクトでpredictを使用することもできます。この関数にはベースRが付属しています。詳細については、?smooth.splineを参照してください。
それを本当に滑らかにするために...
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)
ggplot2パッケージのqplot()関数は非常に使いやすく、信頼帯を含むエレガントなソリューションを提供します。例えば、
qplot(x,y, geom='smooth', span =0.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")
他の答えはすべて良いアプローチです。ただし、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)))
以下は、それを生成したシグモイド曲線でオーバーレイされたデータです。
この種のデータは、母集団間のバイナリ行動を見るときによく見られます。たとえば、これは、顧客が何かを購入したかどうか(y軸のバイナリ1/0)対サイトで費やした時間(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
は非常に遅く、approx
の100倍の時間がかかります。 Lowess
は、approx
よりも優れた結果をもたらしますが、それでもかなり高速に実行されます(黄土より15倍高速)。
Loess
も、ポイントの数が増えるとますます動きが悪くなり、約50,000使用できなくなります。
編集:追加の調査では、loess
が特定のデータセットにより適していることが示されています。小さいデータセットを扱っている場合やパフォーマンスが考慮されていない場合は、両方の機能を試して結果を比較してください。
このメソッドが表示されていないので、他の誰かがこれを実行しようとしている場合、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