rolling_std rolling_mean rolling panda has attribute python numpy time-series sliding-window

rolling_mean - rolling window python



ventana deslizante en numpy (4)

La solucion es

np.lib.stride_tricks.as_strided(a, shape=(4,6), strides=(8,4)) .

El uso de zancadas es intuitivo cuando empiezas a pensar en términos de punteros / direcciones.

El método as_strided() tiene 3 argumentos.

  1. datos
  2. forma
  3. zancadas

Los datos son la matriz en la que operaríamos.

Para usar as_strided() para implementar funciones de ventana deslizante, debemos calcular la forma de la salida de antemano. En la pregunta, (4,6) es la forma de salida. Si las dimensiones no son correctas, terminamos leyendo valores de basura. Esto se debe a que estamos accediendo a los datos moviendo el puntero un par de bytes (según el tipo de datos).

Determinar el valor correcto de los avances es esencial para obtener los resultados esperados. Antes de calcular los pasos, averigüe la memoria ocupada por cada elemento. Podemos obtener esto usando arr.strides[-1] . En este ejemplo, la memoria ocupada por un elemento es de 4 bytes. Arreglos Numpy se crean en la fila de manera importante. Por lo tanto, el primer elemento de la siguiente fila está justo al lado del último elemento de la fila actual.

Ej: 0, 1 | 10, 11 | ...

10 está justo al lado de 1.

Imagine la matriz 2D remodelada a 1D (esto es aceptable ya que los datos se almacenan en un formato de fila mayor). El primer elemento de cada fila en la salida es el elemento indexado impar en la matriz 1D. 0, 10, 20, 30, ..

Por lo tanto, la cantidad de pasos en la memoria que debemos seguir para pasar de 0 a 10, de 10 a 20, por lo tanto, es 2 * tamaño de elemento mem . Entonces, cada fila tiene un paso de 2 * 4bytes = 8. Para una fila dada en la salida, todos los elementos son adyacentes entre sí en nuestra matriz 1D imaginaria. Entonces, para obtener el siguiente elemento en una fila, simplemente tome una zancada igual al tamaño de un elemento. Entonces, el paso de columna es de 4 bytes.

Por lo tanto, strides=(8,4)

Una explicación alternativa: La salida tiene una forma de (4,6). Paso de columna 4 . Por lo tanto, los elementos de la primera fila comienzan en el índice 0 y tienen 6 elementos, cada uno espaciado con 4 bytes de separación. Una vez recopilada la primera fila, la segunda fila comienza a 8 bytes del inicio de la fila actual. La tercera fila comienza a 8 bytes del punto de inicio de la segunda fila y así sucesivamente.

La forma determina el número de filas y columnas que necesitamos. las zancadas definen los pasos de memoria para iniciar una fila y recopilar un elemento de columna

Tengo una gran variedad de formas (6,2)

[[00,01], [10,11], [20,21], [30,31], [40,41], [50,51]]

Necesito una ventana deslizante con tamaño de paso 1 y tamaño de ventana 3 como esto:

[[00,01,10,11,20,21], [10,11,20,21,30,31], [20,21,30,31,40,41], [30,31,40,41,50,51]]

Estoy buscando una solución numpy. Si su solución pudiera parametrizar la forma de la matriz original, así como el tamaño de la ventana y el tamaño de los pasos, sería genial.

Encontré esta respuesta relacionada con el uso de zancadas para un filtro de promedio móvil eficiente, pero no veo cómo especificar el tamaño de los pasos allí y cómo colapsar la ventana de la matriz 3d a una matriz 2D continua. También este iterador de ventana deslizante o deslizante en Python, pero está en Python y no estoy seguro de cuán eficiente sea. Además, admite elementos pero no los une al final si cada elemento tiene varias características.


Una comprensión de la lista corta es posible con more_itertools.windowed 1 :

Dado

import numpy as np import more_itertools as mit a = [["00","01"], ["10","11"], ["20","21"], ["30","31"], ["40","41"], ["50","51"]] b = np.array(a)

Código

np.array([list(mit.flatten(w)) for w in mit.windowed(a, n=3)])

o

np.array([[i for item in w for i in item] for w in mit.windowed(a, n=3)])

o

np.array(list(mit.windowed(b.ravel(), n=6)))

Salida

array([[''00'', ''01'', ''10'', ''11'', ''20'', ''21''], [''10'', ''11'', ''20'', ''21'', ''30'', ''31''], [''20'', ''21'', ''30'', ''31'', ''40'', ''41''], [''30'', ''31'', ''40'', ''41'', ''50'', ''51'']], dtype=''<U2'')

Las ventanas deslizantes de tamaño n=3 se crean y se aplanan. Tenga en cuenta que el tamaño de paso predeterminado es more_itertools.windowed(..., step=1) .

Actuación

Como una matriz, la respuesta aceptada es la más rápida.

%timeit np.hstack((a[:-2], a[1:-1], a[2:])) # 37.5 µs ± 1.88 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each) %timeit np.hstack((b[:-2], b[1:-1], b[2:])) # 12.9 µs ± 166 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each) %timeit np.array([list(mit.flatten(w)) for w in mit.windowed(a, n=3)]) # 23.2 µs ± 1.73 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each) %timeit np.array([[i for item in w for i in item] for w in mit.windowed(a, n=3)]) # 21.2 µs ± 999 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each) %timeit np.array(list(mit.windowed(b.ravel(), n=6))) # 43.4 µs ± 374 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

Una biblioteca de terceros que implementa recetas de itertool y muchas herramientas útiles.


Puede hacer una ventana deslizante vectorizada en números usando una indexación elegante.

>>> import numpy as np >>> a = np.array([[00,01], [10,11], [20,21], [30,31], [40,41], [50,51]]) >>> a array([[ 0, 1], [10, 11], [20, 21], #define our 2d numpy array [30, 31], [40, 41], [50, 51]]) >>> a = a.flatten() >>> a array([ 0, 1, 10, 11, 20, 21, 30, 31, 40, 41, 50, 51]) #flattened numpy array >>> indexer = np.arange(6)[None, :] + 2*np.arange(4)[:, None] >>> indexer array([[ 0, 1, 2, 3, 4, 5], [ 2, 3, 4, 5, 6, 7], #sliding window indices [ 4, 5, 6, 7, 8, 9], [ 6, 7, 8, 9, 10, 11]]) >>> a[indexer] array([[ 0, 1, 10, 11, 20, 21], [10, 11, 20, 21, 30, 31], #values of a over sliding window [20, 21, 30, 31, 40, 41], [30, 31, 40, 41, 50, 51]]) >>> np.sum(a[indexer], axis=1) array([ 63, 123, 183, 243]) #sum of values in ''a'' under the sliding window.

Explicación de lo que hace este código.

El np.arange(6)[None, :] crea un vector de fila del 0 al 6, y np.arange(4)[:, None] crea un vector de columna del 0 al 4. Esto da como resultado una matriz de 4x6 donde cada fila ( seis de ellos) representa una ventana, y el número de filas (cuatro de ellas) representa el número de ventanas. El múltiplo de 2 hace que la ventana deslizante se deslice 2 unidades a la vez, lo que es necesario para deslizarse sobre cada tupla. Con el uso de la división de matriz numpy puede pasar la ventana deslizante a la matriz numpy aplanada y hacer agregados en ellos como suma.


In [1]: import numpy as np In [2]: a = np.array([[00,01], [10,11], [20,21], [30,31], [40,41], [50,51]]) In [3]: w = np.hstack((a[:-2],a[1:-1],a[2:])) In [4]: w Out[4]: array([[ 0, 1, 10, 11, 20, 21], [10, 11, 20, 21, 30, 31], [20, 21, 30, 31, 40, 41], [30, 31, 40, 41, 50, 51]])

Podrías escribir esto como una función como tal:

def window_stack(a, stepsize=1, width=3): n = a.shape[0] return np.hstack( a[i:1+n+i-width:stepsize] for i in range(0,width) )

Esto realmente no depende de la forma de la matriz original, siempre y cuando a.ndim = 2 . Tenga en cuenta que nunca uso ninguna longitud en la versión interactiva. La segunda dimensión de la forma es irrelevante; Cada fila puede ser tan larga como quieras. Gracias a la sugerencia de @ Jaime, puedes hacerlo sin verificar la forma en absoluto:

def window_stack(a, stepsize=1, width=3): return np.hstack( a[i:1+i-width or None:stepsize] for i in range(0,width) )