如何从内核密度估计中获取内核(最好是sklearn.neighbors)?

时间:2017-07-25 12:55:10

标签: python scikit-learn kernel-density

我目前正致力于时间序列数据集的季节性估算。

我得到的是数据集中可能出现的可能频率/周期的数据集。因此,这有点嘈杂(例如,有一些时期为[100,98,101,102]实际应该是"相同")。

为了估计尖锐的周期,我尝试通过核密度估计(kde,sklearn.neighbors.KernelDensity)来估计峰值,如下所示:

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

X1 = np.random.randint(1, 4, 20)
X2 = np.random.randint(10, 13, 200)
X = np.concatenate((X1, X2), axis=0)
# the peaks schould be at 2 and 11!

bw = 1

kde = KernelDensity(kernel='gaussian', bandwidth=bw).fit(X.reshape(-1, 1))
estimator = np.linspace(0, 15, 100)
kde_est = np.exp(kde.score_samples(estimator.reshape(-1, 1)))

plt.plot(estimator, kde_est)

peaks_pos = signal.argrelextrema(kde_est, np.greater)[0]

print(estimator[peaks_pos])
# the peaks are at around 2 and 11!

此外,我想知道这个估算的内核是怎样的。对于高斯情况,应该有一组/ mu和/ sigma应该可用于所有[默认] 40内核。我可以访问这些信息吗? 我找不到文档中的线索或kde属性的详细信息。但我很确定,这应该可以在任何地方使用。

为了澄清,为什么我需要这个:

在下面的示例中,2个峰值距离太近而无法找到,但我确定内核会出现。

X1 = np.random.randint(1, 4, 20)
X2 = np.random.randint(5, 8, 200)
X = np.concatenate((X1, X2), axis=0)
# the peaks schould be at 2 and 6!

bw = 1

kde = KernelDensity(kernel='gaussian', bandwidth=bw).fit(X.reshape(-1, 1))
estimator = np.linspace(0, 15, 100)
kde_est = np.exp(kde.score_samples(estimator.reshape(-1, 1)))

plt.plot(estimator, kde_est)

peaks_pos = signal.argrelextrema(kde_est, np.greater)[0]

print(estimator[peaks_pos])
# the peaks are at around 6 and sometimes 2!

1 个答案:

答案 0 :(得分:2)

我相信你所寻找的东西在核密度估算中找不到。 KDE中的所有内核具有完全相同的形状(标准偏差),并以数据点为中心(因此均值由X中的值确定。)

你可以做些什么来防止正常分布与模糊峰值的接近程度是调整带宽(如果你的第二个样本,我设法通过使用0.7的带宽来获得相当一致的2个峰值。有代数方法可以做到这一点(参见:维基百科),或者您可以使用交叉验证为您的样本选择最佳带宽(请参阅:blog on the subject)

但是,如果要将数据集拆分为具有各种形状(权重,均值和协方差)的正态分布描述的不同组件,则可能需要使用高斯混合建模。你可以在下面找到一个例子。为了确定最佳组件数量,有各种方法,例如轮廓标准或akaike信息标准(内置于scikitlearn)。由于我们知道示例中有2个正态分布,因此我没有实现这样的标准,但您可以轻松地在互联网上找到更多信息。

X1 = np.random.randint(1, 4, 20)
X2 = np.random.randint(5, 8, 200)
X = np.concatenate((X1, X2), axis=0)
# the peaks schould be at 2 and 6!

components = 2

gmm = GaussianMixture(n_components = components).fit(X.reshape(-1,1))

#you can now directly get the means from the gaussian mixture models components,
#skipping the score_samples and signal.argrelextrema steps.
print gmm.means_
#the means are around 2 and 6!


#your original method of getting the peaks:
estimator = np.linspace(0, 15, 100)
gmm_est = np.exp(gmm.score_samples(estimator.reshape(-1,1)))

plt.hist(X,normed=True)
plt.plot(estimator,gmm_est,linewidth=5,color='black',alpha=0.7)


peaks_pos = signal.argrelextrema(gmm_est, np.greater)[0]

print(estimator[peaks_pos])


#plotting the separate components:
for n,weight in enumerate(gmm.weights_):
    plt.plot(estimator,weight*stats.norm.pdf(estimator,gmm.means_[n][0],np.sqrt(gmm.covariances_[n][0][0])))
plt.show()

image of results