NumPy-Array-Initialisierung (mit identischen Werten füllen)

236

Ich muss ein NumPy-Array mit einer Länge erstellen n, von denen jedes Element ist v.

Gibt es etwas Besseres als:

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

Ich weiß zerosund oneswürde für v = 0, 1 arbeiten. Ich könnte verwenden v * ones(n), aber es wird nicht funktionieren, wenn es vist None, und wäre auch viel langsamer.

max
quelle
1
Auf meinem Computer ist die Verwendung a = np.zeros(n)in der Schleife für den Fall 0 schneller als a.fill(0). Dies widerspricht meinen Erwartungen, da ich dachte, ich a=np.zeros(n)müsste neuen Speicher zuweisen und initialisieren. Wenn jemand dies erklären kann, würde ich es schätzen.
user3731622
Sie können Nonein kein Numpy-Array zuweisen, da die Zellen mit einem bestimmten Datentyp erstellt werden, während None einen eigenen Typ hat und tatsächlich ein Zeiger ist.
Camion
@ Camion Ja, ich weiß es jetzt :) Natürlich v * ones(n)ist es immer noch schrecklich, da es die teure Multiplikation verwendet. Ersetzen Sie es *durch +und es v + zeros(n)stellt sich in einigen Fällen als überraschend gut heraus ( stackoverflow.com/questions/5891410/… ).
Max
Anstatt ein Array mit Nullen vor dem Hinzufügen von v zu erstellen, ist es noch schneller, es leer zu erstellen var = np.empty(n)und dann mit 'var [:] = v' zu füllen. (Übrigens np.full()ist so schnell)
Camion

Antworten:

307

NumPy 1.8 wurde eingeführt. Dies np.full()ist eine direktere Methode als die empty()folgende, fill()um ein Array mit einem bestimmten Wert zu erstellen:

>>> 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]])

Dies ist wohl die Art und Weise, ein Array mit bestimmten Werten zu erstellen, da es explizit beschreibt, was erreicht wird (und im Prinzip sehr effizient sein kann, da es eine sehr spezifische Aufgabe ausführt).

Eric O Lebigot
quelle
1
Diese full () -Methode funktioniert gut für mich, aber ich kann keine Dokumentation dafür finden. Kann mich jemand auf den richtigen Ort hinweisen?
James Adams
1
Sie können dies zumindest help(numpy.full)in einer Python-Shell tun . Ich bin auch überrascht, dass es nicht in der Webdokumentation steht.
Eric O Lebigot
Auf meinem System (Python 2.7, Numpy 1.8) ist np.full () tatsächlich etwas langsamer als np.empty (), gefolgt von np.fill ().
John Zwinck
1
Bei 10.000 Elementen beobachte ich dasselbe (außer das np.fill()existiert nicht und sollte es sein arr.fill()), mit einem Unterschied von ungefähr 10%. Wenn der Unterschied größer wäre, würde ich ein Problem im NumPy-Bug-Tracker ansprechen. :) Ich bevorzuge expliziteren und klareren Code für einen so kleinen Unterschied in der Ausführungszeit, also gehe ich die np.full()ganze Zeit mit.
Eric O Lebigot
Auf meinem Computer ist np.full () die gleiche Geschwindigkeit wie np.array.fill ()
Fnord
92

Aktualisiert für Numpy 1.7.0: (Hutspitze zu @Rolf Bartstra.)

a=np.empty(n); a.fill(5) ist am schnellsten.

In absteigender Geschwindigkeitsreihenfolge:

%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
quelle
13
Das Hinzufügen eines Timings für die neueren und direkteren np.full()wäre nützlich. Auf meinem Computer ist es mit NumPy 1.8.1 etwa 15% langsamer als die weniger direkte fill()Version (was unerwartet full()ist und das Potenzial hat, etwas schneller zu werden).
Eric O Lebigot
@ DavidSanders: Ich bin nicht sicher, ob ich dir folge: fill()ist die schnellste Lösung. Die Multiplikationslösung ist viel langsamer.
Eric O Lebigot
2
Hinweis: Wenn Geschwindigkeit wirklich ein Problem darstellt, macht die Verwendung einer Größe von 10000anstelle von 1e4aus irgendeinem Grund einen spürbaren Unterschied ( full()ist mit fast 50% langsamer 1e4).
Eric O Lebigot
full()Wenn ich nur meine Ergebnisse mit hinzufüge , läuft es erheblich langsamer, wenn der Datentyp nicht explizit ein Float ist. Ansonsten ist es mit den besten Methoden hier vergleichbar (aber etwas langsamer).
user2699
@ user2699 ich dies nicht beobachtet werde, mit 100.000 Elementen: full(100000, 5), full(100000, 5, dtype=float), full(100000, 5, dtype=int)und a =np.empty(100000); a.fill(5)alle nehmen etwa zur gleichen Zeit auf meinem Rechner (ohne Caching: %timeit -r1 -n1 …) (NumPy 1.11.2).
Eric O Lebigot
65

Ich glaube, das fillist der schnellste Weg, dies zu tun.

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

Sie sollten auch immer vermeiden, wie in Ihrem Beispiel zu iterieren. Mit einer einfachen Funktion a[:] = vkönnen Sie mithilfe von Numpy Broadcasting erreichen, was Ihre Iteration bewirkt .

Paul
quelle
1
Danke dir. Beim Betrachten fillsah ich, dass das repeatmeinen Bedürfnissen noch besser entspricht.
Max
Haben Sie etwas dagegen, Ihre Antwort zu aktualisieren, um zu sagen, dass Ihre Empfehlung a[:]=vinsgesamt tatsächlich schneller ist als die fill?
Max
@max Ist es schneller? Broadcasting ist eine allgemeinere Methode, um ein Array zu füllen, und ich würde vermuten, dass es langsamer oder gleich dem sehr engen Anwendungsfall von ist fill.
Paul
16

Offenbar nicht nur die absoluten Geschwindigkeiten , sondern auch die Geschwindigkeit , um (wie durch user1579844 berichtete) sind maschinenabhängig; Folgendes habe ich gefunden:

a=np.empty(1e4); a.fill(5) ist am schnellsten;

In absteigender Geschwindigkeitsreihenfolge:

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!)

Versuchen Sie also herauszufinden, was auf Ihrer Plattform am schnellsten ist.

Rolf Bartstra
quelle
14

ich hatte

numpy.array(n * [value])

im Kopf, aber anscheinend ist das langsamer als alle anderen Vorschläge für groß genug n.

Hier ist ein vollständiger Vergleich mit Perfplot (einem meiner Lieblingsprojekte ).

Geben Sie hier die Bildbeschreibung ein

Die beiden emptyAlternativen sind immer noch die schnellsten (mit NumPy 1.12.1). fullholt große Arrays ein.


Code zum Generieren des Plots:

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
quelle
7

Sie können numpy.tilezB verwenden:

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]])

Obwohl tileein Array "kacheln" soll (anstelle eines Skalars, wie in diesem Fall), erledigt es die Aufgabe und erstellt vorgefüllte Arrays beliebiger Größe und Dimension.

Rolf Bartstra
quelle
5

ohne numpy

>>>[2]*3
[2, 2, 2]
tnusraddinov
quelle
Vorschläge [v] * nwären für die OP-Frage direkter relevant.
beleuchtet
Diese Antwort erwähnte diesen Ansatz bereits.
CommonSense