Buat numpy matrix diisi dengan NaNs

195

Saya memiliki kode berikut:

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

Itu menciptakan width x height x 9matriks diisi dengan nol. Sebagai gantinya, saya ingin tahu apakah ada fungsi atau cara untuk menginisialisasi mereka alih-alih dengan NaNcara mudah.

melahap elysium
sumber
2
Satu peringatan adalah bahwa NumPy tidak memiliki nilai NA integer (tidak seperti R). Lihat panda daftar gotcha . Karenanya np.nansalah ketika dikonversi ke int.
smci
smci benar. Untuk NumPy tidak ada nilai NaN tersebut. Jadi itu tergantung pada jenis dan pada NumPy nilai mana yang akan ada untuk NaN. Jika Anda tidak mengetahui hal ini, itu akan menyebabkan masalah
MasterControlProgram

Jawaban:

271

Anda jarang membutuhkan loop untuk operasi vektor di numpy. Anda dapat membuat larik yang belum diinisialisasi dan menetapkan semua entri sekaligus:

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

Saya telah menghitung waktunya alternatif di a[:] = numpy.nansini dan a.fill(numpy.nan)sebagaimana diposting oleh 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

Pengaturan waktu menunjukkan preferensi untuk ndarray.fill(..) sebagai alternatif yang lebih cepat. OTOH, saya suka implementasi kenyamanan numpy di mana Anda dapat menetapkan nilai untuk seluruh irisan pada saat itu, maksud kode sangat jelas.

Perhatikan bahwa ndarray.fillmenjalankan operasinya di tempat, jadi numpy.empty((3,3,)).fill(numpy.nan)alih-alih akan kembali None.

u0b34a0f6ae
sumber
8
Saya setuju bahwa maksud kode Anda lebih jelas. Tapi terima kasih untuk berisi timing (atau lebih tepatnya, kenyataan bahwa Anda masih diposting mereka), saya menghargai itu :)
Jorge Israel Peña
2
Aku seperti ini: a = numpy.empty((3, 3,)) * numpy.nan. Waktunya lebih cepat dari pada filltetapi lebih lambat dari pada metode penugasan, tetapi itu adalah oneliner !!
heltonbiker
2
Silakan lihat jawaban ini: stackoverflow.com/questions/10871220/…
Ivan
3
Saya lebih suka .fill()metode ini, tetapi perbedaan kecepatan berkurang menjadi hampir tidak ada saat array semakin besar.
nucky101
4
... karena np.empty([2, 5])membuat array, kemudian fill()memodifikasi array itu di tempat, tetapi tidak mengembalikan salinan atau referensi. Jika Anda ingin memanggil np.empty(2, 5)dengan nama ("assign is to a variable"), Anda harus melakukannya sebelum melakukan operasi di tempat. Hal yang sama juga terjadi jika Anda melakukannya [1, 2, 3].insert(1, 4). Daftar dibuat dan 4 dimasukkan, tetapi tidak mungkin untuk mendapatkan referensi ke daftar (dan dengan demikian dapat diasumsikan telah dikumpulkan dari sampah). Pada data yang tidak dapat diubah seperti string, salinan dikembalikan, karena Anda tidak dapat beroperasi di tempat. Panda dapat melakukan keduanya.
flutefreak7
164

Opsi lain adalah menggunakan numpy.full, opsi yang tersedia di NumPy 1.8+

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

Ini cukup fleksibel dan Anda dapat mengisinya dengan nomor lain yang Anda inginkan.

Pietro Biroli
sumber
19
Saya akan menganggap ini sebagai jawaban yang paling benar karena itu memang tepat untuk apa full. np.empy((x,y))*np.nanadalah runner-up yang bagus (dan kompatibilitas untuk versi lama numpy).
travc
ini lebih lambatfill 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 Jika Anda meletakkan kode yang setara di dalam loop waktu mereka hampir sama. Kedua metode pada dasarnya sama, Anda baru saja mendapatkan "np.empty" di luar timer di yang pertama. 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

Saya membandingkan alternatif kecepatan yang disarankan dan menemukan bahwa, untuk mengisi vektor / matriks yang cukup besar, semua alternatif kecuali val * onesdan array(n * [val])sama-sama cepat.

masukkan deskripsi gambar di sini


Kode untuk mereproduksi plot:

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
sumber
Aneh yang numpy.full(n, val)lebih lambat daripada a = numpy.empty(n) .. a.fill(val)karena ia melakukan hal yang sama secara internal
endolith
26

Apakah Anda kenal numpy.nan?

Anda dapat membuat metode Anda sendiri seperti:

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

Kemudian

nans([3,4])

akan menghasilkan

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

Saya menemukan kode ini di utas milis .

Jorge Israel Peña
sumber
1
Sepertinya berlebihan.
Fisikawan Gila
@MadPhysicist Itu sepenuhnya tergantung pada situasi Anda. Jika Anda harus menginisialisasi hanya satu array NaN tunggal, maka ya, fungsi kustom mungkin berlebihan. Namun jika Anda harus menginisialisasi array NaN di banyak tempat dalam kode Anda, maka memiliki fungsi ini menjadi cukup nyaman.
Xukrao
1
@Xukaro. Tidak juga, mengingat bahwa versi yang lebih fleksibel dan efisien dari fungsi semacam itu sudah ada dan disebutkan dalam beberapa jawaban lainnya.
Fisikawan Gila
10

Anda selalu dapat menggunakan perkalian jika Anda tidak segera mengingat metode .emptyatau .full:

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

Tentu saja ia bekerja dengan nilai numerik lainnya juga:

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

Tetapi jawaban yang diterima @ u0b34a0f6ae adalah 3x lebih cepat (siklus CPU, bukan siklus otak untuk mengingat sintaks 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
hobs
sumber
6

Alternatif lain adalah numpy.broadcast_to(val,n) yang mengembalikan dalam waktu konstan terlepas dari ukuran dan juga yang paling efisien memori (mengembalikan tampilan elemen yang diulang). Peringatannya adalah bahwa nilai yang dikembalikan hanya baca-saja.

Di bawah ini adalah perbandingan kinerja semua metode lain yang telah diusulkan menggunakan tolok ukur yang sama seperti dalam jawaban Nico Schlömer .

masukkan deskripsi gambar di sini

Giancarlo Sportelli
sumber
5

Seperti yang dikatakan, numpy.empty () adalah cara untuk pergi. Namun, untuk objek, fill () mungkin tidak melakukan persis seperti yang Anda pikirkan:

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)

Salah satu jalan keluar misalnya:

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
sumber
Selain hampir tidak ada hubungannya dengan pertanyaan aslinya, rapi.
Fisikawan Gila
1
Nah, ini tentang "Menginisialisasi matriks numpy ke sesuatu selain nol atau satu", dalam kasus "sesuatu yang lain" adalah objek :) (Lebih praktisnya, google membawa saya ke sini untuk menginisialisasi dengan daftar kosong)
ntg
3

Namun kemungkinan lain yang belum disebutkan di sini adalah menggunakan ubin NumPy:

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

Juga memberi

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

Saya tidak tahu tentang perbandingan kecepatan.

JHBonarius
sumber