python - 如何优化一个 numpy 循环,该循环对一个数组中的值求和,该数组由另一个数组索引,其中值等于循环索引

标签 python performance numpy for-loop

我有这段代码在应用程序运行期间被多次调用。 它采用代表值的数字数组 (value_array)。 这些应该在 zone_array 中定义的区域中汇总。 zone_ids 表示 zone_array 中所有可能区域的列表。

它基本上是这样的:我有一张人口栅格 map ,我想知道有多少人生活在区域 map 的每个区域。

代码:

values = np.zeros(len(zone_ids))
for i in zone_ids:
    values[i] = round(np.nansum(value_array[zone_array == i]), 2)
return values

罪魁祸首似乎是 for 循环,但我还没有找到消除它并得到相同结果的方法。

我用 bincount 尝试过,但没有成功。 使用 numba jit 也没有效果。

我想远离 cython,因为此代码将在不支持 cython 的 Qgis 插件中使用。

测试代码:

import numpy as np


def fill_values(zone_array, value_array, zone_ids):
    values = np.zeros(len(zone_ids))
    for i in zone_ids:
        values[i] = round(np.nansum(value_array[zone_array == i]), 2)
    return values


def run():
    # 300 different zones
    zone_ids = range(300)
    # zone map with 300 zones
    zone_array = (np.random.rand(2000, 2000) * 300).astype(int)
    # value map from which we want the sum of values per zone (real map can have NaN values)
    value_array = (np.random.rand(2000, 2000) * 10.)
    value_array[5, 5] = np.NAN
    fill_values(zone_array, value_array, zone_ids)


if __name__ == '__main__':
    run()

每个循环 1.92 秒 ± 17.5 毫秒(7 次运行的平均值 ± 标准偏差,每次 1 个循环)

按照 Divakar 的建议实现 bincount :

每个循环 203 毫秒 ± 15.2 毫秒(7 次运行的平均值 ± 标准偏差,每次 1 个循环)

最佳答案

如果直接使用 bincount,您将在求和中得到 NaN。因此,您可以简单地将 NaNs 替换为 zeros 并使用 bincount。作为矢量化解决方案,这应该快得多。

因此,实现将是 -

val_nonan = np.where(np.isnan(value_array), 0, value_array)
out = np.round(np.bincount(zone_array.ravel(), val_nonan.ravel()),2)

关于python - 如何优化一个 numpy 循环,该循环对一个数组中的值求和,该数组由另一个数组索引,其中值等于循环索引,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46810714/

相关文章:

javascript - 只更新可见的 DOM 元素?

python - 正确使用 numpy searchsorted 例程

python - 沿第三轴的点积

python - 如何将python+pygame程序打包为可执行文件?

LIKE 的 MySQL 性能(无通配符)与 =

javascript - node.js 与客户端 Javascript(与 Chrome/V8 相比)相比是否具有任何性能优势?

python - numpy:通过广播摆脱 for 循环

python - 来自 ManyToMany 关系的查询集

python - 在同一个 Flask View 中处理 GET 和 POST

python - Flask-HTTPAuth 用户访问级别