Створіть нутризовану матрицю, заповнену NaN


195

У мене є такий код:

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

Він створює width x height x 9матрицю, заповнену нулями. Натомість я хотів би знати, чи існує функція чи спосіб їх ініціалізації, а не NaNпросто.


2
Одне застереження полягає в тому, що NumPy не має цілого значення NA (на відміну від R). Дивіться список панд готчей . Звідси np.nanвиходить не так, коли переходить до int.
smci

smci має рацію. Для NumPy немає такого значення NaN. Отже, від типу та від NumPy залежить, яке значення буде для NaN. Якщо ви цього не знаєте, це спричинить неприємності
MasterControlProgram

Відповіді:


271

Вам рідко потрібні петлі для векторних операцій в нуме. Ви можете створити неініціалізований масив і призначити всі записи одночасно:

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

Я приурочив альтернативи a[:] = numpy.nanтут і a.fill(numpy.nan)як опублікував Блаєнк:

$ 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

Часи показують перевагу ndarray.fill(..)як більш швидку альтернативу. ОТОХ, мені подобається реалізація зручності numpy, де ви можете призначити значення цілим фрагментам у той час, намір коду дуже зрозумілий.

Зауважимо, що ndarray.fillвиконує свою операцію на місці, такnumpy.empty((3,3,)).fill(numpy.nan) замість цього повернеться None.


8
Я погоджуюся, що намір вашого коду ясніший. Але дякую за неупереджені таймінги (вірніше, те, що ви все-таки розмістили їх), я ціную це :)
Хорхе Ізраїль Пенья

2
Мені подобається цей: a = numpy.empty((3, 3,)) * numpy.nan. Він fillприділяється часу швидше, але повільніше, ніж метод призначення, але це oneliner !!
heltonbiker

2
Будь ласка, подивіться на цю відповідь: stackoverflow.com/questions/10871220/…
Іван

3
Я віддаю перевагу .fill()методу, але різниця в швидкостях зводиться практично до нічого, оскільки масиви збільшуються.
naught101

4
... тому що np.empty([2, 5])створює масив, значитьfill() змінює цей масив на місці, але не повертає копію чи посилання. Якщо ви хочете зателефонувати np.empty(2, 5)по імені ("призначити змінній"), це потрібно зробити перед тим, як зробити на ньому операції на місці. Те ж саме відбувається, якщо ви робите [1, 2, 3].insert(1, 4). Список створюється і вставляється 4, але неможливо отримати посилання на список (і, таким чином, можна припустити, що було зібрано сміття). На незмінних даних, таких як рядки, копія повертається, тому що ви не можете працювати на місці. Панди можуть робити і те, і інше.
flutefreak7

164

Інший варіант - використання numpy.full, опція, доступна в NumPy 1.8+

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

Це досить гнучко, і ви можете заповнити його будь-яким іншим номером, який хочете.


19
Я вважаю це найбільш правильною відповіддю, оскільки це саме те, що fullпризначено. np.empy((x,y))*np.nan- хороший підбіг (і сумісність для старих версій numpy).
travc

це повільніше, щоfill 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
Фарнабаз

5
@Farnabaz Якщо ви помістите еквівалентний код, що знаходиться в циклі синхронізації, вони приблизно однакові. Два способи в основному рівні, ви тільки що отримали "np.empty" поза таймером у першому.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
Скотт Станевич,

49

Я порівняв запропоновані альтернативи щодо швидкості та виявив, що для достатньо великих векторів / матриць для заповнення всі альтернативи, за винятком val * onesі array(n * [val])є однаково швидкими.

введіть тут опис зображення


Код для відтворення сюжету:

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)",
)

Дивно , що numpy.full(n, val)повільніше , ніж , a = numpy.empty(n) .. a.fill(val)так як він робить те ж саме всередині
ендоліти

26

Ви знайомі? numpy.nan ?

Ви можете створити власний метод, наприклад:

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

Тоді

nans([3,4])

виведе

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

Я знайшов цей код у потоці списку розсилки .


1
Здається, переборщення.
Божевільний фізик

@MadPhysicist Це повністю залежить від вашої ситуації. Якщо вам доведеться ініціалізувати лише один єдиний масив NaN, то так, користувацька функція, ймовірно, є надмірною. Однак якщо вам доведеться ініціалізувати масив NaN у десятках місць у вашому коді, то використання цієї функції стає досить зручним.
Xukrao

1
@Xukaro. Не дуже, зважаючи на те, що більш гнучка та ефективна версія такої функції вже існує і згадується в безлічі інших відповідей.
Божевільний фізик

10

Ви завжди можете використовувати множення, якщо не одразу згадати .emptyабо .fullметоди:

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

Звичайно, він також працює з будь-яким іншим числовим значенням:

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

Але прийнята відповідь @ u0b34a0f6ae - в 3 рази швидше (цикли процесора, а не цикли мозку для запам'ятовування синтаксису нуме;):

$ 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

6

Інша альтернатива - це numpy.broadcast_to(val,n) це повернення в постійний час незалежно від розміру, а також є найбільш ефективною пам'яттю (повертає вигляд повторного елемента). Застереження полягає в тому, що повернене значення є лише для читання.

Нижче наводиться порівняння результатів роботи всіх інших методів, які були запропоновані, використовуючи той самий орієнтир, що і у відповіді Ніко Шльомера .

введіть тут опис зображення


5

Як було сказано, numpy.empty () - це шлях. Однак для об’єктів fill () може не робити саме те, що, на вашу думку, робиться:

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)

Один із способів, наприклад, може бути:

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)

Крім того, що практично не має нічого спільного з оригінальним питанням, акуратне.
Божевільний фізик

1
Ну, йдеться про "Ініціалізацію матричної нумерії до чогось іншого, ніж нуля чи одиниці", у випадку, якщо "щось інше" є об'єктом :) (Більш практично, Google привів мене сюди для ініціалізації з порожнім списком)
ntg

3

Ще одна можливість, поки не згадана тут, - це використовувати плитку NumPy:

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

Також дає

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

Я не знаю про порівняння швидкості.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.