Initialisation du tableau NumPy (remplir avec des valeurs identiques)

238

J'ai besoin de créer un tableau NumPy de longueur n, dont chaque élément est v.

Y a-t-il quelque chose de mieux que:

a = empty(n)
for i in range(n):
    a[i] = v

Je sais zeroset onesfonctionnerais pour v = 0, 1. Je pourrais utiliser v * ones(n), mais cela ne fonctionnera pas quand il vest None, et serait également beaucoup plus lent.

max
la source
1
Sur mon ordinateur, pour le cas 0, l'utilisation a = np.zeros(n)dans la boucle est plus rapide que a.fill(0). Ceci est contraire à ce que j'attendais car je pensais a=np.zeros(n)qu'il faudrait allouer et initialiser une nouvelle mémoire. Si quelqu'un peut expliquer cela, je l'apprécierais.
user3731622
Vous ne pouvez pas mettre None dans un tableau numpy, car les cellules sont créées avec un type de données spécifique tandis que None a son propre type et est en fait un pointeur.
Camion
@Camion Ouais, je sais maintenant :) Bien sûr, v * ones(n)c'est toujours horrible, car il utilise la multiplication coûteuse. Remplacez-le *par +cependant et v + zeros(n)s'avère étonnamment bon dans certains cas ( stackoverflow.com/questions/5891410/… ).
max
max, au lieu de créer un tableau avec des zéros avant d'ajouter v, il est encore plus rapide de le créer vide avec var = np.empty(n)puis de le remplir avec 'var [:] = v'. (btw, np.full()c'est aussi rapide que ça)
Camion

Réponses:

309

NumPy 1.8 introduit np.full(), qui est une méthode plus directe que celle empty()suivie fill()pour créer un tableau rempli d'une certaine valeur:

>>> np.full((3, 5), 7)
array([[ 7.,  7.,  7.,  7.,  7.],
       [ 7.,  7.,  7.,  7.,  7.],
       [ 7.,  7.,  7.,  7.,  7.]])

>>> np.full((3, 5), 7, dtype=int)
array([[7, 7, 7, 7, 7],
       [7, 7, 7, 7, 7],
       [7, 7, 7, 7, 7]])

C'est sans doute la façon de créer un tableau rempli de certaines valeurs, car il décrit explicitement ce qui est réalisé (et il peut en principe être très efficace car il effectue une tâche très spécifique).

Eric O Lebigot
la source
1
Cette méthode full () fonctionne bien pour moi mais je ne trouve pas un peu de documentation pour cela. Quelqu'un peut-il me diriger vers le bon endroit?
James Adams
1
Vous pouvez au moins le faire help(numpy.full)dans un shell Python. Je suis également surpris qu'il ne figure pas dans la documentation Web.
Eric O Lebigot
Sur mon système (Python 2.7, Numpy 1.8), np.full () est en fait légèrement plus lent que np.empty () suivi de np.fill ().
John Zwinck
1
Pour 10 000 éléments, j'observe la même chose (sauf qu'elle np.fill()n'existe pas et devrait l'être arr.fill()), avec une différence d'environ 10%. Si la différence était plus grande, je soulèverais un problème dans le traqueur de bogues NumPy. :) Je préfère un code plus explicite et plus clair, pour une si petite différence de temps d'exécution, donc j'y vais np.full()tout le temps.
Eric O Lebigot
Sur ma machine, np.full () a la même vitesse que np.array.fill ()
Fnord
92

Mise à jour pour Numpy 1.7.0: (Pointe du chapeau à @Rolf Bartstra.)

a=np.empty(n); a.fill(5) est le plus rapide.

Par ordre de vitesse décroissante:

%timeit a=np.empty(1e4); a.fill(5)
100000 loops, best of 3: 5.85 us per loop

%timeit a=np.empty(1e4); a[:]=5 
100000 loops, best of 3: 7.15 us per loop

%timeit a=np.ones(1e4)*5
10000 loops, best of 3: 22.9 us per loop

%timeit a=np.repeat(5,(1e4))
10000 loops, best of 3: 81.7 us per loop

%timeit a=np.tile(5,[1e4])
10000 loops, best of 3: 82.9 us per loop
Yariv
la source
13
Il np.full()serait utile d' ajouter un calendrier pour les plus récents et les plus directs . Sur ma machine, avec NumPy 1.8.1, elle est environ 15% plus lente que la fill()version moins directe (ce qui est inattendu, car elle full()a le potentiel d'aller un peu plus vite).
Eric O Lebigot
@DavidSanders: Je ne suis pas sûr de vous suivre: fill()c'est la solution la plus rapide. La solution de multiplication est beaucoup plus lente.
Eric O Lebigot
2
Remarque: si la vitesse est vraiment un problème, l'utilisation d'une taille de 10000au lieu de 1e4fait une différence notable, pour une raison quelconque ( full()est presque 50% plus lente, avec 1e4).
Eric O Lebigot
En ajoutant simplement mes résultats avec full(), il s'exécute considérablement plus lentement lorsque le type de données n'est pas explicitement un flottant. Sinon, c'est comparable (mais légèrement plus lent) avec les meilleures méthodes ici.
user2699
@ user2699 Je ne respecte pas cela, avec 100.000 éléments: full(100000, 5), full(100000, 5, dtype=float), full(100000, 5, dtype=int)et a =np.empty(100000); a.fill(5)tous prennent environ en même temps sur ma machine (sans mise en cache: %timeit -r1 -n1 …) (NumPy 1.11.2).
Eric O Lebigot,
65

Je pense que fillc'est le moyen le plus rapide de le faire.

a = np.empty(10)
a.fill(7)

Vous devez également toujours éviter d'itérer comme vous le faites dans votre exemple. Un simple a[:] = vaccomplira ce que fait votre itération en utilisant la diffusion numpy .

Paul
la source
1
Je vous remercie. En regardant fill, j'ai vu que cela repeatconvenait encore mieux à mes besoins.
max
Cela vous dérange-t-il de mettre à jour votre réponse pour dire que votre recommandation a[:]=vest en fait plus rapide que la fill?
max
@max Est-ce plus rapide? La diffusion est un moyen plus général de remplir un tableau et je suppose que c'est plus lent ou égal au cas d'utilisation très étroit de fill.
Paul
16

Apparemment, non seulement les vitesses absolues mais aussi l' ordre de vitesse (tel que rapporté par user1579844) dépendent de la machine; voici ce que j'ai trouvé:

a=np.empty(1e4); a.fill(5) est le plus rapide;

Par ordre de vitesse décroissante:

timeit a=np.empty(1e4); a.fill(5) 
# 100000 loops, best of 3: 10.2 us per loop
timeit a=np.empty(1e4); a[:]=5
# 100000 loops, best of 3: 16.9 us per loop
timeit a=np.ones(1e4)*5
# 100000 loops, best of 3: 32.2 us per loop
timeit a=np.tile(5,[1e4])
# 10000 loops, best of 3: 90.9 us per loop
timeit a=np.repeat(5,(1e4))
# 10000 loops, best of 3: 98.3 us per loop
timeit a=np.array([5]*int(1e4))
# 1000 loops, best of 3: 1.69 ms per loop (slowest BY FAR!)

Alors, essayez de découvrir et d'utiliser ce qui est le plus rapide sur votre plate-forme.

Rolf Bartstra
la source
14

j'ai eu

numpy.array(n * [value])

à l'esprit, mais apparemment, c'est plus lent que toutes les autres suggestions pour assez grand n .

Voici une comparaison complète avec perfplot (un de mes projets favoris ).

entrez la description de l'image ici

Les deux emptyalternatives sont toujours les plus rapides (avec NumPy 1.12.1). fullrattrape pour les grands tableaux.


Code pour générer le tracé:

import numpy as np
import perfplot


def empty_fill(n):
    a = np.empty(n)
    a.fill(3.14)
    return a


def empty_colon(n):
    a = np.empty(n)
    a[:] = 3.14
    return a


def ones_times(n):
    return 3.14 * np.ones(n)


def repeat(n):
    return np.repeat(3.14, (n))


def tile(n):
    return np.repeat(3.14, [n])


def full(n):
    return np.full((n), 3.14)


def list_to_array(n):
    return np.array(n * [3.14])


perfplot.show(
    setup=lambda n: n,
    kernels=[empty_fill, empty_colon, ones_times, repeat, tile, full, list_to_array],
    n_range=[2 ** k for k in range(27)],
    xlabel="len(a)",
    logx=True,
    logy=True,
)
Nico Schlömer
la source
7

Vous pouvez utiliser numpy.tile, par exemple:

v = 7
rows = 3
cols = 5
a = numpy.tile(v, (rows,cols))
a
Out[1]: 
array([[7, 7, 7, 7, 7],
       [7, 7, 7, 7, 7],
       [7, 7, 7, 7, 7]])

Bien qu'il tilesoit destiné à «tuiler» un tableau (au lieu d'un scalaire, comme dans ce cas), il fera le travail, créant des tableaux pré-remplis de toutes tailles et dimensions.

Rolf Bartstra
la source
5

sans engourdissement

>>>[2]*3
[2, 2, 2]
tnusraddinov
la source
La suggestion [v] * nserait plus directement liée à la question du PO.
allumé le
Cette réponse mentionne déjà cette approche.
CommonSense