Créer une matrice numpy remplie de NaNs

195

J'ai le code suivant:

r = numpy.zeros(shape = (width, height, 9))

Il crée une width x height x 9matrice remplie de zéros. Au lieu de cela, j'aimerais savoir s'il existe une fonction ou un moyen de les initialiser à la place en NaNs de manière simple.

Elysium dévoré
la source
2
Une mise en garde est que NumPy n'a pas de valeur NA entière (contrairement à R). Voir la liste des pandas des pandas . Va donc np.nanmal lorsqu'il est converti en int.
smci
smci a raison. Pour NumPy, il n'y a pas une telle valeur NaN. Cela dépend donc du type et de NumPy quelle valeur sera là pour NaN. Si vous n'êtes pas au courant de cela, cela causera des problèmes
MasterControlProgram

Réponses:

271

Vous avez rarement besoin de boucles pour les opérations vectorielles dans numpy. Vous pouvez créer un tableau non initialisé et attribuer à toutes les entrées à la fois:

>>> a = numpy.empty((3,3,))
>>> a[:] = numpy.nan
>>> a
array([[ NaN,  NaN,  NaN],
       [ NaN,  NaN,  NaN],
       [ NaN,  NaN,  NaN]])

J'ai chronométré les alternatives a[:] = numpy.nanici et a.fill(numpy.nan)telles que publiées par Blaenk:

$ python -mtimeit "import numpy as np; a = np.empty((100,100));" "a.fill(np.nan)"
10000 loops, best of 3: 54.3 usec per loop
$ python -mtimeit "import numpy as np; a = np.empty((100,100));" "a[:] = np.nan" 
10000 loops, best of 3: 88.8 usec per loop

Les horaires montrent une préférence ndarray.fill(..)comme alternative plus rapide. OTOH, j'aime l'implémentation pratique de numpy où vous pouvez attribuer des valeurs à des tranches entières à l'époque, l'intention du code est très claire.

Notez que ndarray.filleffectue son opération sur place, donc numpy.empty((3,3,)).fill(numpy.nan)reviendra à la place None.

u0b34a0f6ae
la source
8
Je suis d'accord que l'intention de votre code est plus claire. Mais merci pour les horaires impartiaux (ou plutôt, le fait que vous les ayez toujours postés), je l'apprécie :)
Jorge Israel Peña
2
Je comme celui - ci: a = numpy.empty((3, 3,)) * numpy.nan. Il a chronométré plus rapidement fillmais plus lentement que la méthode d'affectation, mais c'est un oneliner !!
heltonbiker
2
Veuillez regarder cette réponse: stackoverflow.com/questions/10871220/…
Ivan
3
Je préfère la .fill()méthode, mais la différence de vitesse se réduit à presque rien à mesure que les tableaux s'agrandissent.
naught101
4
... car np.empty([2, 5])crée un tableau, puis fill()modifie ce tableau sur place, mais ne renvoie ni copie ni référence. Si vous voulez appeler np.empty(2, 5)par un nom ("assigner à une variable"), vous devez le faire avant de faire des opérations sur place dessus. La même chose se produit si vous le faites [1, 2, 3].insert(1, 4). La liste est créée et un 4 est inséré, mais il est impossible d'obtenir une référence à la liste (et donc on peut supposer qu'elle a été récupérée). Sur les données immuables comme les chaînes, une copie est retournée, car vous ne pouvez pas fonctionner sur place. Les pandas peuvent faire les deux.
flutefreak7
164

Une autre option est d'utiliser numpy.full, une option disponible dans NumPy 1.8+

a = np.full([height, width, 9], np.nan)

C'est assez flexible et vous pouvez le remplir avec n'importe quel autre numéro que vous souhaitez.

Pietro Biroli
la source
19
Je considérerais cela comme la réponse la plus correcte car c'est exactement ce à quoi il fullest destiné. np.empy((x,y))*np.nanest un bon runner-up (et compatibilité pour les anciennes versions de numpy).
travc
c'est plus lent quefill python -mtimeit "import numpy as np; a = np.empty((100,100));" "a.fill(np.nan)" 100000 loops, best of 3: 13.3 usec per loop python -mtimeit "import numpy as np; a = np.full((100,100), np.nan);" 100000 loops, best of 3: 18.5 usec per loop
Farnabaz
5
@Farnabaz Si vous mettez le code équivalent à l'intérieur de la boucle de synchronisation, ils sont à peu près les mêmes. Les deux méthodes sont fondamentalement égales, vous avez juste le "np.empty" en dehors du temporisateur dans le premier. python -mtimeit "import numpy as np; a = np.empty((1000,1000)); a.fill(np.nan)" 1000 loops, best of 3: 381 usec per loop $ python -mtimeit "import numpy as np; a = np.full((1000,1000), np.nan);" 1000 loops, best of 3: 383 usec per loop
Scott Staniewicz
48

J'ai comparé les alternatives suggérées pour la vitesse et constaté que, pour des vecteurs / matrices suffisamment grands à remplir, toutes les alternatives sauf val * oneset array(n * [val])sont également rapides.

entrez la description de l'image ici


Code pour reproduire l'intrigue:

import numpy
import perfplot

val = 42.0


def fill(n):
    a = numpy.empty(n)
    a.fill(val)
    return a


def colon(n):
    a = numpy.empty(n)
    a[:] = val
    return a


def full(n):
    return numpy.full(n, val)


def ones_times(n):
    return val * numpy.ones(n)


def list(n):
    return numpy.array(n * [val])


perfplot.show(
    setup=lambda n: n,
    kernels=[fill, colon, full, ones_times, list],
    n_range=[2 ** k for k in range(20)],
    logx=True,
    logy=True,
    xlabel="len(a)",
)
Nico Schlömer
la source
Étrange qui numpy.full(n, val)est plus lent que a = numpy.empty(n) .. a.fill(val)depuis car il fait la même chose en interne
endolith
26

Connaissez-vous numpy.nan?

Vous pouvez créer votre propre méthode telle que:

def nans(shape, dtype=float):
    a = numpy.empty(shape, dtype)
    a.fill(numpy.nan)
    return a

ensuite

nans([3,4])

sortirait

array([[ NaN,  NaN,  NaN,  NaN],
       [ NaN,  NaN,  NaN,  NaN],
       [ NaN,  NaN,  NaN,  NaN]])

J'ai trouvé ce code dans un fil de discussion .

Jorge Israel Peña
la source
1
Semble exagéré.
Mad Physicist
@MadPhysicist Cela dépend entièrement de votre situation. Si vous devez initialiser un seul tableau NaN, alors oui, une fonction personnalisée est probablement exagérée. Cependant, si vous devez initialiser un tableau NaN à des dizaines d'endroits dans votre code, avoir cette fonction devient très pratique.
Xukrao
1
@Xukaro. Pas vraiment, étant donné qu'une version plus flexible et efficace d'une telle fonction existe déjà et est mentionnée dans plusieurs autres réponses.
Mad Physicist
10

Vous pouvez toujours utiliser la multiplication si vous ne vous souvenez pas immédiatement des méthodes .emptyou .full:

>>> np.nan * np.ones(shape=(3,2))
array([[ nan,  nan],
       [ nan,  nan],
       [ nan,  nan]])

Bien sûr, cela fonctionne également avec toute autre valeur numérique:

>>> 42 * np.ones(shape=(3,2))
array([[ 42,  42],
       [ 42,  42],
       [ 42, 42]])

Mais la réponse acceptée par @ u0b34a0f6ae est 3 fois plus rapide (cycles CPU, pas cycles cérébraux pour se souvenir de la syntaxe numpy;):

$ python -mtimeit "import numpy as np; X = np.empty((100,100));" "X[:] = np.nan;"
100000 loops, best of 3: 8.9 usec per loop
(predict)laneh@predict:~/src/predict/predict/webapp$ master
$ python -mtimeit "import numpy as np; X = np.ones((100,100));" "X *= np.nan;"
10000 loops, best of 3: 24.9 usec per loop
plaques de cuisson
la source
6

Une autre alternative est celle numpy.broadcast_to(val,n)qui retourne en temps constant quelle que soit la taille et qui est également la plus efficace en mémoire (elle retourne une vue de l'élément répété). La mise en garde est que la valeur renvoyée est en lecture seule.

Ci-dessous, une comparaison des performances de toutes les autres méthodes qui ont été proposées en utilisant le même benchmark que dans la réponse de Nico Schlömer .

entrez la description de l'image ici

Giancarlo Sportelli
la source
5

Comme dit, numpy.empty () est le chemin à parcourir. Cependant, pour les objets, fill () peut ne pas faire exactement ce que vous pensez qu'il fait:

In[36]: a = numpy.empty(5,dtype=object)
In[37]: a.fill([])
In[38]: a
Out[38]: array([[], [], [], [], []], dtype=object)
In[39]: a[0].append(4)
In[40]: a
Out[40]: array([[4], [4], [4], [4], [4]], dtype=object)

Une solution peut être par exemple:

In[41]: a = numpy.empty(5,dtype=object)
In[42]: a[:]= [ [] for x in range(5)]
In[43]: a[0].append(4)
In[44]: a
Out[44]: array([[4], [], [], [], []], dtype=object)
ntg
la source
En plus d'avoir pratiquement rien à voir avec la question d'origine, c'est bien.
Mad Physicist
1
Eh bien, il s'agit de "Initialiser la matrice numpy à autre chose que zéro ou un", dans le cas où "quelque chose d'autre" est un objet :) (Plus concrètement, Google m'a conduit ici pour l'initialisation avec une liste vide)
ntg
3

Encore une autre possibilité non encore mentionnée ici est d'utiliser la tuile NumPy:

a = numpy.tile(numpy.nan, (3, 3))

Donne également

array([[ NaN,  NaN,  NaN],
       [ NaN,  NaN,  NaN],
       [ NaN,  NaN,  NaN]])

Je ne connais pas la comparaison de vitesse.

JHBonarius
la source