Criar matriz numpy preenchida com NaNs

195

Eu tenho o seguinte código:

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

Ele cria uma width x height x 9matriz preenchida com zeros. Em vez disso, eu gostaria de saber se existe uma função ou maneira de inicializá-los, em vez de NaNs de uma maneira fácil.

elísio devorado
fonte
2
Uma ressalva é que o NumPy não possui um valor inteiro de NA (ao contrário de R). Veja a lista de pandas de pandas . Portanto, np.nandá errado quando convertido em int.
smci
SMCI está certo. Para NumPy, não existe esse valor NaN. Portanto, depende do tipo e do NumPy, qual valor estará presente para NaN. Se você não estiver ciente disso, isso causará problemas
MasterControlProgram

Respostas:

271

Você raramente precisa de loops para operações de vetor em numpy. Você pode criar uma matriz não inicializada e atribuir a todas as entradas de uma vez:

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

Eu cronometrei as alternativas a[:] = numpy.nanaqui e a.fill(numpy.nan)como postadas por 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

Os tempos mostram uma preferência por ndarray.fill(..)como a alternativa mais rápida. OTOH, eu gosto da implementação de conveniência do numpy, onde você pode atribuir valores a fatias inteiras no momento, a intenção do código é muito clara.

Observe que ndarray.fillrealiza sua operação no local, numpy.empty((3,3,)).fill(numpy.nan)retornando None.

u0b34a0f6ae
fonte
8
Concordo que a intenção do seu código é mais clara. Mas graças para os horários imparciais (ou melhor, o fato de que você ainda postou-los), eu aprecio isso :)
Jorge Israel Peña
2
I como este: a = numpy.empty((3, 3,)) * numpy.nan. O tempo foi mais rápido do que o fillmais lento que o método de atribuição, mas é um delineador !!
precisa saber é o seguinte
2
Por favor, olhe esta resposta: stackoverflow.com/questions/10871220/...
Ivan
3
Eu prefiro o .fill()método, mas a diferença de velocidade reduz a praticamente nada, à medida que as matrizes ficam maiores.
naught101
4
... porque np.empty([2, 5])cria uma matriz, fill()modifica-a no local, mas não retorna uma cópia ou referência. Se você deseja chamar np.empty(2, 5)por um nome ("atribuir é a uma variável"), é necessário fazê-lo antes de executar as operações no local. A mesma coisa acontece se você fizer [1, 2, 3].insert(1, 4). A lista é criada e um 4 é inserido, mas é impossível obter uma referência à lista (e, portanto, pode-se supor que ela tenha sido coletada de lixo). Em dados imutáveis, como seqüências de caracteres, uma cópia é retornada, porque você não pode operar no local. Os pandas podem fazer as duas coisas.
precisa saber é o seguinte
164

Outra opção é usar numpy.full, uma opção disponível no NumPy 1.8+

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

Isso é bastante flexível e você pode preenchê-lo com qualquer outro número que desejar.

Pietro Biroli
fonte
19
Eu consideraria essa a resposta mais correta, já que é ansiosamente o que isso fullsignifica. np.empy((x,y))*np.nané um bom vice-campeão (e compatibilidade para versões antigas do numpy).
travc 21/09/15
isso é mais lento quefill 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 Se você colocar o código equivalente dentro do loop de temporização, eles são praticamente os mesmos. Os dois métodos são basicamente iguais, você acabou de obter o "np.empty" fora do cronômetro no primeiro. 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 28/10
47

Comparei as alternativas sugeridas para velocidade e descobri que, para vetores / matrizes grandes o suficiente para preencher, todas as alternativas, exceto val * onese array(n * [val])são igualmente rápidas.

insira a descrição da imagem aqui


Código para reproduzir o gráfico:

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
fonte
Estranho que numpy.full(n, val)é mais lento do que a = numpy.empty(n) .. a.fill(val)uma vez que faz a mesma coisa internamente
endolith
26

Você é familiar com numpy.nan ?

Você pode criar seu próprio método, como:

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

Então

nans([3,4])

produziria

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

Encontrei esse código em um thread de lista de discussão .

Jorge Israel Peña
fonte
1
Parece exagero.
May Physicist
@ MadPhysicist Isso depende inteiramente da sua situação. Se você precisar inicializar apenas uma única matriz NaN, sim, uma função personalizada provavelmente será um exagero. No entanto, se você precisar inicializar uma matriz NaN em dezenas de locais no seu código, ter essa função se tornará bastante conveniente.
Xukrao 28/09
1
@Xukaro. Na verdade, dado que já existe uma versão mais flexível e eficiente dessa função e é mencionada em várias outras respostas.
Mad Physicist
10

Você sempre pode usar a multiplicação se não se lembrar imediatamente dos métodos .emptyou .full:

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

Claro que também funciona com qualquer outro valor numérico:

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

Mas a resposta aceita do @ u0b34a0f6ae é 3x mais rápida (ciclos da CPU, não ciclos do cérebro para lembrar a sintaxe 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
fogão
fonte
6

Outra alternativa é numpy.broadcast_to(val,n) que retorna em tempo constante, independentemente do tamanho, e também é a mais eficiente em memória (retorna uma visão do elemento repetido). A ressalva é que o valor retornado é somente leitura.

Abaixo está uma comparação dos desempenhos de todos os outros métodos que foram propostos usando o mesmo benchmark da resposta de Nico Schlömer .

insira a descrição da imagem aqui

Giancarlo Sportelli
fonte
5

Como dito, numpy.empty () é o caminho a percorrer. No entanto, para objetos, fill () pode não fazer exatamente o que você pensa que faz:

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)

Uma maneira de contornar isso pode ser, por exemplo:

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
fonte
Além de praticamente não ter nada a ver com a pergunta original, puro.
May Physicist
1
Bem, trata-se de "Inicializar matriz numpy para algo diferente de zero ou um", no caso "algo outro" é um objeto :) (Na prática, o google me levou aqui para inicializar com uma lista vazia)
ntg
3

Ainda outra possibilidade ainda não mencionada aqui é usar o bloco NumPy:

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

Também dá

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

Eu não sei sobre comparação de velocidade.

JHBonarius
fonte