Инициализация массива NumPy (заполнить одинаковыми значениями)

238

Мне нужно создать массив длины 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)что нужно будет выделить и инициализировать новую память. Если кто-то может объяснить это, я был бы признателен.
user3731622
Вы не можете поместить None в массив numpy, поскольку ячейки создаются с определенным типом данных, в то время как None имеет свой собственный тип и фактически является указателем.
Камион
@Camion Да, теперь я знаю :) Конечно, v * ones(n)все еще ужасно, так как использует дорогостоящее умножение. Замените *на +while, и v + zeros(n)в некоторых случаях он оказывается на удивление хорошим ( stackoverflow.com/questions/5891410/… ).
максимум
max, вместо создания массива с нулями перед добавлением v, еще быстрее создать его пустым, var = np.empty(n)а затем заполнить его с помощью var [:] = v. (кстати, np.full()так быстро , как это)
Camion

Ответы:

309

Представлен 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
Этот метод full () работает хорошо для меня, но я не могу найти немного документации для него. Кто-нибудь может указать мне на правильное место?
Джеймс Адамс
1
Вы можете по крайней мере сделать это help(numpy.full)в оболочке Python. Я также удивлен, что этого нет в веб-документации.
Эрик О Лебиго
В моей системе (Python 2.7, Numpy 1.8) np.full () на самом деле немного медленнее, чем np.empty (), за которым следует np.fill ().
Джон Цвинк
1
Для 10000 элементов я наблюдаю то же самое (за исключением того, что 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(), он работает значительно медленнее, когда тип данных явно не является плавающим. В противном случае, это сопоставимо (но немного медленнее) с лучшими методами здесь.
user2699
@ 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

Очевидно, что не только абсолютные скорости, но и порядок скорости (как сообщается пользователем 1579844) зависят от машины; вот что я нашел:

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.

Вот полное сравнение с перфплотом ( мой любимый проект).

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

Две 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он предназначен для «разбиения» массива (вместо скаляра, как в данном случае), он будет выполнять свою работу, создавая предварительно заполненные массивы любого размера и размера.

Рольф Бартстра
источник
5

без обалденного

>>>[2]*3
[2, 2, 2]
tnusraddinov
источник
Предложение [v] * nбудет иметь более непосредственное отношение к вопросу ОП.
горит
Этот ответ уже упоминал этот подход.
CommonSense