python arrays numpy multidimensional-array slice

python - Selección de ventanas aleatorias de filas de matrices Numpy multidimensionales



arrays multidimensional-array (2)

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

Quiero seleccionar una ventana aleatoria de un tamaño determinado 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]])

Cómo sería una solución ideal para 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 desafortunadamente esto no funciona.

Con lo que voy ahora 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 comprensión de la lista (y obtener un aumento de velocidad mínimo), pero me preguntaba si hay alguna forma vectorizada súper inteligente y numpy 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 declaración de devolución, cambie el corte a indexación avanzada , también debe 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]])