sklearn中2D-KDE带宽与scipy带宽的关系

2024-06-06 15:58:42 发布

您现在位置:Python中文网/ 问答频道 /正文

我试图比较二维数组的sklearn.neighbors.KernelDensity与{a2}的性能。在

this article我看到在每个函数中带宽(bw)是不同的。本文给出了在scipy中设置正确bw的方法,因此它将与sklearn中使用的相同。基本上它用样本标准差除以bw。结果是:

# For sklearn
bw = 0.15

# For scipy
bw = 0.15/x.std(ddof=1)

其中x是我用来获取KDE的示例数组。这在1D中很好用,但在2D中我做不到

以下是我得到的信息:

^{pr2}$

iso2以指数形式表示,因为sklearn返回日志值)

我得到的iso1iso2的结果是不同的,我不知道应该如何影响带宽(在任何一个函数中)使它们相等(它们应该是这样)。在


添加

sklearn聊天时(由ep)告诉我,在用scipy计算内核之前,我应该缩放(x,y)中的值,以便获得与sklearn相比较的结果。在

我就是这么做的:

# Scale values.
x_val_sca = np.asarray(values[0])/np.asarray(values).std(axis=1)[0]
y_val_sca = np.asarray(values[1])/np.asarray(values).std(axis=1)[1]
values = [x_val_sca, y_val_sca]
kernel = stats.gaussian_kde(values, bw_method=bw_value)

ie:在使用scipy获取内核之前,我缩放了这两个维度,而保留了sklearn中获取内核的行。在

这给出了更好的结果,但得到的核仍然存在差异:

kernels

其中红点是代码中的(x1,y1)点。所以可以看出,尽管密度估计值很小,但在形状上仍然存在差异。也许这是能达到的最好的结果?在


Tags: 函数fornpvalscipy数组sklearn内核
1条回答
网友
1楼 · 发布于 2024-06-06 15:58:42

几年后,我尝试了这个方法,并认为我可以在不需要重新缩放数据的情况下使用它。但是带宽值确实需要一些缩放:

# For sklearn
bw = 0.15

# For scipy
bw = 0.15/x.std(ddof=1)

两个kde对同一点的求值不完全相等。例如,以下是对(x1, y1)点的评估:

^{2}$

但我想已经够近了。在

以下是二维情况下的MWE和输出,据我所见,几乎完全相同:

enter image description here

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

# Generate random data.
n = 1000
m1, m2 = np.random.normal(-3., 3., size=n), np.random.normal(-3., 3., size=n)
# Define limits.
xmin, xmax = min(m1), max(m1)
ymin, ymax = min(m2), max(m2)
ext_range = [xmin, xmax, ymin, ymax]
# Format data.
x, y = np.mgrid[xmin:xmax:100j, ymin:ymax:100j]
positions = np.vstack([x.ravel(), y.ravel()])
values = np.vstack([m1, m2])

# Define some point to evaluate the KDEs.
x1, y1 = 0.5, 0.5
# Bandwidth value.
bw = 0.15

#                            -
# Perform a kernel density estimate on the data using scipy.
# **Bandwidth needs to be scaled to match Sklearn results**
kernel = stats.gaussian_kde(
    values, bw_method=bw/np.asarray(values).std(ddof=1))
# Get KDE value for the point.
iso1 = kernel((x1, y1))
print 'iso1 = ', iso1[0]

#                            -
# Perform a kernel density estimate on the data using sklearn.
kernel_sk = KernelDensity(kernel='gaussian', bandwidth=bw).fit(zip(*values))
# Get KDE value for the point. Use exponential since sklearn returns the
# log values
iso2 = np.exp(kernel_sk.score_samples([[x1, y1]]))
print 'iso2 = ', iso2[0]


# Plot
fig = plt.figure(figsize=(10, 10))
gs = gridspec.GridSpec(1, 2)

# Scipy
plt.subplot(gs[0])
plt.title("Scipy", x=0.5, y=0.92, fontsize=10)
# Evaluate kernel in grid positions.
k_pos = kernel(positions)
kde = np.reshape(k_pos.T, x.shape)
plt.imshow(np.rot90(kde), cmap=plt.cm.YlOrBr, extent=ext_range)
plt.contour(x, y, kde, 5, colors='k', linewidths=0.6)

# Sklearn
plt.subplot(gs[1])
plt.title("Sklearn", x=0.5, y=0.92, fontsize=10)
# Evaluate kernel in grid positions.
k_pos2 = np.exp(kernel_sk.score_samples(zip(*positions)))
kde2 = np.reshape(k_pos2.T, x.shape)
plt.imshow(np.rot90(kde2), cmap=plt.cm.YlOrBr, extent=ext_range)
plt.contour(x, y, kde2, 5, colors='k', linewidths=0.6)

fig.tight_layout()
plt.savefig('KDEs', dpi=300, bbox_inches='tight')

相关问题 更多 >