web-dev-qa-db-fra.com

Prendre des sous-tableaux du tableau numpy avec une foulée / taille d'étape donnée

Disons que j'ai un Python Numpy array a.

a = numpy.array([1,2,3,4,5,6,7,8,9,10,11])

Je veux créer une matrice de sous-séquences à partir de ce tableau de longueur 5 avec la foulée 3. La matrice des résultats se présentera donc comme suit:

numpy.array([[1,2,3,4,5],[4,5,6,7,8],[7,8,9,10,11]])

Une façon possible d'implémenter cela serait d'utiliser une boucle for.

result_matrix = np.zeros((3, 5))
for i in range(0, len(a), 3):
  result_matrix[i] = a[i:i+5]

Existe-t-il un moyen plus propre de mettre cela en œuvre dans Numpy?

27
Stackd

Approche n ° 1: Utilisation de broadcasting -

def broadcasting_app(a, L, S ):  # Window len = L, Stride len/stepsize = S
    nrows = ((a.size-L)//S)+1
    return a[S*np.arange(nrows)[:,None] + np.arange(L)]

Approche n ° 2: Utilisation plus efficace NumPy strides -

def strided_app(a, L, S ):  # Window len = L, Stride len/stepsize = S
    nrows = ((a.size-L)//S)+1
    n = a.strides[0]
    return np.lib.stride_tricks.as_strided(a, shape=(nrows,L), strides=(S*n,n))

Exemple d'exécution -

In [143]: a
Out[143]: array([ 1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11])

In [144]: broadcasting_app(a, L = 5, S = 3)
Out[144]: 
array([[ 1,  2,  3,  4,  5],
       [ 4,  5,  6,  7,  8],
       [ 7,  8,  9, 10, 11]])

In [145]: strided_app(a, L = 5, S = 3)
Out[145]: 
array([[ 1,  2,  3,  4,  5],
       [ 4,  5,  6,  7,  8],
       [ 7,  8,  9, 10, 11]])
35
Divakar

Version modifiée du code de @ Divakar avec vérification pour s'assurer que la mémoire est contiguë et que le tableau retourné ne peut pas être modifié. (Les noms de variables ont changé pour mon application DSP).

def frame(a, framelen, frameadv):
"""frame - Frame a 1D array
a - 1D array
framelen - Samples per frame
frameadv - Samples between starts of consecutive frames
   Set to framelen for non-overlaping consecutive frames

Modified from Divakar's 10/17/16 11:20 solution:
https://stackoverflow.com/questions/40084931/taking-subarrays-from-numpy-array-with-given-stride-stepsize

CAVEATS:
Assumes array is contiguous
Output is not writable as there are multiple views on the same memory

"""

if not isinstance(a, np.ndarray) or \
   not (a.flags['C_CONTIGUOUS'] or a.flags['F_CONTIGUOUS']):
    raise ValueError("Input array a must be a contiguous numpy array")

# Output
nrows = ((a.size-framelen)//frameadv)+1
oshape = (nrows, framelen)

# Size of each element in a
n = a.strides[0]

# Indexing in the new object will advance by frameadv * element size
ostrides = (frameadv*n, n)
return np.lib.stride_tricks.as_strided(a, shape=oshape,
                                       strides=ostrides, writeable=False)
0
Marie R