【问题标题】:Fitting partial Gaussian拟合偏高斯
【发布时间】:2017-06-14 22:59:39
【问题描述】:

我正在尝试使用 scikit-learn 拟合高斯总和,因为 scikit-learn GaussianMixture 似乎比使用 curve_fit 更强大。

问题:即使是单个高斯峰的截断部分,它也不能很好地拟合:

from sklearn import mixture
import matplotlib.pyplot
import matplotlib.mlab
import numpy as np

clf = mixture.GaussianMixture(n_components=1, covariance_type='full')
data = np.random.randn(10000)
data = [[x] for x in data]
clf.fit(data)
data = [item for sublist in data for item in sublist]
rangeMin = int(np.floor(np.min(data)))
rangeMax = int(np.ceil(np.max(data)))
h = matplotlib.pyplot.hist(data, range=(rangeMin, rangeMax), normed=True);
plt.plot(np.linspace(rangeMin, rangeMax),
         mlab.normpdf(np.linspace(rangeMin, rangeMax),
                      clf.means_, np.sqrt(clf.covariances_[0]))[0])

给予 现在将 data = [[x] for x in data] 更改为 data = [[x] for x in data if x <0] 以截断分布返回 任何想法如何正确安装截断?

注意:分布不一定在中间被截断,可能会剩下完整分布的 50% 到 100% 之间的任何值。

如果有人能指出我的替代包,我也会很高兴。我只尝试了curve_fit,但一旦涉及两个以上的峰值,就无法让它做任何有用的事情。

【问题讨论】:

  • 您期待什么?高斯的一半不是高斯,所以一个简单的高斯的所有拟合都不能产生好的结果。当您尝试高斯混合时,您可以使用 mixtures。但是对于多个高斯的混合,您需要的不仅仅是n_components=1。这就是整个想法。
  • 不确定这是真的。如果您使用 curve_fit 对单个高斯进行拟合,则效果非常好。只是这对于一个以上的峰值不能有效地工作。另外,为简单起见,n_components=1...
  • scipy stats 模块具有名为 truncnorm 的截断高斯数据的特定统计分布,当我尝试它时,它符合您的示例截断数据。如果您可以使用它,请参阅 truncnorm 的 scipy 文档:docs.scipy.org/doc/scipy/reference/generated/…
  • 究竟是什么导致您在使用curve_fit 方法时遇到问题?您是否尝试过scipy.optimize 的其他最小化方法?这是一个非常强大的工具箱,我认为不应轻易放弃。
  • 我的数据非常嘈杂,用眼睛判断 GMM 通常会找到好的结果——除非部分数据被截断。我认为 GMM 的优势在于为拟合找到好的种子,这对于curve_fit 很难实现。当使用 curve_fit 一半的时间时,拟合甚至不会收敛。在这个问题上没有尝试过任何其他优化例程,但根据我的经验,它们都非常依赖于初始值。

标签: numpy scipy scikit-learn curve-fitting gaussian


【解决方案1】:

有点野蛮,但简单的解决方案是将曲线分成两半 (data = [[x] for x in data if x < 0]),镜像左侧部分 (data.append([-data[d][0]])),然后进行常规高斯拟合。

import numpy as np
from sklearn import mixture
import matplotlib.pyplot as plt
import matplotlib.mlab as mlab

np.random.seed(seed=42)
n = 10000

clf = mixture.GaussianMixture(n_components=1, covariance_type='full')

#split the data and mirror it
data = np.random.randn(n)
data = [[x] for x in data if x < 0]
n = len(data)
for d in range(n):
    data.append([-data[d][0]])

clf.fit(data)
data = [item for sublist in data for item in sublist]
rangeMin = int(np.floor(np.min(data)))
rangeMax = int(np.ceil(np.max(data)))
h = plt.hist(data[0:n], bins=20, range=(rangeMin, rangeMax), normed=True);
plt.plot(np.linspace(rangeMin, rangeMax),
         mlab.normpdf(np.linspace(rangeMin, rangeMax),
                      clf.means_, np.sqrt(clf.covariances_[0]))[0] * 2)

plt.show()

【讨论】:

  • 这看起来不错,但我应该提到的是,它不一定是分布的一半,但可以是任意截断(通常留下多于一半的分布来适应)。抱歉,我修改了问题。
【解决方案2】:

lhcgeneva 问题是,一旦你的数据不包括曲线的最大值,就会有越来越多的高斯可能拟合:

Black point represent the data, red points the fitted Gaussian

图中,黑点代表拟合曲线的数据,红点代表拟合结果。这个结果是通过使用A Simple Algorithm for Fitting a Gaussian Function实现的

【讨论】:

    猜你喜欢
    • 2014-11-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-30
    • 2012-07-15
    • 2015-07-26
    • 2021-10-14
    相关资源
    最近更新 更多