Erstellen Sie eine mit NaNs gefüllte Numpy-Matrix

195

Ich habe folgenden Code:

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

Es wird eine width x height x 9Matrix mit Nullen erstellt. Stattdessen möchte ich wissen, ob es eine Funktion oder einen Weg gibt, sie auf NaNeinfache Weise zu s zu initialisieren .

verschlungenes Elysium
quelle
2
Eine Einschränkung ist, dass NumPy keinen ganzzahligen NA-Wert hat (im Gegensatz zu R). Siehe Pandas Liste der Fallstricke . Daher np.nangeht es schief, wenn es in int konvertiert wird.
smci
smci ist richtig. Für NumPy gibt es keinen solchen NaN-Wert. Es hängt also vom Typ und von NumPy ab, welcher Wert für NaN vorhanden sein wird. Wenn Sie sich dessen nicht bewusst sind, wird es Probleme verursachen
MasterControlProgram

Antworten:

271

Sie benötigen selten Schleifen für Vektoroperationen in Numpy. Sie können ein nicht initialisiertes Array erstellen und allen Einträgen gleichzeitig zuweisen:

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

Ich habe die Alternativen a[:] = numpy.nanhier und a.fill(numpy.nan)wie von Blaenk gepostet zeitlich festgelegt:

$ 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

Die Timings zeigen eine Präferenz für ndarray.fill(..)die schnellere Alternative. OTOH, ich mag die praktische Implementierung von numpy, bei der Sie ganzen Slices gleichzeitig Werte zuweisen können. Die Absicht des Codes ist sehr klar.

Beachten Sie, dass ndarray.fillder Vorgang direkt ausgeführt numpy.empty((3,3,)).fill(numpy.nan)wird und stattdessen zurückgegeben wird None.

u0b34a0f6ae
quelle
8
Ich bin damit einverstanden, dass die Absicht Ihres Codes klarer ist. Aber danke für die unvoreingenommenen Timings (oder besser gesagt, die Tatsache, dass du sie immer noch gepostet hast), ich weiß das zu schätzen :)
Jorge Israel Peña
2
Ich mag dieses : a = numpy.empty((3, 3,)) * numpy.nan. Es war schneller als, fillaber langsamer als die Zuweisungsmethode, aber es ist ein Oneliner !!
Heltonbiker
2
Bitte schauen Sie sich diese Antwort an: stackoverflow.com/questions/10871220/…
Ivan
3
Ich bevorzuge die .fill()Methode, aber der Geschwindigkeitsunterschied verringert sich auf praktisch nichts, wenn die Arrays größer werden.
naught101
4
... weil np.empty([2, 5])ein Array erstellt und dieses Array dann fill()direkt geändert wird, aber keine Kopie oder Referenz zurückgegeben wird. Wenn Sie np.empty(2, 5)mit einem Namen aufrufen möchten ("Zuweisen ist einer Variablen"), müssen Sie dies tun, bevor Sie direkte Operationen daran ausführen. Das Gleiche passiert, wenn Sie es tun [1, 2, 3].insert(1, 4). Die Liste wird erstellt und eine 4 eingefügt, es ist jedoch unmöglich, einen Verweis auf die Liste zu erhalten (und daher kann davon ausgegangen werden, dass es sich um Müll handelt). Bei unveränderlichen Daten wie Zeichenfolgen wird eine Kopie zurückgegeben, da Sie nicht direkt arbeiten können. Pandas können beides.
Flutefreak7
163

Eine weitere Option ist die Verwendung numpy.full, eine Option, die in NumPy 1.8+ verfügbar ist

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

Dies ist ziemlich flexibel und Sie können es mit jeder anderen Nummer füllen, die Sie möchten.

Pietro Biroli
quelle
19
Ich würde dies als die richtigste Antwort betrachten, da es genau das fullist, wofür es gedacht ist. np.empy((x,y))*np.nanist ein guter Zweitplatzierter (und Kompatibilität für alte Versionen von numpy).
travc
Dies ist langsamer alsfill 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 Wenn Sie den entsprechenden Code in die Zeitschleife einfügen, sind sie ungefähr gleich. Die beiden Methoden sind im Grunde gleich, Sie haben gerade die "np.empty" außerhalb des Timers in der ersten. 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
47

Ich habe die vorgeschlagenen Alternativen für die Geschwindigkeit verglichen und festgestellt, dass bei ausreichend großen Vektoren / Matrizen alle Alternativen außer val * onesund array(n * [val])gleich schnell sind.

Geben Sie hier die Bildbeschreibung ein


Code zur Reproduktion der Handlung:

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
quelle
Seltsam, das numpy.full(n, val)ist langsamer als a = numpy.empty(n) .. a.fill(val)da es intern dasselbe tut
Endolith
26

Kennen Sie sich aus numpy.nan?

Sie können Ihre eigene Methode erstellen, z.

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

Dann

nans([3,4])

würde ausgeben

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

Ich habe diesen Code in einem Mailinglisten-Thread gefunden .

Jorge Israel Peña
quelle
1
Scheint übertrieben.
Mad Physicist
@ MadPhysicist Das hängt ganz von Ihrer Situation ab. Wenn Sie nur ein einziges NaN-Array initialisieren müssen, ist eine benutzerdefinierte Funktion wahrscheinlich übertrieben. Wenn Sie jedoch ein NaN-Array an Dutzenden von Stellen in Ihrem Code initialisieren müssen, ist diese Funktion sehr praktisch.
Xukrao
1
@ Xukaro. Nicht wirklich, da es bereits eine flexiblere und effizientere Version einer solchen Funktion gibt, die in mehreren anderen Antworten erwähnt wird.
Mad Physicist
10

Sie können die Multiplikation immer verwenden, wenn Sie die Methoden .emptyoder nicht sofort aufrufen .full:

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

Natürlich funktioniert es auch mit jedem anderen numerischen Wert:

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

Die akzeptierte Antwort von @ u0b34a0f6ae ist jedoch dreimal schneller (CPU-Zyklen, keine Gehirnzyklen, um sich an die Numpy-Syntax zu erinnern;):

$ 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
Kochfelder
quelle
6

Eine andere Alternative ist die, numpy.broadcast_to(val,n)die unabhängig von der Größe in konstanter Zeit zurückgegeben wird und außerdem am speichereffizientesten ist (sie gibt eine Ansicht des wiederholten Elements zurück). Die Einschränkung ist, dass der zurückgegebene Wert schreibgeschützt ist.

Nachfolgend finden Sie einen Vergleich der Leistungen aller anderen Methoden, die unter Verwendung des gleichen Benchmarks wie in der Antwort von Nico Schlömer vorgeschlagen wurden .

Geben Sie hier die Bildbeschreibung ein

Giancarlo Sportelli
quelle
5

Wie gesagt, numpy.empty () ist der richtige Weg. Bei Objekten kann fill () jedoch möglicherweise nicht genau das tun, was Sie denken:

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)

Ein Weg kann zB sein:

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
quelle
Abgesehen davon, dass es praktisch nichts mit der ursprünglichen Frage zu tun hat, ordentlich.
Mad Physicist
1
Nun, es geht um "Initialisierung der Numpy-Matrix auf etwas anderes als Null oder Eins", falls "etwas anderes" ein Objekt ist :) (Praktischer
gesagt
3

Eine weitere Möglichkeit, die hier noch nicht erwähnt wurde, ist die Verwendung der NumPy-Kachel:

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

Gibt auch

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

Ich weiß nichts über Geschwindigkeitsvergleiche.

JHBonarius
quelle