Étant donné 2 tableaux de départs et d'arrêts, y a-t-il un moyen de générer des tableaux de nombres séquentiels dans numpy sans recourir à des boucles? Par exemple:
np.linspace(start, stop, num=3, axis=1)
array([[1. , 2.5, 4. ],
[3. , 4. , 5. ],
[5. , 6. , 7. ]])
linspace est le plus proche de ce que je veux mais je dois utiliser le même nombre d'étapes pour chaque série:
start = np.array([1, 3, 5]) stop = np.array([4, 5, 7]) # Expected result [ [1, 2, 3, 4], [3, 4, 5], [5, 6, 7] ]
3 Réponses :
Une compréhension de liste compte-t-elle comme étant "sans boucles"?
[list(range(a,b+1)) for (a,b) in zip(start, stop)]
range (a, b) doit être range (a, b + 1) à la place.
Le "résultat attendu" dans la question ressemble à une liste de listes, je pense
Merci pour la réponse Simon. Le résultat peut être une liste ou un ndarray. Je recherche des opérations vectorisées puisque je les ai en boucle.
Comme @hpaulj l'a indiqué dans les commentaires, vous ne pouvez pas avoir de tableau irrégulier, donc au moins le conteneur externe devra être une liste. Vous pouvez le faire sans boucles en utilisant OU Ce n'est pas exactement vectorisé, mais n'expose aucun mot-clé en boucle. Une compréhension de liste est susceptible d'être plus rapide que l'une ou l'autre approche. itertools.starmap code > et numpy.stack code> ou zip a >: result = list(starmap(np.arange, zip(start, stop + 1))
result = list(starmap(np.arange, np.stack(start, stop + 1, axis=-1))
La compréhension évidente des listes:
In [98]: np.linspace([1,3,5], [4,5,7], num=3, axis=1)
Out[98]:
array([[1. , 2.5, 4. ],
[3. , 4. , 5. ],
[5. , 6. , 7. ]])
In [99]: timeit np.linspace([1,3,5], [4,5,7], num=3, axis=1)
87.2 µs ± 260 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
Notez que je commence par les listes, car elles sont plus rapides.
frompyfunc est un bon outil pour faire des tableaux d'objets dtype:
In [97]: timeit [list(range(i,j)) for i,j in zip([1,3,5],[5,6,8])] 2.38 µs ± 44.7 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
mais c'est plus lent que la compréhension.
mais si nous générons des listes à la place, la compréhension est encore plus rapide: p >
In [94]: f = np.frompyfunc(np.arange, 2,1)
In [95]: f(np.array([1,3,5]), np.array([5,6,8]))
Out[95]:
array([array([1, 2, 3, 4]), array([3, 4, 5]), array([5, 6, 7])],
dtype=object)
In [96]: timeit f(np.array([1,3,5]), np.array([5,6,8]))
10.9 µs ± 36.8 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
Mais regardez cet linspace magique et vectorisé :
In [92]: [np.arange(i,j) for i,j in zip([1,3,5],[5,6,8])] Out[92]: [array([1, 2, 3, 4]), array([3, 4, 5]), array([5, 6, 7])] In [93]: timeit [np.arange(i,j) for i,j in zip([1,3,5],[5,6,8])] 4.46 µs ± 97.9 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
lent !!
Mais ceci est un petit exemple. Les classements peuvent changer avec des cas beaucoup plus volumineux. Dans tous les cas, ne supposez pas que «vectorisé» est toujours plus rapide. Il existe de nombreux cas où les opérations de liste Python sont plus rapides, en particulier lorsque les tailles sont modestes. Créer des tableaux numpy est un peu coûteux - même s'ils sont rapides une fois créés.
Étant donné que les résultats peuvent varier en longueur, vous devez effectuer une sorte d'itération de liste. L'approche
linspacefonctionne car les sous-listes sont de taille cohérente. Il peut générer une liste et mettre à l'échelle les autres. Avec des longueurs variables, il n'y a pas de raccourci de tableau.