【问题标题】:Accounting for noise in 2D Gaussian model考虑二维高斯模型中的噪声
【发布时间】:2020-08-17 23:08:25
【问题描述】:

我需要将嵌入大量均匀噪声的 2D 高斯拟合,如下左图所示。我尝试将sklearn.mixture.GaussianMixture 与两个组件一起使用(代码在底部),但这显然失败了,如下右图所示。

我想将概率分配给属于 2D 高斯和均匀背景噪声的每个元素。这似乎是一项足够简单的任务,但我没有找到“简单”的方法。

有什么建议吗?它不需要是 GMM,我对其他方法/包持开放态度。


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

# Generate 2D Gaussian data
N_c = 100
xy_c = np.random.normal((.5, .5), .05, (N_c, 2))

# Generate uniform noise
N_n = 1000
xy_n = np.random.uniform(.0, 1., (N_n, 2))

# Combine into a single data set
data = np.concatenate([xy_c, xy_n])

# fit a Gaussian Mixture Model with two components
model = mixture.GaussianMixture(n_components=2, covariance_type='full')
model.fit(data)
probs = model.predict_proba(data)
labels = model.predict(data)
# Separate the two clusters for plotting
msk0 = labels == 0
c0, p0 = data[msk0], probs[msk0].T[0]
msk1 = labels == 1
c1, p1 = data[msk1], probs[msk1].T[1]

# Plot
plt.subplot(121)
plt.scatter(*xy_n.T, c='b', alpha=.5)
plt.scatter(*xy_c.T, c='r', alpha=.5)
plt.xlim(0., 1.)
plt.ylim(0., 1.)

plt.subplot(122)
plt.scatter(*c0.T, c=p0, alpha=.75)
plt.scatter(*c1.T, c=p1, alpha=.75)
plt.colorbar()
# display predicted scores by the model as a contour plot
X, Y = np.meshgrid(np.linspace(0., 1.), np.linspace(0., 1.))
XX = np.array([X.ravel(), Y.ravel()]).T
Z = -model.score_samples(XX)
Z = Z.reshape(X.shape)
plt.contour(X, Y, Z)

plt.show()

【问题讨论】:

  • 一般来说这个问题是相当困难的。您需要制作一个混合高斯分布和均匀分布的模型,然后使用EM algorithm 之类的东西拟合参数。但是,如果您对自己的数据了解得更多,实际上可能会有更简单的方法。噪声和信号分布的“相对高度”是多少?你知道信噪比吗?属于任一类的任何给定点的先验概率,还是高斯参数的先验概率?还有什么?
  • 不,我没有更多的数据知道只有一个高斯分布隐藏在噪声中。
  • 是的,KernelDensity 在这里可能很有用。 Here's 一个示例用例
  • 我不确定 KDE 在这种情况下会如何帮助我。我不需要使用核总和来表征样本的分布,我需要一种将二维高斯与噪声分离的方法。

标签: python machine-learning cluster-analysis gaussian mixture-model


【解决方案1】:

我认为内核密度可以帮助您定位高斯并排除它之外的点(例如在密度较小的区域)

这是一个示例代码:

import numpy as np
import matplotlib.pyplot as plt
from sklearn import mixture
from sklearn.neighbors import KernelDensity


# Generate 2D Gaussian data
N_c = 100
xy_c = np.random.normal((.2, .2), .05, (N_c, 2))

# Generate uniform noise
N_n = 1000
xy_n = np.random.uniform(.0, 1., (N_n, 2))

# Combine into a single data set
data = np.concatenate([xy_c, xy_n])
print(data.shape)

model = KernelDensity(kernel='gaussian',bandwidth=0.05)
model.fit(data)
probs = model.score_samples(data)

# Plot
plt.subplot(131)
plt.scatter(*xy_n.T, c='b', alpha=.5)
plt.scatter(*xy_c.T, c='r', alpha=.5)

plt.xlim(0., 1.)
plt.ylim(0., 1.)

# plot kernel score
plt.subplot(132)
plt.scatter(*data.T, c=probs, alpha=.5)

# display predicted scores by the model as a contour plot
X, Y = np.meshgrid(np.linspace(0., 1.), np.linspace(0., 1.))
XX = np.array([X.ravel(), Y.ravel()]).T
Z = -model.score_samples(XX)
Z = Z.reshape(X.shape)
plt.contour(X, Y, Z)
plt.xlim(0,1)
plt.ylim(0,1)

# plot kernel score with threshold
plt.subplot(133)
plt.scatter(*data.T, c=probs>0.5, alpha=.5) # here you can adjust the threshold
plt.colorbar()
plt.xlim(0,1)
plt.ylim(0,1)

这是输出图:

我更改了高斯的中心以确保我的代码正常工作。右侧面板显示带有阈值的内核分数,在您的情况下可用于过滤掉高斯之外的噪声数据,但您无法过滤高斯内部的噪声。

【讨论】:

  • 所以对于probs>0.5,您直接使用拟合KernelDensity 得到的概率来分配给“集群”或其他?
  • 是的,proba(它不是真正的proba)与一个区域的样本数量有关,所以在高斯区域会比在噪声区域高。阈值是一种将样本分类为“高斯”或“噪声”的简单方法,但您可以直接使用proba 来获得更少的二进制输出,就像在中间面板中显示的那样
  • 实际上,proba 这里是数据的对数似然,所以它表现得像一个概率(越高越好),但是这些值是标准化的,所以它不是一个概率。
  • 我明白了,我刚刚开始熟悉这个:) 这似乎是解决这个问题的一种非常方便的方法。很好的答案! @comartel
  • 是的,同意,如果你想要的是属于一个或另一个分布的概率,那么这不是正确的方法,那么@Gabriel
猜你喜欢
  • 1970-01-01
  • 2016-02-07
  • 2014-08-26
  • 2016-08-17
  • 2011-12-08
  • 1970-01-01
  • 2014-09-23
  • 1970-01-01
  • 2012-03-27
相关资源
最近更新 更多