2 votes

Découper le tableau en sous-réseaux à recouvrement inversé

Comment découper efficacement un tableau en sous-ensembles qui se chevauchent, de manière à ce que pour

>>> N = 5
>>> L = 2  # could be any, less than N
>>> x = range(N)

le résultat attendu est

[[1,0],[2,1],[3,2],[4,3]]

Voici ce que j'ai essayé :

>>> [ x[i:i-L:-1] for i in range(L-1,len(x)) ]
[[], [3, 2], [4, 3], [5, 4]]  # wrong

>>> [ x[i:i-L:-1] for i in range(L,len(x)) ]
[[2, 1], [3, 2], [4, 3]]  # wrong

>>> [ x[i:i-L if i-L >= 0 else None:-1] for i in range(L-1,len(x)) ]
[[1, 0], [2, 1], [3, 2], [4, 3]]  # correct

Elle produit le résultat souhaité, mais est-ce la meilleure façon de l'obtenir ?

Existe-t-il des fonctions numpy, itertools qui pourraient vous aider ?

1voto

Roman Pekar Points 31863

Vous pouvez utiliser une simple liste de compréhension

>>> [[x[i+1], x[i]] for i in range(len(x) - 1)]
[[1, 0], [2, 1], [3, 2], [4, 3]]

Ou utiliser itertools.izip :

>>> from itertools import izip
>>> [list(k) for k in izip(x[1:], x)]
[[1, 0], [2, 1], [3, 2], [4, 3]]

Je vois que vous avez mis à jour la question, voici donc une version générique itertools avec l'utilisation de itertools.izip , itertools.islice y itertools.imap

>>> res = imap(lambda i:islice(reversed(x), i, i+L), xrange(N-L,-1,-1))
>>> [list(e) for e in res]
[[1, 0], [2, 1], [3, 2], [4, 3]]

Ou même des générateurs purs :

>>> res = (reversed(x[i:i+L]) for i in xrange(N-L+1))
>>> [list(e) for e in res]
[[1, 0], [2, 1], [3, 2], [4, 3]]

1voto

Divakar Points 20144

Je suppose que l'entrée est un tableau NumPy. Donc, si ce n'est pas déjà le cas, nous pourrions l'avoir sous forme de tableau avec np.asarray() . Nous commencerons donc par : x = np.asarray(input_list) si l'entrée est une liste. Sur cette base, essayons de résoudre le problème.

Voici une approche utilisant strides qui utilise le concept de views qui évite de faire des copies et doit donc être assez efficace -.

L = 2 # Row length
strided = np.lib.stride_tricks.as_strided
n = x.strides[0]
out = strided(x[L-1:],shape=(x.size-L+1,L),strides=(n,-n))

Échantillons -

In [85]: L = 2

In [86]: strided(x[L-1:],shape=(x.size-L+1,L),strides=(n,-n))
Out[86]: 
array([[1, 0],
       [2, 1],
       [3, 2],
       [4, 3]])

In [87]: L = 3

In [88]: strided(x[L-1:],shape=(x.size-L+1,L),strides=(n,-n))
Out[88]: 
array([[2, 1, 0],
       [3, 2, 1],
       [4, 3, 2]])

In [89]: L = 4

In [90]: strided(x[L-1:],shape=(x.size-L+1,L),strides=(n,-n))
Out[90]: 
array([[3, 2, 1, 0],
       [4, 3, 2, 1]])

Voici une autre approche utilisant broadcasting -

L = 2 # Row length
out = x[np.arange(x.size-L+1)[:,None] + np.arange(L-1,-1,-1)]

1voto

hpaulj Points 6132

Ou avec le zip normal (produisant une liste de tuples)

In [158]: x=list(range(5))
In [159]: x[1:],x[0:-1]
Out[159]: ([1, 2, 3, 4], [0, 1, 2, 3])
In [160]: list(zip(x[1:],x[0:-1]))
Out[160]: [(1, 0), (2, 1), (3, 2), (4, 3)]

ou pour les listes

In [161]: [list(i) for i in zip(x[1:],x[0:-1])]
Out[161]: [[1, 0], [2, 1], [3, 2], [4, 3]]

L'utilisation du zip est une sorte de transposition. numpy se transpose également facilement :

In [167]: arr=np.array((x[1:],x[:-1]))
In [168]: arr
Out[168]: 
array([[1, 2, 3, 4],
       [0, 1, 2, 3]])
In [169]: arr.T.tolist()
Out[169]: [[1, 0], [2, 1], [3, 2], [4, 3]]

Notez que j'ai dû faire deux copies de la liste. La liste de Divakar stride_tricks est le seul moyen de créer des "fenêtres" qui se chevauchent sans se copier. Il s'agit d'une méthode plus avancée.

Pour les petites listes, je suggère de s'en tenir à l'approche par liste. La création de tableaux entraîne des frais généraux.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X