arrays numpy convolution

arrays - Uso de la función numpy `as_strided` para crear parches, mosaicos, ventanas corredizas o deslizantes de dimensión arbitraria



convolution (1)

Pasé un tiempo esta mañana buscando una pregunta generalizada a la que apuntar duplicados para preguntas sobre as_strided y / o cómo hacer funciones de ventana generalizadas . Parece que hay muchas questions sobre cómo (de forma segura) crear parches, ventanas deslizantes, ventanas enrollables, mosaicos o vistas en una matriz para aprendizaje automático, convolución, procesamiento de imágenes y / o integración numérica.

Estoy buscando una función generalizada que pueda aceptar un parámetro de window , step y axis y devolver una vista as_strided para dimensiones arbitrarias. np.squeeze() mi respuesta a continuación, pero estoy interesado si alguien puede hacer un método más eficiente, ya que no estoy seguro de que usar np.squeeze() sea ​​el mejor método, no estoy seguro de que mis declaraciones de afirmación hagan que la función sea segura suficiente para escribir en la vista resultante, y no estoy seguro de cómo manejar el caso de borde del axis no está en orden ascendente.

DEBIDA DILIGENCIA

La función más generalizada que puedo encontrar es sklearn.feature_extraction.image.extract_patches escrita por @eickenberg (así como el aparentemente equivalente skimage.util.view_as_windows ), pero no están bien documentados en la red y no pueden hacer ventanas menos ejes de los que hay en la matriz original (por ejemplo, esta pregunta solicita una ventana de cierto tamaño sobre un solo eje). También, a menudo, las preguntas quieren una respuesta única.

@Divakar creó una función numpy generalizada para las entradas 1-d here , pero las entradas de mayor dimensión requieren un poco más de cuidado. He creado una ventana 2D básica sobre el método de entrada 3D , pero no es muy extensible.


Aquí está la receta que tengo hasta ahora:

def window_nd(a, window, steps = None, axis = None, outlist = False): """ Create a windowed view over `n`-dimensional input that uses an `m`-dimensional window, with `m <= n` Parameters ------------- a : Array-like The array to create the view on window : tuple or int If int, the size of the window in `axis`, or in all dimensions if `axis == None` If tuple, the shape of the desired window. `window.size` must be: equal to `len(axis)` if `axis != None`, else equal to `len(a.shape)`, or 1 steps : tuple, int or None The offset between consecutive windows in desired dimension If None, offset is one in all dimensions If int, the offset for all windows over `axis` If tuple, the steps along each `axis`. `len(steps)` must me equal to `len(axis)` axis : tuple, int or None The axes over which to apply the window If None, apply over all dimensions if tuple or int, the dimensions over which to apply the window outlist : boolean If output should be as list of windows. If False, it will be an array with `a.nidim + 1 <= a_view.ndim <= a.ndim *2`. If True, output is a list of arrays with `a_view[0].ndim = a.ndim` Warning: this is a memory-intensive copy and not a view Returns ------- a_view : ndarray A windowed view on the input array `a`, or copied list of windows """ ashp = np.array(a.shape) if axis != None: axs = np.array(axis, ndmin = 1) assert np.all(np.in1d(axs, np.arange(ashp.size))), "Axes out of range" else: axs = np.arange(ashp.size) window = np.array(window, ndmin = 1) assert (window.size == axs.size) | (window.size == 1), "Window dims and axes don''t match" wshp = ashp.copy() wshp[axs] = window assert np.all(wshp <= ashp), "Window is bigger than input array in axes" stp = np.ones_like(ashp) if steps: steps = np.array(steps, ndmin = 1) assert np.all(steps > 0), "Only positive steps allowed" assert (steps.size == axs.size) | (steps.size == 1), "Steps and axes don''t match" stp[axs] = steps astr = np.array(a.strides) shape = tuple((ashp - wshp) // stp + 1) + tuple(wshp) strides = tuple(astr * stp) + tuple(astr) as_strided = np.lib.stride_tricks.as_strided a_view = np.squeeze(as_strided(a, shape = shape, strides = strides)) if outlist: return list(a_view.reshape((-1,) + tuple(wshp))) else: return a_view

Algunos casos de prueba:

a = np.arange(1000).reshape(10,10,10) window_nd(a, 4).shape # sliding (4x4x4) window Out: (7, 7, 7, 4, 4, 4) window_nd(a, 2, 2).shape # (2x2x2) blocks Out: (5, 5, 5, 2, 2, 2) window_nd(a, 2, 1, 0).shape # sliding window of width 2 over axis 0 Out: (9, 2, 10, 10) window_nd(a, 2, 2, (0,1)).shape # tiled (2x2) windows over first and second axes Out: (5, 5, 2, 2, 10) window_nd(a,(4,3,2)).shape # arbitrary sliding window Out: (7, 8, 9, 4, 3, 2) window_nd(a,(4,3,2),(1,5,2),(0,2,1)).shape #arbitrary windows, steps and axis Out: (7, 5, 2, 4, 2, 3) # note shape[-3:] != window as axes are out of order