【问题标题】:How do I fit a Gaussian curve to this data? [duplicate]如何将高斯曲线拟合到这些数据? [复制]
【发布时间】:2020-04-03 10:48:25
【问题描述】:

我是 R 的新手,我正试图得到一条曲线来拟合这个散布数据,这给了我一个高斯曲线。我真的很感激任何帮助。 数据:

library(tidyverse)
MK20 <- tribble(~X.Intensity,    ~Average,
             0.400,  0.0000000,
             0.463,  0.0000000,
             0.536,  0.000000,
             0.621,  0.0000000,
             0.719,  0.0000000,
             0.833,  0.0000000,
             0.965,  0.0000000,
             1.120,  0.0000000,
             1.290,  0.0000000,
             1.500,  0.0000000,
             1.740,  0.0000000,
             2.010,  0.0000000,
             2.330,  0.0000000,
             2.700,  0.0000000,
             3.120,  0.0000000,
             3.620,  0.0000000,
             4.190,  0.0000000,
             4.850,  0.0000000,
             5.610,  0.0000000,
             6.500,  0.0000000,
             7.530,  0.0000000,
             8.720,  0.0000000,
             10.100,  0.0000000,
             11.700,  0.0000000,
             13.500,  0.0000000,
             15.700,  0.0000000,
             18.200,  0.0000000,
             21.000,  0.0000000,
             24.400,  0.0000000,
             28.200,  0.0000000,
             32.700,  0.0000000,
             37.800,  0.0000000,
             43.800,  0.7023333,
             50.700,  3.3700000,
             58.800,  7.3933333,
             68.100, 11.4666667,
             78.800, 14.3666667,
             91.300, 15.4000000,
             106.000, 14.5000000,
             122.000, 12.0000000,
             142.000,  8.6433333,
             164.000,  5.2200000,
             190.000,  2.4500000,
             220.000,  0.7580000,
             255.000,  0.1306667,
             295.000,  0.0000000,
             342.000,  0.0000000,
             396.000,  0.0000000,
             459.000,  0.0000000,
             531.000,  0.0000000,
             615.000,  0.0000000,
             712.000,  0.0000000,
             825.000,  0.0000000,
             955.000,  0.0000000,
             1110.000,  0.0000000,
             1280.000,  0.0000000,
             1480.000,  0.0000000,
             1720.000,  0.0000000,
             1990.000,  0.0000000,
             2300.000,  0.0000000,
             2670.000,  0.0000000,
             3090.000,  0.0000000,
             3580.000,  0.0000000,
             4150.000,  0.0000000,
             4800.000,  0.0000000,
             5560.000,  0.0000000,
             6440.000,  0.0000000,
             7460.000,  0.0000000,
             8630.000,  0.0000000)

我用来绘图的代码是:

plot(log10(MK20$X.Intensity), MK20$Average, col=1, xlim=c(-0.5,4), ylim=c(0,20), xlab="Log(Average diameter)", ylab="Intensity", xaxt='n')

我正在使用 minor.tick.axis 函数在对数 x 轴上添加次要刻度。我想向该数据添加一条高斯曲线(最适合)。我尝试在绘图上添加type='l',但曲线并不平滑,我不希望曲线必须触及每个数据点,而是最适合的曲线。

如果解决方案很简单,但我无法弄清楚,我很抱歉。

【问题讨论】:

  • 这似乎是链接目标问题的副本。我建议看一下欺骗目标问题的答案。下面发布的答案均未显示如何拟合数据的正态分布。

标签: r gaussian best-fit-curve


【解决方案1】:

接触每个点的曲线肯定会最适合您的数据。 :)

除此之外,您可以尝试包含平滑曲线,例如

plot(log10(MK20$X.Intensity), MK20$Average, col=1, xlim=c(-0.5,4), ylim=c(0,20), 
     xlab="Log(Average diameter)", ylab="Intensity", xaxt='n', type='n')
lines(lowess(MK20$Average ~ log10(MK20$X.Intensity), f=0.3))

您可以在(0 和 1)之间改变 f= 参数以更改平滑级别。

这是 f=0.3 时的输出。

【讨论】:

    【解决方案2】:

    在这种情况下,我们不能使用通常的fitdistr 方法来拟合正态分布,因为我们没有原始数据。看起来“平均”列是某种类型的密度估计。如果它是 pdf,那么它应该集成到 1 但它没有。

    f <- approxfun(x = log10(MK20$X.Intensity), y= MK20$Average)
    integrate(f, lower = log10(0.4), upper = log10(8630))
    
    #6.142134 with absolute error < 0.00043
    

    因此我们可以通过将其缩小约 6.14 来将其转换为 pdf,然后尝试找到与该 pdf 匹配的均值和标准差。

    这是对简单高斯拟合的首次尝试。首先,我选择了平均值 2(通过查看密度最大的位置)、k = 6.14(积分值)的比例因子,然后使用 sd 直到有一个合理的拟合。

    m=2
    s=0.15
    k=6.14
    x_seq = seq(1,3,length.out = 100)
    df <- tibble(x_seq = x_seq, dens = dnorm(x_seq, m, s))
    
    
    MK20 %>% 
      mutate(log_intensity = log10(X.Intensity)) %>% 
      ggplot(aes(log_intensity, Average/k)) +
      geom_point() +
      geom_line(data = df, aes(x_seq, dens)) 
    

    接下来我使用 optimx 通过最小化拟合和数据之间的平方和来拟合 3 个参数(k = 比例因子、m = 平均值、s = 标准偏差)。

    目标函数(拟合和数据之间差异的平方和)

    f <- function(x) {
      k = x[1]
      m = x[2]
      s = x[3]
      MK20 %>% 
      mutate(log_intensity = log10(X.Intensity)) %>%
      mutate(fit = dnorm(log_intensity, m, s)) %>% 
      summarise(sum((fit - Average/k)^2)) %>% pull
    }
    

    使用 optimx 查找参数(最小平方和) 参数的初始值取自眼睛拟合。

    library(optimx)    
    optimx(par = c(6.14, 2, 0.15), fn = f )
    
    #k = 6.294696 m = 1.971488 s= 0.1583936 
    

    让我们用拟合的参数重新绘制

    # points for a gaussian
    x_seq = seq(1,3,length.out = 100) 
    df <- tibble(x_seq = x_seq, dens = dnorm(x_seq, m, s))
    
    
    MK20 %>% 
      mutate(log_intensity = log10(X.Intensity)) %>% 
      ggplot(aes(log_intensity, Average/k)) +
      geom_point() +
      geom_line(data = df, aes(x_seq, dens)) 
    

    【讨论】:

    • 这不合适。您正在为一组选定的参数(均值和方差)绘制正态分布。拟合是一种推理过程,用于获得以数据为条件的那些参数的估计值。你能修改你的答案以显示一个实际的适合吗?
    • @MauritsEvers 我的参数以数据为条件 - 我手动选择了参数以符合眼睛。不管你是对的,做得更好是可能和适当的。现在已经添加了一个数值拟合程序。
    • 手动选择参数以“通过眼睛拟合” 并不是统计界通常如何解释如何将模型拟合到数据的问题。事实上,这可能非常危险,因为眼睛可能是一个很差的判断力(参见例如Anscombe's quartet)。不要以错误的方式理解这一点,但这不是一个好的答案。首先,它表明了糟糕的统计实践。此外,在您的编辑中,您没有给出任何解释(参数、代码、算法等)来证明optimx 的使用。 [...]
    • [续] 将正态分布拟合到数据的典型方法是使用 MASS:: fitdistrfitdistrplus::fitdist 在这种情况下,对 OPs 问题的回答变成了单线(参见欺骗目标) . Stack Overflow 旨在建立一个全面的问题和答案目录,对有类似问题的人有用。由于上述原因,我认为您的“答案”不符合这些条件。
    • @MauritsEvers 也许我误解了这个问题,但我认为fitdistr 方法在这里不起作用,因为我们没有原始数据。我们有某种类型的密度估计。无论如何,我已经编辑了我的答案来解释我来自哪里。我也听从了你的建议来解释 optimx 在做什么。
    猜你喜欢
    • 2021-10-14
    • 1970-01-01
    • 2014-04-27
    • 1970-01-01
    • 2018-12-10
    • 1970-01-01
    • 2017-04-02
    • 1970-01-01
    • 2022-01-02
    相关资源
    最近更新 更多