【问题标题】:Estimate joint density with 2d Gaussian kernel使用 2d 高斯核估计联合密度
【发布时间】:2021-11-13 23:29:56
【问题描述】:

我有以下数据集,我必须使用具有二维高斯核和宽度 h=5 的核密度估计来估计“bwt”和“年龄”的联合密度。我不能使用诸如 scipy 之类的模块,其中有现成的函数可以执行此操作,我必须构建函数来计算密度。这是我到目前为止所得到的。

import numpy as np
import pandas as pd

babies_full = pd.read_csv("https://www2.helsinki.fi/sites/default/files/atoms/files/babies2.txt", sep='\t')

#Getting the columns I need
babies_full1=babies_full[['gestation', 'age']]
x=np.array(babies_full1,'int')

#2d Gaussian kernel 
def k_2dgauss(x):
    return np.exp(-np.sum(x**2, 1)/2) / np.sqrt(2*np.pi)

#Multivariate kernel density
def mv_kernel_density(t, x, h):
    d = x.shape[1]
    return np.mean(k_2dgauss((t - x)/h))/h**d

t = np.linspace(1.0, 5.0, 50)
h=5
print(mv_kernel_density(t, x, h))

但是,我收到一个值错误“ValueError:操作数无法与形状 (50,) (1173,2) 一起广播”,这认为是因为矩阵的形状不同。我也不明白为什么 k_2dgauss(x) 对我来说返回一个零数组,因为它应该只返回一个值。一般来说,我对核密度估计的概念是新手,我真的不知道我是否写对了函数,所以任何提示都会有所帮助!

【问题讨论】:

  • 您的第一个问题是(t-x)t 的形状为 (50),x 的形状为 (1173,2),因此 python 目前无法执行此第一个操作。你到底想让(t-x) 在这里做什么?然后我们可以尝试想出一种方法来做到这一点。您是否正在尝试制作 2D 直方图/PDF?或者您是否尝试使用 2D 高斯内核进行某种平滑处理?
  • @StevenThomas 感谢您的回复!我试图通过使用 2D 高斯核来估计“bwt”和“age”两列的联合密度以获得平滑的密度。我最终想获得特定年龄点和体重的估计密度值。
  • 根据您最初提出的问题,我仍然不确定您到底想要什么。比如你提到的数组t是什么? h=5的意义是什么?我认为您可能将高斯函数与正态分布混合在一起?我将在下面给出我认为你所追求的答案,以及我将如何做到这一点。如果不正确,请告诉我。
  • 我试图根据 d 维核密度估计公式 1/(nh^d)*sum^n_{i=1} K*((x-x_i )/h) 其中 x 在我的公式中是 t,x_i 是 x。这是在我的教科书上,但en.wikipedia.org/wiki/… 有一个类似的公式(相同的想法?),现在当我查看它时,t 也应该是 d 维的。抱歉,如果这令人困惑,我对这个主题还是很陌生,有点困惑!
  • 好的,这与我认为你想要的不同,我不确定我是否能够帮助你解决这个问题。也就是说,我仍然可以查看您的代码并告诉您什么不起作用。在k_2dgauss 的位中,您有np.sum(x**2, 1),但这不是正确的语法。让我们从这部分开始。你要这个做什么? x 应该在这里是什么类型的变量?它是一个数字/浮点数吗?或者它将是一个数组?如果是数组,一维还是二维?

标签: python function kernel-density probability-density


【解决方案1】:

根据我的 cmets 在您原来的帖子中,我认为这是您想要做的,但如果不是,请回到我这里,我们可以再试一次。

# info supplied by OP
import numpy as np
import pandas as pdbabies_full = \
pd.read_csv("https://www2.helsinki.fi/sites/default/files/atoms/files/babies2.txt", sep='\t')
#Getting the columns I need
babies_full1=babies_full[['gestation', 'age']]
x=np.array(babies_full1,'int')

# my contributions
from math import floor, ceil
def binMaker(arr, base):
    """function I already use for this sort of thing.
    arr is the arr I want to make bins for
    base is the bin separation, but does require you to import floor and ceil
    otherwise you can make these bins manually yourself"""
    binMin = floor(arr.min() / base) * base
    binMax = ceil(arr.max() / base) * base
    return np.arange(binMin, binMax + base, base)

bins1 = binMaker(x[:,0], 20.) # bins from 140. to 360. spaced 20 apart
bins2 = binMaker(x[:,1], 5.) # bins from 15. to 45. spaced 5. apart

counts = np.zeros((len(bins1)-1, len(bins2)-1)) # empty array for counts to go in
for i in range(0, len(bins1)-1): # loop over the intervals, hence the -1
    boo = (x[:,0] >= bins1[i]) * (x[:,0] < bins1[i+1])
    for j in range(0, len(bins2)-1): # loop over the intervals, hence the -1
        counts[i,j] = np.count_nonzero((x[boo,1] >= bins2[j]) * 
                                        (x[boo,1] < bins2[j+1]))
# if you want your PDF to be a fraction of the total
# rather than the number of counts, do the next line
counts /= x.shape[0]

# plotting
import matplotlib.pyplot as plt
from matplotlib.colors import BoundaryNorm

# setting the levels so that each number in counts has its own colour
levels = np.linspace(-0.5, counts.max()+0.5, int(counts.max())+2)
cmap = plt.get_cmap('viridis') # or any colormap you like
norm = BoundaryNorm(levels, ncolors=cmap.N, clip=True)

fig, ax = plt.subplots(1, 1, figsize=(6,5), dpi=150)
pcm = ax.pcolormesh(bins2, bins1, counts, ec='k', lw=1)
fig.colorbar(pcm, ax=ax, label='Counts (%)')
ax.set_xlabel('Age')
ax.set_ylabel('Gestation')
ax.set_xticks(bins2)
ax.set_yticks(bins1)
plt.title('Manually making a 2D (joint) PDF')

如果这是您想要的,那么np.histgoram2d 有一个更简单的方法,尽管我认为您指定它必须使用您自己的方法,而不是内置函数。为了完整起见,我还是把它包括在内。

pdf = np.histogram2d(x[:,0], x[:,1], bins=(bins1,bins2))[0]
pdf /= x.shape[0] # again for normalising and making a percentage

levels = np.linspace(-0.5, pdf.max()+0.5, int(pdf.max())+2)
cmap = plt.get_cmap('viridis') # or any colormap you like
norm = BoundaryNorm(levels, ncolors=cmap.N, clip=True)
fig, ax = plt.subplots(1, 1, figsize=(6,5), dpi=150)
pcm = ax.pcolormesh(bins2, bins1, pdf, ec='k', lw=1)
fig.colorbar(pcm, ax=ax, label='Counts (%)')
ax.set_xlabel('Age')
ax.set_ylabel('Gestation')
ax.set_xticks(bins2)
ax.set_yticks(bins1)
plt.title('using np.histogram2d to make a 2D (joint) PDF')

最后说明 - 在本例中,counts 不等于 pdf 的唯一位置是 40 <= 和&lt;,我有点不确定np.histogram2d 如何处理 bin 范围之外或 bin 边缘等的值。我们可以看到x的元素负责

>>> print(x[1011])
[280   45]

【讨论】:

    猜你喜欢
    • 2021-01-21
    • 1970-01-01
    • 2015-10-01
    • 1970-01-01
    • 2015-02-21
    • 2012-04-06
    • 2017-05-09
    • 2021-07-11
    相关资源
    最近更新 更多