考虑在2D高斯模型中噪音的影响

5

我需要拟合一个嵌入大量均匀噪声的二维高斯分布,如下图左侧所示。我尝试使用sklearn.mixture.GaussianMixture并使用两个组件(代码在底部),但显然会失败,如下图右侧所示。

enter image description here

我希望能为每个元素分配属于二维高斯和均匀背景噪声的概率。这似乎是一个足够简单的任务,但我没有找到“简单”的方法来完成它。
有什么建议吗?它不需要是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算法的方法拟合参数。但是,如果您更了解数据,可能会有更简单的方法。噪声和信号分布的“相对高度”是多少?您知道SNR吗?任何给定点属于任一类别或高斯参数的先验概率?还有其他什么? - bnaecker
不,我没有比这更多的数据,只知道在噪声中只有一个高斯分布。 - Gabriel
你看过核密度吗?https://scikit-learn.org/stable/auto_examples/neighbors/plot_species_kde.html#sphx-glr-auto-examples-neighbors-plot-species-kde-py - CoMartel
是的,KernelDensity 在这里可能很有用。这里有一个使用案例。 - yatu
我不确定在这种情况下如何使用KDE会对我有所帮助。我不需要使用核的总和来表征样本的分布,我需要一种将二维高斯与噪声分离的方法。 - Gabriel
显示剩余2条评论
1个回答

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)

而这就是输出的图形:

Output figure

我改变了高斯的中心以确保我的代码正常工作。右侧面板显示了核分数和阈值,这可以用于过滤高斯外部的嘈杂数据,但是你无法过滤高斯内部的噪音。

1
实际上,这里的 proba 是数据的对数似然,因此它的行为类似于概率(越高越好),但是这些值已经被归一化,因此并不是严格意义上的概率。 - CoMartel
1
我明白了,我刚开始熟悉这个 :) 这似乎是解决这个问题的非常方便的方法。好答案! @comartel - yatu
虽然这种方法看起来像是有效的,但它并不是解决原始问题的适当解决方案。它需要手动调整参数(不像GMM那样无监督),无法考虑“聚类”区域内的噪声,并且它没有利用重要的知识,即在“均匀”噪声中嵌入了聚类高斯(未纳入模型),并且它没有为属于任一分布(高斯/噪声)的点分配适当的概率。还是感谢CoMartel提供的答案! - Gabriel
对于您的所有评论,我都表示同意!此外:您可以尝试一些方法来自动查找阈值(例如Otsu阈值)。不幸的是,我认为您无法在高斯区域中将噪声与信号分离(但如果您找到了方法,我会非常感兴趣)。 - CoMartel
1
是的,如果你想要一个考虑到属于一个或另一个分布的概率,那么这不是正确的方法。@Gabriel - yatu
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接