आर में मेरे डेटा के लिए एक चिकनी वक्र कैसे फिट करें?


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 त्रुटियां कीं। ये निर्देशांक शायद फिटिंग एल्गोरिथम द्वारा नहीं बदले जाने चाहिए। लेकिन मैं लापता x मानों में त्रुटियों (y) का अनुकरण करना चाहता हूं, उदाहरण के लिए डेटा में, f (4) = 8 और f (5) = 7, इसलिए संभवतः f (4.5) का उपयोग 7 और 8 के बीच कुछ है कुछ बहुपद या अन्य चौरसाई।
फ्रैंक

2
उस स्थिति में, x के प्रत्येक मान के लिए एक एकल डेटा बिंदु के साथ, मैं बिल्कुल भी सहज नहीं होगा। मेरे पास अपने मापा डेटा बिंदुओं के लिए बस बड़े बिंदु हैं, उन्हें जोड़ने वाली पतली रेखाओं के साथ। दर्शक को कुछ भी पता चलता है कि आप अपने डेटा के बारे में अधिक जानते हैं।
हरलन

आप इस उदाहरण के लिए सही हो सकते हैं। यह जानना अच्छा है कि इसे कैसे करना है, और मैं इसे बाद में किसी अन्य डेटा पर उपयोग करना चाहता हूं, उदाहरण के लिए, यह समझ में आता है कि आपके पास हजारों बहुत नुकीले डेटा बिंदु हैं जो इस तरह के ऊपर और नीचे जाते हैं, लेकिन एक सामान्य प्रवृत्ति है , उदाहरण के लिए यहाँ की तरह ऊपर की ओर जाना: प्लॉट (seq (1,100) + रनिफ़ (100, 0,10), टाइप = 'l')।
फ्रैंक

यहाँ एक अच्छा तरीका है, आँकड़ें ।stackexchange.com
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)

वेनेबल्स और रिप्ले की एमएएस पुस्तक में चौरसाई पर एक पूरा खंड है जो स्प्लिन और बहुपद को भी कवर करता है - लेकिन loess()यह हर किसी के पसंदीदा के बारे में है।


आप इसे इस डेटा पर कैसे लागू करते हैं? मुझे यकीन नहीं है कि कैसे क्योंकि यह एक सूत्र की उम्मीद करता है। धन्यवाद!
फ्रैंक

7
जैसा कि मैंने आपको उदाहरण में दिखाया था कि कब xऔर yक्या दृश्यमान चर हैं। अगर वे नाम के एक data.frame के स्तंभ हैं foo, तो आप एक जोड़ने के data=fooविकल्प के लिए loess(y ~ x. data=foo)कॉल - बस आर के लगभग सभी अन्य मॉडलिंग कार्यों में तरह
एक प्रकार की कटार 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
@Wichert Akkerman ऐसा लगता है कि तारीख प्रारूप अधिकांश आर कार्यों से नफरत है। मैं आम तौर पर नई $ तारीख = as.numeric (नई $ तारीख, as.Date ("2015-01-01"), इकाइयों = "दिन") के अनुसार कुछ करता हूं (जैसा कि स्टेट पर वर्णित है ।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 वस्तुओं पर भविष्यवाणी का उपयोग कर सकते हैं। फ़ंक्शन आर के साथ आता है, विवरण के लिए देखें? 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

qplot () ggplot2 पैकेज में समारोह का उपयोग करने के बहुत सरल है और एक सुरुचिपूर्ण समाधान है कि आत्मविश्वास बैंड भी शामिल है प्रदान करता है। उदाहरण के लिए,

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

पैदा करता है यहाँ छवि विवरण दर्ज करें


सवाल को चकमा देने के लिए नहीं, लेकिन मैं एक चिकनी फिट के लिए आर ^ 2 (या छद्म आर ^ 2) मूल्यों की रिपोर्टिंग को संदिग्ध मानता हूं। बैंडविड्थ कम होते ही एक स्मूथी डेटा के करीब आ जाएगी।
अंडर्मिनर

यह आपकी मदद कर सकते हैं: stackoverflow.com/questions/7549694/...
Underminer

हम्म, मैं अंत में आर 3.3.1 में आपका कोड नहीं चला सकता था। मैंने ggplot2सफलतापूर्वक बू स्थापित किया है qplotक्योंकि यह डेबियन 8.5 में फ़ंक्शन नहीं ढूँढ सकता है।
लेओ लेपोल्ड हर्ट्ज़ '

13

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

11

अन्य उत्तर सभी अच्छे दृष्टिकोण हैं। हालांकि, आर में कुछ अन्य विकल्प हैं , जिनका उल्लेख नहीं किया गया है, जिनमें शामिल हैं 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)))

यहाँ सिग्मॉइड वक्र के साथ डेटा ओवरलेड है जो इसे उत्पन्न करता है:

डेटा

आबादी के बीच द्विआधारी व्यवहार को देखते हुए इस तरह का डेटा आम है। उदाहरण के लिए, यह ग्राहक द्वारा साइट पर खर्च किए गए समय (x- अक्ष) की राशि के अनुसार कुछ खरीदा (या एक द्विआधारी y- अक्ष पर 1) हो सकता है।

इन कार्यों के प्रदर्शन अंतर को बेहतर ढंग से प्रदर्शित करने के लिए बड़ी संख्या में बिंदुओं का उपयोग किया जाता है।

Smooth, splineऔरsmooth.spline सभी इस तरह के मापदंडों के किसी भी सेट के साथ एक डेटासेट पर gibberish का उत्पादन करते हैं, शायद मैंने हर बिंदु पर मैप करने की उनकी प्रवृत्ति के कारण, जो शोर डेटा के लिए काम नहीं करता है।

हालांकि 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 ले रही है approxLowessकी तुलना में बेहतर परिणाम पैदा करता है approx, जबकि अभी भी काफी तेजी से चल रहा है (15x तेजी से कम)।

Loess 50,000 की संख्या के आसपास अनुपयोगी होने के कारण अंकों की संख्या बढ़ने के साथ-साथ तेजी भी बढ़ती जा रही है।

EDIT: अतिरिक्त शोध से पता चलता है कि 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

पहले लोस विधि और ऑटो फॉर्मूला के साथ दूसरा सुझाव फार्मूला के साथ गम विधि के साथ

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.