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, langt...@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-le...@python.org > https://mail.python.org/mailman3/lists/numpy-discussion.python.org/ > Member address: dom.grigo...@gmail.com
_______________________________________________ NumPy-Discussion mailing list -- numpy-discussion@python.org To unsubscribe send an email to numpy-discussion-le...@python.org https://mail.python.org/mailman3/lists/numpy-discussion.python.org/ Member address: arch...@mail-archive.com