我正在尝试使用the scipy.stats.gaussian_kde
class来平滑使用纬度和经度信息收集的一些离散数据,因此它最终显示为与等高线图有点相似,其中高密度是峰值,低密度是山谷。
我很难将二维数据集放入gaussian_kde
类。我已经玩弄了解它如何与1维数据一起工作,所以我认为2维将是这样的:
from scipy import stats
from numpy import array
data = array([[1.1, 1.1],
[1.2, 1.2],
[1.3, 1.3]])
kde = stats.gaussian_kde(data)
kde.evaluate([1,2,3],[1,2,3])
这就是说我[1.1, 1.1], [1.2, 1.2], [1.3, 1.3]
有3分。我希望在x和y轴上使用宽度为1的1到3进行核密度估计。
创建gaussian_kde时,它一直给我这个错误:
raise LinAlgError("singular matrix")
numpy.linalg.linalg.LinAlgError: singular matrix
查看gaussian_kde
的源代码,我意识到我正在考虑数据集的含义与维度的计算方式完全不同,但我找不到任何示例代码维度数据与模块一起使用。有人可以通过一些示例方法帮助我使用gaussian_kde
多维数据吗?
答案 0 :(得分:5)
This example似乎就是你要找的东西:
import numpy as np
import scipy.stats as stats
from matplotlib.pyplot import imshow
# Create some dummy data
rvs = np.append(stats.norm.rvs(loc=2,scale=1,size=(2000,1)),
stats.norm.rvs(loc=0,scale=3,size=(2000,1)),
axis=1)
kde = stats.kde.gaussian_kde(rvs.T)
# Regular grid to evaluate kde upon
x_flat = np.r_[rvs[:,0].min():rvs[:,0].max():128j]
y_flat = np.r_[rvs[:,1].min():rvs[:,1].max():128j]
x,y = np.meshgrid(x_flat,y_flat)
grid_coords = np.append(x.reshape(-1,1),y.reshape(-1,1),axis=1)
z = kde(grid_coords.T)
z = z.reshape(128,128)
imshow(z,aspect=x_flat.ptp()/y_flat.ptp())
显然,轴需要修理。
您还可以使用
执行数据的散点图scatter(rvs[:,0],rvs[:,1])
答案 1 :(得分:4)
我认为你正在将核密度估计与插值或内核回归混合在一起。如果您有更多的积分样本,KDE会估算积分的分布。
我不确定你想要哪种插值,但是scipy.interpolate中的样条线或rbf会更合适。
如果你想要一维内核回归,那么你可以在scikits.statsmodels中找到一个有几个不同内核的版本。
更新:这是一个例子(如果这是你想要的)
>>> data = 2 + 2*np.random.randn(2, 100)
>>> kde = stats.gaussian_kde(data)
>>> kde.evaluate(np.array([[1,2,3],[1,2,3]]))
array([ 0.02573917, 0.02470436, 0.03084282])
gaussian_kde在行中具有变量,在列中具有观察值,因此与统计中的常规方向相反。在您的示例中,所有三个点都在一条线上,因此它具有完美的相关性。也就是说,我猜,奇异矩阵的原因。
调整阵列方向并添加一个小噪声,该示例有效,但看起来仍然非常集中,例如您附近没有任何采样点(3,3):
>>> data = np.array([[1.1, 1.1],
[1.2, 1.2],
[1.3, 1.3]]).T
>>> data = data + 0.01*np.random.randn(2,3)
>>> kde = stats.gaussian_kde(data)
>>> kde.evaluate(np.array([[1,2,3],[1,2,3]]))
array([ 7.70204299e+000, 1.96813149e-044, 1.45796523e-251])
答案 2 :(得分:0)
顶部答案中发布的示例对我不起作用。我不得不稍微调整一下它现在有效:
import numpy as np
import scipy.stats as stats
from matplotlib import pyplot as plt
# Create some dummy data
rvs = np.append(stats.norm.rvs(loc=2,scale=1,size=(2000,1)),
stats.norm.rvs(loc=0,scale=3,size=(2000,1)),
axis=1)
kde = stats.kde.gaussian_kde(rvs.T)
# Regular grid to evaluate kde upon
x_flat = np.r_[rvs[:,0].min():rvs[:,0].max():128j]
y_flat = np.r_[rvs[:,1].min():rvs[:,1].max():128j]
x,y = np.meshgrid(x_flat,y_flat)
grid_coords = np.append(x.reshape(-1,1),y.reshape(-1,1),axis=1)
z = kde(grid_coords.T)
z = z.reshape(128,128)
plt.imshow(z,aspect=x_flat.ptp()/y_flat.ptp())
plt.show()
答案 3 :(得分:0)
我发现很难理解SciPy手册对gaussian_kde
如何处理2D数据的描述。这是一个解释,旨在补充@endolith的示例。我将代码分为几个步骤并加上注释,以解释较不直观的部分。
首先,导入:
import numpy as np
import scipy.stats as st
from matplotlib.pyplot import imshow, show
创建一些虚拟数据:它们是“ X”和“ Y”点坐标的一维数组。
np.random.seed(142) # for reproducibility
x = st.norm.rvs(loc=2, scale=1, size=2000)
y = st.norm.rvs(loc=0, scale=3, size=2000)
对于2D密度估计,gaussian_kde
对象必须使用包含两行包含“ X”和“ Y”数据集的数组来初始化。用NumPy术语,我们将它们“垂直堆叠”:
xy = np.vstack((x, y))
因此,“ X”数据在第一行xy[0,:]
中,而“ Y”数据在第二行xy[1,:]
中,而xy.shape
是(2, 2000)
。现在创建gaussian_kde
对象:
dens = st.gaussian_kde(xy)
我们将在2D网格上评估估计的2D密度PDF。在NumPy中创建网格的方法不止一种。我在这里展示了一种与@endolith的方法不同(但在功能上等效)的方法:
gx, gy = np.mgrid[x.min():x.max():128j, y.min():y.max():128j]
gxy = np.dstack((gx, gy)) # shape is (128, 128, 2)
gxy
是一个3-D数组,[i,j]
的第gxy
个元素包含对应的“ X”和“ Y”值的2元素列表:{{ 1}}的值为gxy[i, j]
。
我们必须在每个2D网格点上调用[ gx[i], gy[j] ]
(或dens()
这是同一件事)。 NumPy为此具有非常优雅的功能:
dens.pdf()
换句话说,可调用的z = np.apply_along_axis(dens, 2, gxy)
(也可能是dens
)是在3D数组dens.pdf
中沿axis=2
(第三轴)调用的,值应以二维数组形式返回。唯一的问题是gxy
的形状将是z
,而不是我期望的(128,128,1)
。请注意,documentation表示:
out的形状[返回值L.D.]与arr的形状相同,除了沿 轴尺寸。该轴已删除,并替换为新尺寸 等于func1d返回值的形状。所以如果func1d返回 标量输出将比arr少一维。
很可能(128,128)
返回了一个1个元组,而不是我希望的标量。我没有进一步调查该问题,因为这很容易解决:
dens()
之后,我们可以生成图像:
z = z.reshape(128, 128)
这是图像。 (请注意,我也已经实现了@endolith的版本,并且得到了与该版本没有区别的图像。)