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]])