Eu tenho um DataFrame pandas onde cada célula contém um dict Python.
>>> data = {"Q":{"X":{2:2010}, "Y":{2:2011, 3:2009}},"R":{"X":{1:2013}}}
>>> frame = DataFrame(data)
>>> frame
Q R
X {2: 2010} {1: 2013}
Y {2: 2011, 3: 2009} NaN
Eu gostaria de substituir o NaN com um dict vazio, para obter este resultado:
Q R
X {2: 2010} {1: 2013}
Y {2: 2011, 3: 2009} {}
No entanto, porque o fillna
A função interpreta empty dict não como um valor escalar, mas como um mapeamento de column -> value, não faz NADA se eu simplesmente fizer isso (ou seja, não funciona):
>>> frame.fillna(inplace=True, value={})
Q R
X {2: 2010} {1: 2013}
Y {2: 2011, 3: 2009} NaN
Existe alguma maneira de usar fillna
para realizar o que eu quero? Eu tenho que percorrer todo o DataFrame ou construir um dict bobo com todas as minhas colunas mapeadas para empty dict?
Respostas:
5 para resposta № 1Consegui usar DataFrame.applymap
nesse caminho:
>>> from pandas import isnull
>>> frame=frame.applymap(lambda x: {} if isnull(x) else x)
>>> frame
Q R
X {2: 2010} {1: 2013}
Y {2: 2011, 3: 2009} {}
Esta solução evita as armadilhas em ambosSolução de EdChum (onde todas as células NaN acabam apontando para o mesmo objeto dict subjacente na memória, evitando que sejam atualizadas independentemente umas das outras) e Shashank (onde uma estrutura de dados potencialmente grande precisa ser construída com dicts aninhados, apenas para especificar um único valor de dit vazio).
2 para resposta № 2
O problema é que quando um dict é passado para fillna
, ele tenta preencher os valores com base nas colunas no quadro. Então a primeira solução que tentei foi -
frame.fillna({column: {} for column in frame.columns})
Mas se um dicionário é fornecido no segundo nível como este, ele tenta combinar as chaves com o índice, então a solução que funcionou foi -
frame.fillna({column: {ind: {} for ind in frame.index} for column in frame.columns})
Que dá -
Q R
X {2: 2010} {1: 2013}
Y {2: 2011, 3: 2009} {}
A resposta do EdChum provavelmente é melhor para as suas necessidades, mas isso pode ser usado quando você não quer fazer alterações no lugar.
EDIT: A solução acima funciona bem para quadros menores, mas pode ser um problema para quadros maiores. Usando replace
pode resolver isso.
frame.replace(np.nan, {column: {} for column in frame.columns})
1 para resposta № 3
Isso funciona usando loc
:
In [6]:
frame.loc[frame["R"].isnull(), "R"] = {}
frame
Out[6]:
Q R
X {2: 2010} {1: 2013}
Y {2: 2011, 3: 2009} {}
0 para a resposta № 4
Usar .values
acessor para atribuir em matriz numpy diretamente:
frame.R = frame.R.astype(object) # assertion
frame.R.values[frame.R.isnull()] = {}