Taking minimum value of each entry +- 10 rows either side in numpy array

ε祈祈猫儿з 提交于 2019-12-11 06:46:55

问题


I have a 3d numpy array and want to generate a secondary array consisting of the minimum of each value and the values in the 10 rows directly above and 10 rows directly below (i.e each entry is the minimum value from 21 values) for each 2d array.

I've been trying to use 'numpy.clip' to deal with the edges of the array - here the range of values which the minimum is taken from should simply reduce to 10 at the values on the top/bottom of the array. I think something like 'scipy.signal.argrelmin' seems to be what I'm after.

Here's my code so far, definitely not the best way to go about it:

import numpy as np

array_3d = np.random.random_integers(50, 80, (3, 50, 18))
minimums = np.zeros(array_3d.shape)

for array_2d_index in range(len(array_3d)):
    for row_index in range(len(array_3d[array_2d_index])):
        for col_index in range(len(array_3d[array_2d_index][row_index])):
            minimums[array_2d_index][row_index][col_index] = min(array_3d[array_2d_index][np.clip(row_index-10, 0, 49):np.clip(row_index+10, 0, 49)][col_index])

The main issue I think is that this is taking the minimum from the columns either side of each entry instead of the rows, which has been giving index errors.

Would appreciate any advice, thanks.


回答1:


Approach #1

Here's one approach with np.lib.stride_tricks.as_strided -

def strided_3D_axis1(array_3d, L):
    s0,s1,s2 = array_3d.strides
    strided = np.lib.stride_tricks.as_strided 
    m,n,r = array_3d.shape
    nL = n-L+1
    return strided(array_3d, (m,nL,L,r),(s0,s1,s1,s2))

out = strided_3D_axis1(array_3d, L=21).min(axis=-2)

Sample run -

1) Input :

In [179]: array_3d
Out[179]: 
array([[[73, 65, 51, 76, 59],
        [74, 57, 75, 53, 70],
        [60, 74, 52, 54, 60],
        [54, 52, 62, 75, 50],
        [68, 56, 68, 63, 77]],

       [[62, 70, 60, 79, 74],
        [70, 68, 50, 74, 57],
        [63, 57, 69, 65, 54],
        [63, 63, 68, 58, 60],
        [70, 66, 65, 78, 78]]])

2) Strided view :

In [180]: strided_3D_axis1(array_3d, L=3)
Out[180]: 
array([[[[73, 65, 51, 76, 59],
         [74, 57, 75, 53, 70],
         [60, 74, 52, 54, 60]],

        [[74, 57, 75, 53, 70],
         [60, 74, 52, 54, 60],
         [54, 52, 62, 75, 50]],

        [[60, 74, 52, 54, 60],
         [54, 52, 62, 75, 50],
         [68, 56, 68, 63, 77]]],


       [[[62, 70, 60, 79, 74],
         [70, 68, 50, 74, 57],
         [63, 57, 69, 65, 54]],

        [[70, 68, 50, 74, 57],
         [63, 57, 69, 65, 54],
         [63, 63, 68, 58, 60]],

        [[63, 57, 69, 65, 54],
         [63, 63, 68, 58, 60],
         [70, 66, 65, 78, 78]]]])

3) Strided view based min :

In [181]: strided_3D_axis1(array_3d, L=3).min(axis=-2)
Out[181]: 
array([[[60, 57, 51, 53, 59],
        [54, 52, 52, 53, 50],
        [54, 52, 52, 54, 50]],

       [[62, 57, 50, 65, 54],
        [63, 57, 50, 58, 54],
        [63, 57, 65, 58, 54]]])

Approach #2

Here's another with broadcasting upon creating all sliding indices along the second axis -

array_3d[:,np.arange(array_3d.shape[1]-L+1)[:,None] + range(L)].min(-2)

Approach #3

Here's another using Scipy's 1D minimum filter -

from scipy.ndimage.filters import minimum_filter1d as minf

L = 21
hL = (L-1)//2
out = minf(array_3d,L,axis=1)[:,hL:-hL]

Runtime test -

In [231]: array_3d = np.random.randint(50, 80, (3, 50, 18))

In [232]: %timeit strided_3D_axis1(array_3d, L=21).min(axis=-2)
10000 loops, best of 3: 54.2 µs per loop

In [233]: %timeit array_3d[:,np.arange(array_3d.shape[1]-L+1)[:,None] + range(L)].min(-2)
10000 loops, best of 3: 81.3 µs per loop

In [234]: L = 21
     ...: hL = (L-1)//2
     ...: 

In [235]: %timeit minf(array_3d,L,axis=1)[:,hL:-hL]
10000 loops, best of 3: 32 µs per loop


来源:https://stackoverflow.com/questions/45032403/taking-minimum-value-of-each-entry-10-rows-either-side-in-numpy-array

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!