Selección de ventanas aleatorias de filas de matrices numpy multidimensionales

Tengo una gran variedad donde cada fila es una serie de tiempo y, por lo tanto, necesita mantenerse en orden.

Quiero seleccionar una ventana aleatoria de un tamaño dado para cada fila.

Ejemplo:

>>>import numpy as np >>>arr = np.array(range(42)).reshape(6,7) >>>arr array([[ 0, 1, 2, 3, 4, 5, 6], [ 7, 8, 9, 10, 11, 12, 13], [14, 15, 16, 17, 18, 19, 20], [21, 22, 23, 24, 25, 26, 27], [28, 29, 30, 31, 32, 33, 34], [35, 36, 37, 38, 39, 40, 41]]) >>># What I want to do: >>>select_random_windows(arr, window_size=3) array([[ 1, 2, 3], [11, 12, 13], [14, 15, 16], [22, 23, 24], [38, 39, 40]]) 

Qué solución ideal me parecería a mí:

 def select_random_windows(arr, window_size): offsets = np.random.randint(0, arr.shape[0] - window_size, size = arr.shape[1]) return arr[:, offsets: offsets + window_size] 

Pero lamentablemente esto no funciona.

Lo que estoy pasando en este momento es terriblemente lento:

 def select_random_windows(arr, wndow_size): result = [] offsets = np.random.randint(0, arr.shape[0]-window_size, size = arr.shape[1]) for row, offset in enumerate(start_indices): result.append(arr[row][offset: offset + window_size]) return np.array(result) 

Claro, podría hacer lo mismo con una lista de comprensión (y obtener un aumento de velocidad mínimo), pero me preguntaba si hay alguna forma vectorizada de números súper inteligentes para hacer esto.

Aquí hay uno que aprovecha np.lib.stride_tricks.as_strided

 def random_windows_per_row_strided(arr, W=3): idx = np.random.randint(0,arr.shape[1]-W+1, arr.shape[0]) strided = np.lib.stride_tricks.as_strided m,n = arr.shape s0,s1 = arr.strides windows = strided(arr, shape=(m,n-W+1,W), strides=(s0,s1,s1)) return windows[np.arange(len(idx)), idx] 

Prueba de tiempo de ejecución en una matriz más grande con 10,000 filas –

 In [469]: arr = np.random.rand(100000,100) # @Psidom's soln In [470]: %timeit select_random_windows(arr, window_size=3) 100 loops, best of 3: 7.41 ms per loop In [471]: %timeit random_windows_per_row_strided(arr, W=3) 100 loops, best of 3: 6.84 ms per loop # @Psidom's soln In [472]: %timeit select_random_windows(arr, window_size=30) 10 loops, best of 3: 26.8 ms per loop In [473]: %timeit random_windows_per_row_strided(arr, W=30) 100 loops, best of 3: 9.65 ms per loop # @Psidom's soln In [474]: %timeit select_random_windows(arr, window_size=50) 10 loops, best of 3: 41.8 ms per loop In [475]: %timeit random_windows_per_row_strided(arr, W=50) 100 loops, best of 3: 10 ms per loop 

En la statement de retorno, cambie la división a la indexación avanzada , también necesita corregir un poco el código de muestreo:

 def select_random_windows(arr, window_size): offsets = np.random.randint(0, arr.shape[1]-window_size+1, size=arr.shape[0]) return arr[np.arange(arr.shape[0])[:,None], offsets[:,None] + np.arange(window_size)] select_random_windows(arr, 3) #array([[ 4, 5, 6], # [ 7, 8, 9], # [17, 18, 19], # [25, 26, 27], # [31, 32, 33], # [39, 40, 41]])