วิธีทำให้เส้นโค้งเรียบกับข้อมูลของฉันใน R


88

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 พิกัดเหล่านี้ไม่ควรเปลี่ยนแปลงโดยอัลกอริทึมที่เหมาะสม แต่ฉันต้องการจำลองข้อผิดพลาด (y) ที่ค่า x ที่หายไปตัวอย่างเช่นในข้อมูล 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 และ MASS ของ Ripley มีเนื้อหาทั้งหมดเกี่ยวกับการทำให้เรียบซึ่งครอบคลุมถึง Splines และพหุนาม - แต่loess()เป็นเพียงเรื่องโปรดของทุกคน


คุณนำข้อมูลนี้ไปใช้อย่างไร ฉันไม่แน่ใจว่าเป็นอย่างไรเพราะคาดว่าจะมีสูตร ขอบคุณ!
Frank

7
ดังที่ฉันแสดงให้คุณเห็นในตัวอย่างเมื่อตัวแปรif xและyสามารถมองเห็นได้ หากเป็นคอลัมน์ของ data.frame ที่มีชื่อว่าfooคุณจะเพิ่มdata=fooตัวเลือกในการloess(y ~ x. data=foo)โทรเช่นเดียวกับในฟังก์ชันการสร้างแบบจำลองอื่น ๆ เกือบทั้งหมดใน R.
Dirk Eddelbuettel เมื่อ

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

1
@Wichert Akkerman ดูเหมือนว่ารูปแบบวันที่จะถูกเกลียดโดยฟังก์ชัน R ส่วนใหญ่ ฉันมักจะทำอะไรเช่นใหม่ $ date = as.numeric (วันที่ $ ใหม่เป็นวันที่ ("2015-01-01") หน่วย = "วัน") (ตามที่อธิบายไว้ในstat.ethz.ch/pipermail/r- help / 2008- พฤษภาคม / 162719.html )
ลดกิจกรรม

59

อาจจะ smooth.spline เป็นตัวเลือกคุณสามารถตั้งค่าพารามิเตอร์การทำให้เรียบ (โดยทั่วไปอยู่ระหว่าง 0 ถึง 1) ที่นี่

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

คุณยังสามารถใช้การทำนายบนวัตถุ smooth.spline ฟังก์ชั่นมาพร้อมกับฐาน R ดูรายละเอียดได้ที่เส้นเรียบ


27

เพื่อที่จะได้รับมันจริงๆ 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)

25

qplot ()ฟังก์ชั่นในแพคเกจ ggplot2 เป็นเรื่องง่ายมากที่จะใช้งานและให้เป็นโซลูชั่นที่สง่างามที่รวมถึงวงดนตรีที่มีความเชื่อมั่น ตัวอย่างเช่น

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

ผลิต ใส่คำอธิบายภาพที่นี่


ไม่ใช่เพื่อหลบคำถาม แต่ฉันพบการรายงานของค่า R ^ 2 (หรือหลอก R ^ 2) เพื่อให้พอดีกับความเรียบเนียน ความนุ่มนวลจะต้องพอดีกับข้อมูลมากขึ้นเนื่องจากแบนด์วิดท์ลดลง
Underminer

สิ่งนี้อาจช่วยได้: stackoverflow.com/questions/7549694/…
Underminer

อืมฉันไม่สามารถเรียกใช้โค้ดของคุณใน R 3.3.1 ได้ในที่สุด ฉันติดตั้งggplot2bu ไม่สำเร็จqplotเพราะไม่พบฟังก์ชันใน Debian 8.5
LéoLéopold Hertz 준영

14

LOESS เป็นแนวทางที่ดีมากอย่างที่ Dirk กล่าวไว้

อีกทางเลือกหนึ่งคือการใช้ Bezier splines ซึ่งในบางกรณีอาจทำงานได้ดีกว่า 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)))

นี่คือข้อมูลที่ซ้อนทับกับเส้นโค้งซิกมอยด์ที่สร้างขึ้น:

ข้อมูล

ข้อมูลประเภทนี้เป็นเรื่องปกติเมื่อดูพฤติกรรมไบนารีในกลุ่มประชากร ตัวอย่างเช่นนี่อาจเป็นพล็อตว่าลูกค้าซื้อสินค้าหรือไม่ (เลขฐานสอง 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ในขณะที่ยังทำงานได้ค่อนข้างเร็ว (เร็วกว่า loess 15 เท่า)

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 นี้สำหรับกระบวนการต่อไป
เบ็น

3

ฉันไม่เห็นวิธีนี้แสดงดังนั้นหากมีคนอื่นต้องการทำเช่นนี้ฉันพบว่าเอกสาร 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

อันดับแรกด้วยวิธี loess และสูตรอัตโนมัติ ที่สองด้วยวิธี gam พร้อมสูตรที่แนะนำ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.