Ініціалізація масиву NumPy (заповнення однаковими значеннями)


237

Мені потрібно створити масив NumPy довжини n, кожен елемент якого є v.

Чи є щось краще, ніж:

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

Я знаю zerosі onesпрацював би для v = 0, 1. Я міг би використовувати v * ones(n), але він не працюватиме, коли vє None, і також буде набагато повільніше.


1
На моєму комп’ютері, для випадку 0, використання a = np.zeros(n)в циклі швидше, ніж a.fill(0). Це суперечить тому, що я очікував, оскільки думав, a=np.zeros(n)що потрібно буде виділити та ініціалізувати нову пам'ять. Якщо хтось може це пояснити, я би вдячний.
користувач3731622

Ви не можете поставити Nonein в масив нумерів, оскільки комірки створюються з певним типом даних, в той час як None не має власного типу і насправді є вказівником.
Каміон

@Camion Так, я знаю зараз :) Звичайно, v * ones(n)це все ще жахливо, оскільки він використовує дороге множення. Замініть *на +хоч і, як v + zeros(n)виявляється, у деяких випадках напрочуд добре ( stackoverflow.com/questions/5891410/… ).
макс

max, замість створення масиву з нулями перед додаванням v, ще швидше створити його порожнім, var = np.empty(n)а потім заповнити його 'var [:] = v'. (До речі, np.full()так швидко , як це)
Camion

Відповіді:


308

Введено NumPy 1.8 np.full(), який є більш прямим методом, ніж empty()слід за fill()створенням масиву, заповненого певним значенням:

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

Це, можливо , спосіб створення масиву , заповнений певними значеннями, тому що він явно описує те , що це досягається (і це в принципі може бути дуже ефективним , так як він виконує дуже конкретне завдання).


1
Цей повний () метод працює для мене добре, але я не можу знайти трохи документації для цього. Хтось може вказати мені на потрібне місце?
Джеймс Адамс

1
Ви можете принаймні зробити це help(numpy.full)в оболонці Python. Я також здивований, що його немає в веб-документації.
Ерік О Лебігот

У моїй системі (Python 2.7, Numpy 1.8), np.full () насправді трохи повільніше, ніж np.empty (), а за ним np.fill ().
Джон Цвінк

1
Щодо 10 000 елементів я спостерігаю те саме (за винятком того, np.fill()що не існує і повинно бути arr.fill()), з різницею близько 10%. Якби різниця була більшою, я поставив би проблему в трекері помилок NumPy. :) Я віддаю перевагу більш чіткому та чіткішому коду, для такої невеликої різниці у виконанні часу, тому я йду з np.full()усім часом.
Ерік О Лебігот

На моїй машині np.full () така ж швидкість, як і np.array.fill ()
Fnord

92

Оновлено для Numpy 1.7.0: (Шапка-підказка до @Rolf Bartstra.)

a=np.empty(n); a.fill(5) найшвидший.

У порядку зменшення швидкості:

%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

13
Додавання термінів для останніх і прямих np.full()було б корисно. На моїй машині, з NumPy 1.8.1, це приблизно на 15% повільніше, ніж менш пряма fill()версія (що несподівано, оскільки full()потенціал проходить трохи швидше).
Ерік О Лебігот

@DavidSanders: Я не впевнений, що я слідкую за вами: fill()це найшвидше рішення. Рішення множення відбувається набагато повільніше.
Ерік О Лебігот

2
Примітка: якщо швидкість насправді викликає занепокоєння, використання розміру 10000замість того, 1e4щоб помітно змінити, чомусь ( full()майже на 50% повільніше, з 1e4).
Ерік О Лебігот

Тільки додаючи мої результати full(), він працює значно повільніше, коли тип даних явно не є плаваючою. Інакше це порівняно (але трохи повільніше) з найкращими методами тут.
користувач2699

@ User2699 Я не спостерігаючи це, з 100000 елементів: full(100000, 5), full(100000, 5, dtype=float), full(100000, 5, dtype=int)і a =np.empty(100000); a.fill(5)все беруть приблизно в той же час на моїй машині (без кешування: %timeit -r1 -n1 …) (NumPy 1.11.2).
Ерік О Лебігот

65

Я вважаю, що fillце найшвидший спосіб зробити це.

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

Ви також завжди повинні уникати ітерацій, як це робите у своєму прикладі. Простий a[:] = vвиконає те, що робить ваша ітерація, використовуючи нумероване мовлення .


1
Дякую. Подивившись fill, я побачив, що repeatще краще відповідає моїм потребам.
макс

Ви не хочете оновлювати свою відповідь, щоб сказати, що ваша рекомендація a[:]=vнасправді швидша за загальну fill?
макс

@max Це швидше? Мовлення є більш загальним способом заповнення масиву, і я б припустив, що це повільніше або дорівнює дуже вузькому випадку використання fill.
Пол

16

По- видимому, не тільки абсолютні швидкості , а й швидкість порядку (за даними user1579844) залежать машин; ось що я знайшов:

a=np.empty(1e4); a.fill(5) найшвидший;

У порядку зменшення швидкості:

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

Отже, спробуйте і дізнайтеся, і використовуйте те, що найшвидше на вашій платформі.


14

я мав

numpy.array(n * [value])

на увазі, але, мабуть, це повільніше, ніж усі інші пропозиції для досить великих n.

Ось повне порівняння з perfplot (мій проект для домашніх тварин).

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

Дві emptyальтернативи все ще найшвидші (з NumPy 1.12.1). fullназдоганяє великі масиви.


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

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

7

Ви можете використовувати numpy.tile, наприклад:

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

Хоча tileпризначений для "плитки" масиву (замість скаляра, як у цьому випадку), він зробить роботу, створивши попередньо заповнені масиви будь-якого розміру та розміру.


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