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
それはあなたのデータが何であるか、そしてあなたがそれを滑らかにしている理由に完全に依存します!データはカウントされますか?密度?測定?どのような測定誤差があるのでしょうか?グラフで読者に伝えようとしているストーリーは何ですか?これらの問題はすべて、データを平滑化するかどうか、およびどのように平滑化するかに影響します。
ハーラン

これらは測定データです。x値1、2、3、...、10で、一部のシステムで2、4、6、...、20のエラーが発生しました。これらの座標は、おそらくフィッティングアルゴリズムによって変更されるべきではありません。しかし、たとえばデータのf(4)= 8とf(5)= 7のように、欠落しているx値でのエラー(y)をシミュレートしたいので、おそらくf(4.5)は7から8の間の値です。いくつかの多項式または他の平滑化。
フランク

2
その場合、xの値ごとに1つのデータポイントがあるため、まったくスムーズになりません。測定されたデータポイントには大きな点があり、細い線で結ばれています。他の何かは、あなたがあなたよりもあなたのデータについてもっと知っていることを視聴者に示唆します。
ハーラン

あなたはこの例に正しいかもしれません。ただし、その方法を知っておくとよいでしょう。後で他のデータで使用したいと思うかもしれません。たとえば、非常にスパイクの多いデータポイントが何千もある場合は意味がありますが、一般的な傾向があります。 、たとえば、次のように上に移動します:plot(seq(1,100)+ runif(100、0,10)、type = 'l')。
フランク

これが良い方法です、stats.stackexchange.com / a / 278666/134555
Belter

回答:


104

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()ほぼすべての人のお気に入りです。


このデータにどのように適用しますか?数式を期待しているので、どうすればいいのかわかりません。ありがとう!
フランク

7
例で示したように、ifxyが表示変数である場合。彼らは名前のdata.frameの列がある場合foo、あなたは追加data=fooのオプションをloess(y ~ x. data=foo)呼び出し-ちょうどR.ほとんどすべての他のモデリング機能のように
ダークEddelbuettel

4
私はまたsupsmu()
すぐに使える

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
ウィッチャート・アッカーマン

1
@WichertAkkermanほとんどのR関数では日付形式が嫌われているようです。私は通常、new $ date = as.numeric(new $ date、as.Date( "2015-01-01")、units = "days")のようなことをしますstat.ethz.ch/pipermail/r-で説明されています) help / 2008-May / 162719.html
アクティビティの削減

58

たぶんsmooth.splineはオプションです。ここでスムージングパラメータ(通常は0から1の間)を設定できます。

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

また、smooth.splineオブジェクトでpredictを使用することもできます。この関数にはベース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 2016年

これが役立つことがあります。stackoverflow.com/questions/7549694/...
Underminer

うーん、R3.3.1で最終的にコードを実行できませんでした。Debian 8.5で機能が見つからないため、ggplot2正常にインストールしましたが実行qplotできません。
レオ・レオポルド・ヘルツ준 영

13

ダークが言ったように、LOESSは非常に良いアプローチです。

もう1つのオプションは、ベジェスプラインを使用することです。これは、データポイントが少ない場合、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には、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軸)のプロットである可能性があります。

これらの機能のパフォーマンスの違いをよりよく示すために、多数のポイントが使用されています。

Smoothsplinesmooth.spline私はおそらくノイズの多いデータのための仕事をしませんすべての点にマッピングする傾向に、試してみましたが、パラメータの任意のセットで、このようなデータセットのすべての農産物ちんぷんかんぷん。

loesslowess、と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は近いですが、両方の尾で奇妙な偏差が発生します。

あなたのデータセットが非常に異なるものになりますが、私は他のデータセットは、両方で、同様に実施することを発見したloesslowessの良好な結果を生成することができます。ベンチマークを見ると、違いはより重要になります。

> 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は非常に遅く、の100倍の時間がかかり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を以降のプロセスに使用することは可能ですか?
ベン

2

このメソッドが表示されていないので、他の誰かがこれを実行しようとしている場合、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

最初にレス法と自動式を使用 し、次に推奨式を使用したガム法を使用します

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.