Ambos os exemplos abaixo falham com o mesmo erro
df = pd.DataFrame(index=[0, 1, 2], columns=['a', 'b'])
df.loc[0, 'a'] = dict(x=2)
df.iloc[0, 0] = dict(x=2)
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-282-62f3ee5ff885> in <module>()
1 # file_map.loc[file_no, 'Q_step_length'] = dict(a=1)
2 df = pd.DataFrame(index=[0, 1, 2], columns=['a', 'b'])
----> 3 df.iloc[0, 0] = dict(x=2)
4 df['a'] = df['a'].apply(lambda x: x[0] if not pd.isnull(x) else x)
5 df
...\lib\site-packages\pandas\core\indexing.py in __setitem__(self, key, value)
177 key = com._apply_if_callable(key, self.obj)
178 indexer = self._get_setitem_indexer(key)
--> 179 self._setitem_with_indexer(indexer, value)
180
181 def _has_valid_type(self, k, axis):
...\lib\site-packages\pandas\core\indexing.py in _setitem_with_indexer(self, indexer, value)
603
604 if isinstance(value, (ABCSeries, dict)):
--> 605 value = self._align_series(indexer, Series(value))
606
607 elif isinstance(value, ABCDataFrame):
...\lib\site-packages\pandas\core\indexing.py in _align_series(self, indexer, ser, multiindex_indexer)
743 return ser.reindex(ax)._values
744
--> 745 raise ValueError('Incompatible indexer with Series')
746
747 def _align_frame(self, indexer, df):
ValueError: Incompatible indexer with Series
Isso funciona, mas está colocando uma lista no dataframe
df[0, 'a'] = [dict(x=2)]
É possível obter o dict diretamente no dataframe usando uma construção muito deselegante como esta:
df['a'] = df['a'].apply(lambda x: x[0] if not pd.isnull(x) else x)
Como é possível armazenar um dict em um dataframe, tentar uma atribuição como acima não deve falhar. Estou ciente de que df.loc[...] = dict(...) atribuirá valores no dict às colunas correspondentes se houver (isso está documentado?) e tem seus próprios problemas, mas esse comportamento não deve se aplicar ao acessar um único local do dataframe
Um dataframe com um dict dentro do local especificado.
pd.show_versions()
compromisso: Nenhum
python: 3.5.4.final.0
bits python: 64
SO: Windows
Versão do SO: 10
máquina: AMD64
processador: Intel64 Family 6 Model 58 Stepping 9, GenuineIntel
byteorder: pouco
LC_ALL: Nenhum
LAN: Nenhum
LOCAL: Nenhum. Nenhum
pandas: 0,20,3
pytest: Nenhum
pip: 9.0.1
ferramentas de configuração: 36.5.0
Cíton: 0,26
numpy: 1.13.1
scip: 0.19.1
xarray: Nenhum
IPython: 6.1.0
esfinge: nenhuma
paty: 0.4.1
dateutil: 2.6.1
pytz: 2017.2
bloco: Nenhum
gargalo: nenhum
tabelas: Nenhuma
numexpr: Nenhum
pena: nenhuma
matplotlib: 2.0.2
openpyxl: Nenhum
xlrd: Nenhum
xlwt: Nenhum
xlsxwriter: Nenhum
lxml: Nenhum
bs4: Nenhum
html5lib: 0,9999999
sqlalchemy: Nenhum
pymysql: Nenhum
psycopg2: Nenhum
jinja2: 2.9.6
s3fs: Nenhum
pandas_gbq: Nenhum
pandas_datareader: Nenhum
isso é bastante não-idiomático, e você está praticamente sozinho aqui. você poderia fazer isso apenas usando uma lista/tupla em torno dele
In [14]: df.loc[0, 'a'] = [dict(x=2)]
In [15]: df
Out[15]:
a b
0 [{'x': 2}] NaN
1 NaN NaN
2 NaN NaN
Encontrou o mesmo problema, teve dois pensamentos:
Armazenar um dict dentro de um DataFrame é incomum, mas há casos válidos em que o software pode estar usando Pandas como uma maneira de representar e manipular dados de estilo de chave/valor arbitrário onde os dados são indexados de uma maneira que faça sentido para a representação em painel.
O comportamento de que a indexação baseada em localização atualizará as colunas com base nas chaves/valores de um dicionário fornecido foi uma surpresa para mim. Este é um recurso de conveniência interessante que faz sentido quando uma coluna explícita não é referenciada. Por exemplo, ao fornecer:
df.loc[row, :] = dict(key1=value1, key2=value2)
Faz sentido que as chaves do dicionário possam ser escritas como colunas e que df.loc[row, key1] == value1
. No entanto, ao fornecer um índice de coluna explícito, inferir as colunas de destino de um dicionário fornecido é (para mim) contra-intuitivo. Se em vez disso eu fornecer:
df.loc[row, col] = dict(key=value)
Estou denotando explicitamente que quero armazenar o valor inteiro na coluna col
e espero que o dicionário seja inserido como está.
De qualquer forma, concordo com @jreback que isso é um pouco não idiomático, MAS sou solidário com a questão original levantada por @andreas-thomik. Eu encontrei um problema em que tentar armazenar um dict em um elemento de um dataframe usando essa sintaxe fazia sentido para o problema específico que eu estava enfrentando, então ele não está totalmente sozinho com essa solicitação.
@aaclayton isso está relacionado a #18955 . Poderíamos/deveríamos suportar melhor a configuração de escalares de dicts (e outros iteráveis). É um pouco complicado embora.
Comentários muito úteis
Encontrou o mesmo problema, teve dois pensamentos:
Armazenar um dict dentro de um DataFrame é incomum, mas há casos válidos em que o software pode estar usando Pandas como uma maneira de representar e manipular dados de estilo de chave/valor arbitrário onde os dados são indexados de uma maneira que faça sentido para a representação em painel.
O comportamento de que a indexação baseada em localização atualizará as colunas com base nas chaves/valores de um dicionário fornecido foi uma surpresa para mim. Este é um recurso de conveniência interessante que faz sentido quando uma coluna explícita não é referenciada. Por exemplo, ao fornecer:
df.loc[row, :] = dict(key1=value1, key2=value2)
Faz sentido que as chaves do dicionário possam ser escritas como colunas e que
df.loc[row, key1] == value1
. No entanto, ao fornecer um índice de coluna explícito, inferir as colunas de destino de um dicionário fornecido é (para mim) contra-intuitivo. Se em vez disso eu fornecer:df.loc[row, col] = dict(key=value)
Estou denotando explicitamente que quero armazenar o valor inteiro na coluna
col
e espero que o dicionário seja inserido como está.De qualquer forma, concordo com @jreback que isso é um pouco não idiomático, MAS sou solidário com a questão original levantada por @andreas-thomik. Eu encontrei um problema em que tentar armazenar um dict em um elemento de um dataframe usando essa sintaxe fazia sentido para o problema específico que eu estava enfrentando, então ele não está totalmente sozinho com essa solicitação.