如何在numpy中创建一个n维网格来评估任意n的函数?

Mar*_*ham 3 python arrays numpy numerical-integration

我正在尝试创建一个简单的数值积分函数来说明蒙特卡罗积分在高维度中的好处.我想要这样的东西:

def quad_int(f, mins, maxs, numPoints=100):
    '''
    Use the naive (Riemann sum) method to numerically integrate f on a box 
    defined by the mins and maxs.

    INPUTS:
    f         - A function handle. Should accept a 1-D NumPy array 
        as input.
    mins      - A 1-D NumPy array of the minimum bounds on integration.
    maxs      - A 1-D NumPy array of the maximum bounds on integration.
    numPoints - An integer specifying the number of points to sample in 
        the Riemann-sum method. Defaults to 100.
    '''
    n = len(mins)

    # Create a grid of evenly spaced points to evaluate f on
    # Evaluate f at each point in the grid; sum all these values up
    dV = np.prod((maxs-mins/numPoints))
    # Multiply the sum by dV to get the approximate integral
Run Code Online (Sandbox Code Playgroud)

我知道我dV会导致数值稳定性问题,但是现在我遇到的问题是创建域名.如果维度的数量是固定的,那么就可以这么简单地使用np.meshgrid:

# We don't want the last value since we are using left-hand Riemann sums
x = np.linspace(mins[0],maxs[0],numPoints)[:-1]
y = np.linspace(mins[1],maxs[1],numPoints)[:-1]
z = np.linspace(mins[2],maxs[2],numPoints)[:-1]

X, Y, Z = np.meshgrid(x,y,z)
tot = 0
for index, x in np.ndenumerate(X):
    tot += f(x, Y[index], Z[index])
Run Code Online (Sandbox Code Playgroud)

是否有类似的np.meshgrid可以为任意维度做到这一点,也许接受一个数组的元组?或者还有其他方法可以在更高的维度上完成黎曼总和吗?我已经考虑过以递归方式进行,但无法弄清楚它是如何工作的.

hpa*_*ulj 8

您可以使用列表推导来生成所有linspaces,然后将该列表传递给meshgrida *(将列表转换为参数元组).

XXX = np.meshgrid(*[np.linspace(i,j,numPoints)[:-1] for i,j in zip(mins,maxs)])
Run Code Online (Sandbox Code Playgroud)

XXX现在是一个n数组列表(每个n维度).

我正在使用直接的Python列表和参数操作.

np.lib.index_tricks具有其他可能有用的索引和网格生成函数和类.值得一读,看看事情是如何完成的.


在索引未知维度的数组时,在各种numpy函数中使用的巧妙技巧是构造为所需索引的列表.它可以包括slice(None)你通常看到的地方:.然后将其转换为元组并使用它.

In [606]: index=[2,3]
In [607]: [slice(None)]+index
Out[607]: [slice(None, None, None), 2, 3]
In [609]: Y[tuple([slice(None)]+index)]
Out[609]: array([ 0. ,  0.5,  1. ,  1.5])
In [611]: Y[:,2,3]
Out[611]: array([ 0. ,  0.5,  1. ,  1.5])
Run Code Online (Sandbox Code Playgroud)

他们使用一个列表,他们需要更改元素.并不总是需要转换为元组

index=[slice(None)]*3
index[1]=0
Y[index] # same as Y[:,0,:]
Run Code Online (Sandbox Code Playgroud)