Inisialisasi array NumPy (isi dengan nilai yang identik)

237

Saya perlu membuat array NumPy dengan panjang n, yang masing-masing elemen v.

Adakah yang lebih baik dari:

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

Saya tahu zerosdan onesakan bekerja untuk v = 0, 1. Aku bisa menggunakan v * ones(n), tetapi tidak akan bekerja ketika vadalahNone , dan juga akan jauh lebih lambat.

maks
sumber
1
Di komputer saya, untuk kasus 0, menggunakan a = np.zeros(n)dalam lingkaran lebih cepat daripada a.fill(0). Ini bertentangan dengan apa yang saya harapkan karena saya pikir a=np.zeros(n)perlu mengalokasikan dan menginisialisasi memori baru. Jika ada yang bisa menjelaskan ini, saya akan sangat menghargainya.
user3731622
Anda tidak dapat menempatkan Nonein dalam array numpy, karena sel-sel dibuat dengan tipe data tertentu sementara Tidak ada yang memiliki tipe sendiri dan sebenarnya adalah pointer.
Camion
@Camion Ya saya tahu sekarang :) Tentu saja v * ones(n)masih mengerikan, karena menggunakan perkalian yang mahal. Ganti *dengan +meskipun, dan v + zeros(n)ternyata sangat bagus dalam beberapa kasus ( stackoverflow.com/questions/5891410/… ).
Maks
maks, alih-alih membuat array dengan nol sebelum menambahkan v, lebih cepat membuatnya kosong dengan var = np.empty(n)dan kemudian mengisinya dengan 'var [:] = v'. (Btw, np.full()secepat ini)
Camion

Jawaban:

308

NumPy 1.8 diperkenalkan np.full(), yang merupakan metode yang lebih langsung daripada empty()diikuti oleh fill()untuk membuat array diisi dengan nilai tertentu:

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

Ini bisa dibilang yang cara untuk menciptakan sebuah array diisi dengan nilai-nilai tertentu, karena secara eksplisit menggambarkan apa yang sedang dicapai (dan dapat pada prinsipnya menjadi sangat efisien karena melakukan tugas yang sangat spesifik).

Eric O Lebigot
sumber
1
Metode full () ini bekerja dengan baik untuk saya tetapi saya tidak dapat menemukan sedikit dokumentasi untuk itu. Adakah yang bisa mengarahkan saya ke tempat yang tepat?
James Adams
1
Setidaknya Anda bisa melakukannya help(numpy.full)di shell Python. Saya juga terkejut bahwa itu tidak ada dalam dokumentasi web.
Eric O Lebigot
Di sistem saya (Python 2.7, Numpy 1.8), np.full () sebenarnya sedikit lebih lambat dari np.empty () diikuti oleh np.fill ().
John Zwinck
1
Untuk 10.000 elemen, saya mengamati hal yang sama (kecuali yang np.fill()tidak ada dan seharusnya arr.fill()), dengan perbedaan sekitar 10%. Jika perbedaannya lebih besar, saya akan mengangkat masalah dalam pelacak bug NumPy. :) Saya lebih suka kode yang lebih eksplisit dan lebih jelas, untuk perbedaan kecil dalam mengeksekusi waktu, jadi saya np.full()selalu mengikuti.
Eric O Lebigot
Di komputer saya np.full () sama kecepatannya dengan np.array.fill ()
Fnord
92

Diperbarui untuk Numpy 1.7.0: (Hat-tip ke @Rolf Bartstra.)

a=np.empty(n); a.fill(5) tercepat.

Dalam urutan kecepatan menurun:

%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
sumber
13
Menambahkan waktu untuk yang lebih baru dan langsung np.full()akan bermanfaat. Di komputer saya, dengan NumPy 1.8.1, ini sekitar 15% lebih lambat dari versi yang kurang langsung fill()(yang tidak terduga, karena full()berpotensi sedikit lebih cepat).
Eric O Lebigot
@ DavidSanders: Saya tidak yakin saya mengikuti Anda: fill()adalah solusi tercepat. Solusi multiplikasi jauh lebih lambat.
Eric O Lebigot
2
Catatan: jika kecepatan benar-benar menjadi perhatian, menggunakan ukuran 10000alih-alih 1e4membuat perbedaan yang nyata, untuk beberapa alasan ( full()hampir 50% lebih lambat, dengan 1e4).
Eric O Lebigot
Dengan menambahkan hasil saya full(), itu berjalan jauh lebih lambat ketika datatype tidak secara eksplisit float. Kalau tidak, ini sebanding (tapi sedikit lebih lambat) dengan metode terbaik di sini.
user2699
@ user2699 Saya tidak mengamati ini, dengan 100.000 unsur-unsur: full(100000, 5), full(100000, 5, dtype=float), full(100000, 5, dtype=int)dan a =np.empty(100000); a.fill(5)semua mengambil sekitar waktu yang sama pada mesin (tanpa caching: %timeit -r1 -n1 …) (NumPy 1.11.2).
Eric O Lebigot
65

Saya percaya filladalah cara tercepat untuk melakukan ini.

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

Anda juga harus selalu menghindari iterasi seperti yang Anda lakukan dalam contoh Anda. Sederhana a[:] = vakan mencapai apa yang dilakukan iterasi Anda menggunakan siaran numpy .

Paul
sumber
1
Terima kasih. Dalam memandang fill, saya melihat yang lebih repeatsesuai dengan kebutuhan saya.
maks
Apakah Anda keberatan memperbarui jawaban Anda untuk mengatakan bahwa rekomendasi Anda a[:]=vsebenarnya secara keseluruhan lebih cepat daripada fill?
maks
@ Max Apakah lebih cepat? Penyiaran adalah cara yang lebih umum untuk mengisi array dan saya kira lebih lambat atau sama dengan kasus penggunaan yang sangat sempit fill.
Paul
16

Tampaknya, tidak hanya kecepatan absolut tetapi juga urutan kecepatan (seperti yang dilaporkan oleh user1579844) bergantung pada mesin; inilah yang saya temukan:

a=np.empty(1e4); a.fill(5) tercepat;

Dalam urutan kecepatan menurun:

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

Jadi, coba dan cari tahu, dan gunakan apa yang tercepat di platform Anda.

Rolf Bartstra
sumber
14

Saya punya

numpy.array(n * [value])

dalam pikiran, tetapi ternyata itu lebih lambat dari semua saran lain untuk cukup besar n .

Berikut ini perbandingan lengkap dengan perfplot (proyek kesayangan saya).

masukkan deskripsi gambar di sini

Dua emptyalternatif tersebut masih yang tercepat (dengan NumPy 1.12.1). fullmengejar array yang besar.


Kode untuk menghasilkan plot:

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

Anda dapat menggunakan numpy.tile, misalnya:

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

Meskipun tiledimaksudkan untuk 'memasang' array (alih-alih skalar, seperti dalam kasus ini), itu akan melakukan tugasnya, membuat array yang sudah diisi sebelumnya dari berbagai ukuran dan dimensi.

Rolf Bartstra
sumber
5

tanpa numpy

>>>[2]*3
[2, 2, 2]
tnusraddinov
sumber
Menyarankan [v] * nakan lebih langsung relevan dengan pertanyaan OP.
menyala
Jawaban ini sudah menyebutkan pendekatan ini.
CommonSense