Applying a function on local environments
![](https://secure.gravatar.com/avatar/763ea7d7604fbc70fdc9b2fe3f7e6204.jpg?s=120&d=mm&r=g)
Dear all, my goal would be to apply some function on a local environment of size K x K x K where K is bigger than 1 and odd. For example, if K = 3, it would be nice to apply some function "func" on such an environment around each n-dimensional position within the n-dimensional array. So, for K = 3 and the position (1,1,1) if a 3D array, one would collect the array values at the positions X = [(0,0,0),(0,0,1),(0,0,2),(0,1,0),...(2,2,2)] (K**3 = 27 in total in this example) and yield those values to "func". The result value at position (1,1,1) in the output array would be y = func(X). The same would apply for all entries excluding the padding area (or according to some padding policy). While I coded this many times on plain buffers in C++, I was wondering if there would be an *efficient* way to do this in numpy? Up to now I relied on the ndenumerate way of iterating n-dimensional arrays and aggregating the values using slices, but this turns out to be unbearably slow even for quite small arrays :-/ Is there a better "numpy-isque" way to do this? I thought of writing a custom view or subclassing, but the efficient aggregation of local environments using the ndenumerate and slice approach is slow, yet in C/C++ random access and native support for parallelism (by means of OpenMP) would drastically accelerate this. Or would it even be preferred to add this functionality to the library? I could imagine a special view, e.g., "LocalEnvironmentArrayView" or just a simple function with the intended usage something like the following: * a = ... # some n-dimensional numpy array * func = lambda env: np.mean(env) - np.std(env) * w = numpy.apply_on_local_environments(a, func, environment_size=3) So, each entry in the interior (or also the boundary, depending on the padding policy) of w would correspond to the evaluation of func on that local environment. Best regards, Thomas
![](https://secure.gravatar.com/avatar/2c3b851e50eb73dd7836e1c45c70e203.jpg?s=120&d=mm&r=g)
Dear Thomas, I think you might be able to do this with https://numpy.org/doc/stable/reference/generated/numpy.lib.stride_tricks.sli... Kind regards Klaus On Fri, Jul 26, 2024 at 2:51 PM <langthom@forwiss.uni-passau.de> wrote:
Dear all,
my goal would be to apply some function on a local environment of size K x K x K where K is bigger than 1 and odd. For example, if K = 3, it would be nice to apply some function "func" on such an environment around each n-dimensional position within the n-dimensional array. So, for K = 3 and the position (1,1,1) if a 3D array, one would collect the array values at the positions X = [(0,0,0),(0,0,1),(0,0,2),(0,1,0),...(2,2,2)] (K**3 = 27 in total in this example) and yield those values to "func". The result value at position (1,1,1) in the output array would be y = func(X). The same would apply for all entries excluding the padding area (or according to some padding policy).
While I coded this many times on plain buffers in C++, I was wondering if there would be an *efficient* way to do this in numpy? Up to now I relied on the ndenumerate way of iterating n-dimensional arrays and aggregating the values using slices, but this turns out to be unbearably slow even for quite small arrays :-/ Is there a better "numpy-isque" way to do this? I thought of writing a custom view or subclassing, but the efficient aggregation of local environments using the ndenumerate and slice approach is slow, yet in C/C++ random access and native support for parallelism (by means of OpenMP) would drastically accelerate this.
Or would it even be preferred to add this functionality to the library? I could imagine a special view, e.g., "LocalEnvironmentArrayView" or just a simple function with the intended usage something like the following:
* a = ... # some n-dimensional numpy array * func = lambda env: np.mean(env) - np.std(env) * w = numpy.apply_on_local_environments(a, func, environment_size=3)
So, each entry in the interior (or also the boundary, depending on the padding policy) of w would correspond to the evaluation of func on that local environment.
Best regards, Thomas _______________________________________________ NumPy-Discussion mailing list -- numpy-discussion@python.org To unsubscribe send an email to numpy-discussion-leave@python.org https://mail.python.org/mailman3/lists/numpy-discussion.python.org/ Member address: kzimmermann@quansight.com
![](https://secure.gravatar.com/avatar/8dc4d0010b050a4bae0b632defb5c4f3.jpg?s=120&d=mm&r=g)
Hello Thomas, It seems that what you are after is application of custom kernels. Similar existing things to look at: * For linear kernels, have a look at `np.correlate` function. * For custom kernels, see `numba` stencils. See: https://numba.pydata.org/numba-doc/latest/user/stencil.html One reason why it might not exist already is because performance of such thing would be poor. In C++ this makes perfect sense. However this way in `numpy` is fairly slow compared to tailored solutions for various problems that use np.correlate, np.convolve and similar. Also, it is not that hard to implement naive version of this. E.g. a quick implementation for 2d function. def correlate_func2d(a, func): """ Examples: >>> a = np.ones((4, 4)) >>> def func(a, i, j): ... sub = a[max(i-1, 0):i+2, max(j-1, 0):j+2] ... return sub.sum() >>> correlate_func2d(a, func) array([[4., 6., 6., 4.], [6., 9., 9., 6.], [6., 9., 9., 6.], [4., 6., 6., 4.]]) """ vfunc = np.vectorize(func, excluded={0}) n, m = a.shape return vfunc(a, np.arange(n)[:,None], np.arange(m)) Maybe something flexible that works for arbitrary number of dimensions could be useful. Although it wouldn’t be very performant, but very convenient (same spirit as np.vectorize). Subarray creation could be factored out of input function (for better convenience, but loss of flexibility). In this case it would be good if `mode` argument was modelled after `np.correlate`. Regards, DG
On 25 Jul 2024, at 19:13, langthom@forwiss.uni-passau.de wrote:
Dear all,
my goal would be to apply some function on a local environment of size K x K x K where K is bigger than 1 and odd. For example, if K = 3, it would be nice to apply some function "func" on such an environment around each n-dimensional position within the n-dimensional array. So, for K = 3 and the position (1,1,1) if a 3D array, one would collect the array values at the positions X = [(0,0,0),(0,0,1),(0,0,2),(0,1,0),...(2,2,2)] (K**3 = 27 in total in this example) and yield those values to "func". The result value at position (1,1,1) in the output array would be y = func(X). The same would apply for all entries excluding the padding area (or according to some padding policy).
While I coded this many times on plain buffers in C++, I was wondering if there would be an *efficient* way to do this in numpy? Up to now I relied on the ndenumerate way of iterating n-dimensional arrays and aggregating the values using slices, but this turns out to be unbearably slow even for quite small arrays :-/ Is there a better "numpy-isque" way to do this? I thought of writing a custom view or subclassing, but the efficient aggregation of local environments using the ndenumerate and slice approach is slow, yet in C/C++ random access and native support for parallelism (by means of OpenMP) would drastically accelerate this.
Or would it even be preferred to add this functionality to the library? I could imagine a special view, e.g., "LocalEnvironmentArrayView" or just a simple function with the intended usage something like the following:
* a = ... # some n-dimensional numpy array * func = lambda env: np.mean(env) - np.std(env) * w = numpy.apply_on_local_environments(a, func, environment_size=3)
So, each entry in the interior (or also the boundary, depending on the padding policy) of w would correspond to the evaluation of func on that local environment.
Best regards, Thomas _______________________________________________ NumPy-Discussion mailing list -- numpy-discussion@python.org To unsubscribe send an email to numpy-discussion-leave@python.org https://mail.python.org/mailman3/lists/numpy-discussion.python.org/ Member address: dom.grigonis@gmail.com
![](https://secure.gravatar.com/avatar/764323a14e554c97ab74177e0bce51d4.jpg?s=120&d=mm&r=g)
On Fri, Jul 26, 2024 at 8:50 AM <langthom@forwiss.uni-passau.de> wrote:
Dear all,
my goal would be to apply some function on a local environment of size K x K x K where K is bigger than 1 and odd. For example, if K = 3, it would be nice to apply some function "func" on such an environment around each n-dimensional position within the n-dimensional array. So, for K = 3 and the position (1,1,1) if a 3D array, one would collect the array values at the positions X = [(0,0,0),(0,0,1),(0,0,2),(0,1,0),...(2,2,2)] (K**3 = 27 in total in this example) and yield those values to "func". The result value at position (1,1,1) in the output array would be y = func(X). The same would apply for all entries excluding the padding area (or according to some padding policy).
scipy.ndimage.generic_filter() <https://docs.scipy.org/doc/scipy/reference/generated/scipy.ndimage.generic_f...> -- Robert Kern
![](https://secure.gravatar.com/avatar/008b55030cffb9a4c4f7d8422e10343e.jpg?s=120&d=mm&r=g)
On Sat, 27 Jul 2024, at 12:02 AM, Robert Kern wrote:
scipy.ndimage.generic_filter() <https://docs.scipy.org/doc/scipy/reference/generated/scipy.ndimage.generic_f...>
See also my post on accelerating generic filters with numba: https://ilovesymposia.com/2017/03/15/prettier-lowlevelcallables-with-numba-j...
![](https://secure.gravatar.com/avatar/763ea7d7604fbc70fdc9b2fe3f7e6204.jpg?s=120&d=mm&r=g)
Dear Dom, Robert, and Juan, thanks for your quick responses! I will take a look primarily at generic_filter and/or the numba accelerated version for a try! Best regards, Thomas
participants (5)
-
Dom Grigonis
-
Juan Nunez-Iglesias
-
Klaus Zimmermann
-
langthom@forwiss.uni-passau.de
-
Robert Kern