【发布时间】:2018-02-18 05:40:07
【问题描述】:
我应该将哪些声明与逻辑函数/索引操作结合起来,以便 Cython 完成繁重的工作?
我有两个大小相等的 numpy 数组形式的大型栅格。第一个数组包含植被指数值,第二个数组包含字段 ID。目标是按字段平均植被指数值。这两个数组都有我想忽略的讨厌的 nodata 值(-9999)。
目前该函数的执行时间超过 60 秒,通常我不会太介意,但我可能会处理数百张图像。即使是 30 秒的改进也会很重要。所以我一直在探索 Cython 来帮助加快速度。我一直使用Cython numpy tutorial 作为指导。
test_cy.pyx 代码:
import numpy as np
cimport numpy as np
cimport cython
@cython.boundscheck(False) # turn off bounds-checking for entire function
@cython.wraparound(False) # turn off negative index wrapping for entire function
cpdef test():
cdef np.ndarray[np.int16_t, ndim=2] ndvi_array = np.load("Z:cython_test/data/ndvi.npy")
cdef np.ndarray[np.int16_t, ndim=2] field_array = np.load("Z:cython_test/data/field_array.npy")
cdef np.ndarray[np.int16_t, ndim=1] unique_field = np.unique(field_array)
unique_field = unique_field[unique_field != -9999]
cdef int field_id
cdef np.ndarray[np.int16_t, ndim=1] f_ndvi_values
cdef double f_avg
for field_id in unique_field :
f_ndvi_values = ndvi_array[np.logical_and(field_array == field_id, ndvi_array != -9999)]
f_avg = np.mean(f_ndvi_values)
Setup.py 代码:
try:
from setuptools import setup
from setuptools import Extension
except ImportError:
from distutils.core import setup
from distutils.extension import Extension
from Cython.Build import cythonize
import numpy
setup(ext_modules = cythonize('test_cy.pyx'),
include_dirs=[numpy.get_include()])
经过一番研究和运行:
cython -a test_cy.pyx
看来索引操作ndvi_array[np.logical_and(field_array == field_id, ndvi_array != -9999)]是瓶颈,还在依赖Python。我怀疑我在这里遗漏了一些重要的声明。包括ndim 没有任何效果。
我对 numpy 也很陌生,所以我可能遗漏了一些明显的东西。
【问题讨论】:
-
正如它在docs 中所说的那样,“陷阱:这种高效的索引只影响某些索引操作,即那些具有恰好 ndim 数量的类型整数索引的操作。因此,例如,如果没有键入 v,那么查找 f[v, w] 未优化。另一方面,这意味着您可以继续使用 Python 对象进行复杂的动态切片等,就像未键入数组时一样。"
-
最简单的改进是缓存
ndvi_array != -9999(因为它不会改变)。除此之外,您可能必须将逻辑索引和均值计算重写为 2D 循环,但这需要更多工作。 -
@Paul 因此,如果我理解正确,我需要将
ndvi_array != -9999存储为变量并键入它,以及field_array = field_id? -
@wessport 我想这将是一种接近它的方式。或者你可以循环并在里面放一个'if'语句。
标签: python numpy optimization cython