【问题标题】:Trouble fitting curve to data set难以将曲线拟合到数据集
【发布时间】:2015-09-15 21:07:35
【问题描述】:

在过去的两天里,我一直在尝试将曲线拟合到以下数据集。正如您所看到的(从图像中),数据本身形成了一条近乎完美的曲线,但我无法找到一种方法来以数学方式表示数据以进行插值和外推。

y = c(0.2966, 0.2793, 0.2147, 0.1523, 0.1177, 0.1026, 0.0934, 0.0767, 
 0.0729, 0.0693, 0.0658, 0.0624, 0.0561, 0.0502, 0.0424, 0.04, 0.0356, 
 0.0335, 0.0316, 0.0279, 0.0231, 0.0217, 0.0203, 0.019, 0.02, 0.016, 
 0.0151, 0.0134, 0.0127, 0.0119, 0.0113, 0.0106, 0.01, 0.0094, 0.0089,
  0.0084, 0.0074, 0.007, 0.0062, 0.0059, 0.0053, 0.0048, 0.0043, 
  0.0041, 0.0037, 0.0033, 0.0032, 0.003, 0.0029, 0.0025, 0.0024, 
  0.0023, 0.0021, 0.002, 0.0016, 0.0016, 0.0014, 0.0012, 0.001, 
  0.0007, 0.0006, 0.0004, 0.0003)

x = c(0.77894, 0.79452, 0.85683, 0.92694, 0.97367, 0.99704, 1.01262, 
   1.04378, 1.05157, 1.05936, 1.06714, 1.07493, 1.09051, 1.10609, 
    1.12946, 1.13725, 1.15283, 1.16062, 1.16841, 1.18399, 1.20735, 
    1.21514, 1.22293, 1.23072, 1.2463, 1.25409, 1.26188, 1.27746, 
    1.28525, 1.29304, 1.30083, 1.30862, 1.3164, 1.32419, 1.33198, 
    1.33977, 1.35535, 1.36314, 1.37872, 1.38651, 1.40209, 1.41767, 
    1.43325, 1.44103, 1.45661, 1.47219, 1.47998, 1.48777, 1.49556, 
    1.51893, 1.52672, 1.53451, 1.55009, 1.55788, 1.58903, 1.59682, 
    1.6124, 1.63577, 1.67472, 1.75261, 1.79156, 1.86945, 1.92398) 

这是用指数曲线(粉红色)和 4 阶多项式(红色)绘制的数据。当四阶拟合时,指数曲线有相当多的误差,但您无法使用它进行推断,并且在应用于类似的数据集时,它并不总是有效。

对于我正在做的事情,我真的需要一些完全适合曲线的东西,但我还没有弄清楚如何去做。谢谢。

【问题讨论】:

  • 你可以试试:lm(log(y)~x)
  • 如果我没记错的话,这不是指数曲线的对数变换吗?
  • 看看log(y)x 的图,我会非常怀疑比指数/log(y) ~ x 更复杂的任何模型。
  • 关于近距离投票的猜测:要求一种完全适合并且可用于外推的方法确实要求不可能。
  • 感谢您以易于导入的格式提供数据。

标签: r math regression


【解决方案1】:

关于外推危险的实物课程。

在没有理论模型的情况下,使用逻辑函数 (f1(...)) 或缩放的对数正态密度函数 (f2(...)) 可以很好地拟合您的数据。可能还有其他功能也很适合。

df <- data.frame(x,y)
library(minpack.lm)   # for nlsLM(...)

f1 <- function(x,a,b,c,d) a*exp(-(b*x))/(1+c*exp(-d*x))
fit.1 <- nlsLM(y~f1(x,a,b,c,d), df, 
               start=c(a=1, b=1, c=100, d=0), control=list(maxiter=500))
f2 <- function(x,a,m,s) a*dlnorm(x, meanlog=m, sdlog=s)
fit.2 <- nlsLM(y~f2(x,a,m,s), df, 
               start=c(a=1, m=0, s=1), control=list(maxiter=500))

plot(y~x,df)
curve(predict(fit.1,data.frame(x)),add=TRUE, col="blue")
curve(predict(fit.2,data.frame(x)),add=TRUE, col="red")

但是看看当你推断时会发生什么。

plot(y~x, df, xlim=c(0.5,2), ylim=c(0,.6))
curve(predict(fit.1,data.frame(x)),add=TRUE, col="blue")
curve(predict(fit.2,data.frame(x)),add=TRUE, col="red")

事实证明,实际上对数正态密度函数的拟合效果稍微好一些,因为残差更接近正态,尽管两种情况下的残差都有很强的模式。关键是,仅通过查看数据和拟合曲线,您可能会接受任一函数,但它们会在外推时给出非常不同的结果,实际上两者都不是很好的拟合。你真的需要一个理论模型。

【讨论】:

    【解决方案2】:

    LOESS 回归似乎可以很好地处理这些数据。

    plot(y~x)
    
    ls <- loess(y~x, span = 0.5)
    pr <- predict(ls, x)
    
    lines(x, pr, col = "red", lwd = 2)
    

    【讨论】:

    • 这是一个完美的选择,但似乎没有办法从黄土函数中获得数学表示。
    • 您需要数学表示有什么特别的原因吗?除非您对生成该数据的过程有具体的了解,否则我不太确定会添加什么。在任何情况下,您都可以使用 predict 函数进行插值。
    • 这条曲线是一个更大问题的一部分。我需要这种表示来解决这个问题。因为它是数据中的关键关系之一。谢谢。
    • 嗯,使用 LOESS 的好处是它是非参数的。并不是说它是世界问题的解决方案,但如果您的数据背后没有理论模型,那么它可能是一种更安全的方法,具有不依赖特定函数来拟合数据的优势。您仍然可以进行插值/外推,但是,如果您确实需要一个方程,那么这不是一个好的解决方案(但请参阅@jlhoward 答案,它很好地说明了为什么假设一个特定的方程没有理由是不好的)。
    【解决方案3】:

    看起来 4 阶 B 样条表现不错:

    library("splines")
    m0 <- lm(y~bs(x,degree=4)) ## default: 5 df
    m1 <- lm(y~bs(x,degree=4,df=6))
    e1 <- glm(y~x,family=gaussian(link="log"))
    
    par(las=1,bty="l")
    plot(x,y,log="y")
    lines(x,predict(m0))
    lines(x,predict(m1),col=2)
    lines(x,predict(e1,type="response"),col=4)
    

    【讨论】:

      【解决方案4】:

      双对数图倾向于显示较大值的线性行为(即幂律),然后混合成更陡峭的斜率。您似乎可以将此图建模为直线加指数,但右侧的外推不确定。

      这个型号是

      log(y) = a.log(x) + b - c.d^log(x)
      

      y = A.x^B.exp(-C.x^D)
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2010-10-09
        • 1970-01-01
        • 2011-10-14
        • 2019-10-13
        • 2016-02-02
        • 2018-12-18
        • 1970-01-01
        相关资源
        最近更新 更多