numpy 在Python中计算网格单元内平均值的最有效方法是什么?

xjreopfe  于 2023-06-23  发布在  Python
关注(0)|答案(2)|浏览(112)

我有一个2d数据点数组(X)和相应的观测值(z),并希望计算每个单元的z平均值的网格。
在Numpy中使用嵌套的for循环效率很低。有没有更快的方法使用内置函数或列表理解?如果可能的话,我想避免使用Numba/JIT。

import numpy

x = numpy.random.rand(1000000)
y = numpy.random.rand(1000000)
z = numpy.random.rand(1000000)

nx = 1000
ny = 1000
xl = numpy.linspace(0,1,nx+1)
yl = numpy.linspace(0,1,ny+1)
zm = numpy.full((nx,ny),numpy.nan)
for i in range(nx):
    for j in range(ny):
        zm[i,j] = numpy.mean(z, where = ((x>xl[i]) & (x<=xl[i+1]) & (y>yl[j]) & (y<=yl[j+1]))) #4.5 ms/loop = 75 minutes

或者,2D变体:

import numpy

X = numpy.array([numpy.random.rand(1000000),numpy.random.rand(1000000)]).T
z = numpy.random.rand(1000000)

nx = 1000
ny = 1000
xl = numpy.linspace(0,1,nx+1)
yl = numpy.linspace(0,1,ny+1)
zm = numpy.full((nx,ny),numpy.nan)
for i in range(nx):
    print(i)
    for j in range(ny):
        zm[i,j] = numpy.mean(z, where = ((X[:,0]>xl[i]) & (X[:,0]<=xl[i+1]) & (X[:,1]>yl[j]) & (X[:,1]<=yl[j+1]))) #4.5 ms/loop = 75 minutes
uqcuzwp8

uqcuzwp81#

pandas中,您可以用途:

import pandas as pd

df = pd.DataFrame({'x': pd.cut(x, xl, labels=range(nx)),
                   'y': pd.cut(y, yl, labels=range(ny)),
                   'z': z})

out = (df.groupby(['x', 'y'])['z'].mean().unstack()
         .reindex(index=range(nx), columns=range(ny))
         .to_numpy()
      )

运行时间:

3.95 s ± 1.83 s per loop (mean ± std. dev. of 7 runs, 1 loop each)
jtw3ybtb

jtw3ybtb2#

你正在构建的实际上是一种直方图。因此,您可以使用提供的numpy函数,如下所示:

import warnings
import numpy as np

x, y, z = np.random.rand(3, 1000000)
nx = ny = 1000

zsum, _, _ = np.histogram2d(x,y, bins=(nx, ny), range=((0,1), (0,1)), weights=z)
zcount, _, _ = np.histogram2d(x, y, bins=(nx, ny), range=((0,1), (0,1)))
with warnings.catch_warnings():
    warnings.simplefilter("ignore", category=RuntimeWarning)
    out = zsum/zcount

print(out)

在这里,我抑制了运行时警告,抱怨除以零,在我们的例子中,这是为了获得NaN值。此外,我忽略了histogram2d函数作为第二个和第三个参数返回的x和y边,并将其分配给丢弃名称_。我创建了一个带有权重的直方图来对值求和,另一个带有计数的直方图通过比率获得平均值。
效率:
请注意,您应该详细说明它的含义,因为您可以优化算法的执行时间,但也可以优化内存消耗,能源消耗等。从注解4.5 ms/loop = 75 minutes中可以清楚地看出,您正在谈论执行时间。
在我的笔记本电脑上,使用@mozway的pandas的答案是:1.1 s ± 147 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
这个使用numpy.histogram2d的答案需要508 ms ± 56.1 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

相关问题