Inicialização do array NumPy (preenchimento com valores idênticos)


237

Eu preciso criar uma matriz NumPy de comprimento n , cada elemento do qual év .

Existe algo melhor do que:

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

Eu sei zerose onesfuncionaria para v = 0, 1. Eu poderia usar v * ones(n), mas não funcionará quando vfor Nonee também seria muito mais lento.


1
No meu computador, para o caso 0, o uso a = np.zeros(n)no loop é mais rápido que a.fill(0). Isso é contrário ao que eu esperava, pois pensei a=np.zeros(n)que precisaria alocar e inicializar nova memória. Se alguém puder explicar isso, eu agradeceria.
— user3731622

Você não pode colocar None em uma matriz numpy, pois as células são criadas com um tipo de dados específico, enquanto None possui seu próprio tipo e é de fato um ponteiro.
— Camion

@Camion Sim, eu sei agora :) É claro que v * ones(n)ainda é horrível, pois usa a multiplicação cara. Substitua *por +, porém, e v + zeros(n)se mostra surpreendentemente bom em alguns casos ( stackoverflow.com/questions/5891410/… ).
— Max

max, em vez de criar uma matriz com zeros antes de adicionar v, é ainda mais rápido criá-la vazia var = np.empty(n)e preenchê-la com 'var [:] = v'. (aliás, np.full()é tão rápido como este)
— Camion

Respostas:


308

Introduzido o NumPy 1.8 np.full(), que é um método mais direto do que o empty()seguido fill()para criar uma matriz preenchida com um determinado valor:

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

Essa é, sem dúvida, a maneira de criar uma matriz preenchida com certos valores, porque descreve explicitamente o que está sendo alcançado (e, em princípio, pode ser muito eficiente, pois executa uma tarefa muito específica).


1
Esse método full () está funcionando bem para mim, mas não consigo encontrar um pouco de documentação para ele. Alguém pode me apontar para o lugar certo?
— James Adams

1
Você pode pelo menos fazer help(numpy.full)em um shell Python. Também estou surpreso que não esteja na documentação da web.
— Eric O Lebigot

No meu sistema (Python 2.7, Numpy 1.8), o np.full () é realmente um pouco mais lento que o np.empty () seguido por np.fill ().
— 21914 John Zwinck

1
Para 10.000 elementos, observo a mesma coisa (exceto que np.fill()não existe e deveria existir arr.fill()), com uma diferença de cerca de 10%. Se a diferença fosse maior, eu levantaria um problema no rastreador de erros do NumPy. :) Prefiro um código mais explícito e claro, por uma diferença tão pequena no tempo de execução, por isso continuo np.full()o tempo todo.
— Eric O Lebigot

No meu np.full máquina () é a mesma velocidade como np.array.fill ()
— Fnord

92

Atualizado para o Numpy 1.7.0: (dica de chapéu para @Rolf Bartstra.)

a=np.empty(n); a.fill(5) é o mais rápido

Em ordem decrescente de velocidade:

%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
Adicionar um tempo para o mais recente e direto np.full()seria útil. Na minha máquina, com o NumPy 1.8.1, é cerca de 15% mais lento que a fill()versão menos direta (o que é inesperado, pois full()tem o potencial de ser um pouco mais rápido).
— Eric O Lebigot

@ DavidSanders: Não tenho certeza se estou te seguindo: fill()é a solução mais rápida. A solução de multiplicação é muito mais lenta.
— Eric O Lebigot

2
Nota: se a velocidade é realmente uma preocupação, usar um tamanho em 10000vez de 1e4faz uma diferença notável, por algum motivo ( full()é quase 50% mais lento com 1e4).
— Eric O Lebigot

Apenas adicionando meus resultados com full(), ele é executado consideravelmente mais lento quando o tipo de dados não é explicitamente um float. Caso contrário, é comparável (mas um pouco mais lento) com os melhores métodos aqui.
— user2699

@ user2699 eu não estou observando isso, com 100.000 elementos: full(100000, 5), full(100000, 5, dtype=float), full(100000, 5, dtype=int)e a =np.empty(100000); a.fill(5)todos têm aproximadamente o mesmo tempo na minha máquina (sem cache: %timeit -r1 -n1 …) (NumPy 1.11.2).
— Eric O Lebigot

65

Eu acredito que fillé a maneira mais rápida de fazer isso.

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

Você também deve sempre evitar iterar como está fazendo no seu exemplo. Um simples a[:] = vrealizará o que sua iteração faz usando difusão numpy .


1
Obrigado. Ao olhar fill, vi que repeatatende às minhas necessidades ainda melhor.
— Max

Você se importa de atualizar sua resposta para dizer que sua recomendação a[:]=vé realmente mais rápida do que a fill?
— max

@max É mais rápido? A transmissão é uma maneira mais geral de preencher uma matriz e eu acho que é mais lenta ou igual ao caso de uso muito restrito de fill.
— Paul

16

Aparentemente, não apenas as velocidades absolutas, mas também a ordem de velocidade (conforme relatado pelo usuário 1579844) dependem da máquina; aqui está o que eu encontrei:

a=np.empty(1e4); a.fill(5) é mais rápido;

Em ordem decrescente de velocidade:

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

Portanto, tente descobrir e use o que é mais rápido em sua plataforma.


14

eu tinha

numpy.array(n * [value])

em mente, mas aparentemente isso é mais lento que todas as outras sugestões de tamanho suficiente n .

Aqui está uma comparação completa com o perfplot (um projeto meu para animais de estimação).

insira a descrição da imagem aqui

As duas emptyalternativas ainda são as mais rápidas (com o NumPy 1.12.1). fullalcança grandes matrizes.


Código para gerar o gráfico:

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

Você pode usar numpy.tile, por exemplo:

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

Embora tilese pretenda 'agrupar' uma matriz (em vez de uma escalar, como neste caso), ela fará o trabalho, criando matrizes pré-preenchidas de qualquer tamanho e dimensão.


Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.