Python pandas inserir lista em uma célula

105

Eu tenho uma lista 'abc' e um dataframe 'df':

abc = ['foo', 'bar']
df =
    A  B
0  12  NaN
1  23  NaN

Quero inserir a lista na célula 1B, então quero este resultado:

    A  B
0  12  NaN
1  23  ['foo', 'bar']

Como posso fazer isso?

1) Se eu usar isso:

df.ix[1,'B'] = abc

Eu recebi a seguinte mensagem de erro:

ValueError: Must have equal len keys and value when setting with an iterable

porque tenta inserir a lista (que tem dois elementos) em uma linha / coluna, mas não em uma célula.

2) Se eu usar isso:

df.ix[1,'B'] = [abc]

em seguida, ele insere uma lista que possui apenas um elemento que é a lista 'abc' ( [['foo', 'bar']]).

3) Se eu usar isso:

df.ix[1,'B'] = ', '.join(abc)

então ele insere uma string: ( foo, bar) mas não uma lista.

4) Se eu usar isso:

df.ix[1,'B'] = [', '.join(abc)]

em seguida, insere uma lista, mas tem apenas um elemento ( ['foo, bar']), mas não dois como eu quero ( ['foo', 'bar']).

Obrigado pela ajuda!


EDITAR

Meu novo dataframe e a lista antiga:

abc = ['foo', 'bar']
df2 =
    A    B         C
0  12  NaN      'bla'
1  23  NaN  'bla bla'

Outro dataframe:

df3 =
    A    B         C                    D
0  12  NaN      'bla'  ['item1', 'item2']
1  23  NaN  'bla bla'        [11, 12, 13]

Desejo inserir a lista 'abc' em df2.loc[1,'B']e / ou df3.loc[1,'B'].

Se o dataframe tiver colunas apenas com valores inteiros e / ou valores NaN e / ou valores de lista, inserir uma lista em uma célula funciona perfeitamente. Se o dataframe tiver colunas apenas com valores de string e / ou valores NaN e / ou valores de lista, inserir uma lista em uma célula funciona perfeitamente. Mas se o dataframe tiver colunas com valores inteiros e de string e outras colunas, a mensagem de erro aparecerá se eu usar isto: df2.loc[1,'B'] = abcou df3.loc[1,'B'] = abc.

Outro dataframe:

df4 =
          A     B
0      'bla'  NaN
1  'bla bla'  NaN

Essas inserções funcionam perfeitamente: df.loc[1,'B'] = abcou df4.loc[1,'B'] = abc.

Ragesz
fonte
1
Qual versão do pandas você está usando? o seguinte funcionou usando pandas 0.15.0:df.loc[1,'b'] = ['foo','bar']
EdChum
Obrigado! Eu uso Python 2.7 e tentei pandas 0.14.0 e 0.15.0 e funcionou com os dados de teste acima. Mas e se eu também tiver uma coluna 'C' com alguns valores inteiros? 'A' tem cordas. Tendo uma coluna inteira e uma coluna srting, recebo o mesmo erro: ValueError: Deve ter chaves len iguais e valor ao definir com um iterável
ragesz
Você vai ter que postar dados e código para explicar e mostrar o que você quer dizer
EdChum

Respostas:

119

set_valueque está obsoleto desde a versão 0.21.0, você deve usar agora at. Ele pode inserir uma lista em uma célula sem gerar um ValueErrorcomo o locfaz. Acho que isso ocorre porque at sempre se refere a um único valor, enquanto locpode se referir a valores, bem como linhas e colunas.

df = pd.DataFrame(data={'A': [1, 2, 3], 'B': ['x', 'y', 'z']})

df.at[1, 'B'] = ['m', 'n']

df =
    A   B
0   1   x
1   2   [m, n]
2   3   z

Você também precisa ter certeza de que a coluna na qual está inserindo tem dtype=object. Por exemplo

>>> df = pd.DataFrame(data={'A': [1, 2, 3], 'B': [1,2,3]})
>>> df.dtypes
A    int64
B    int64
dtype: object

>>> df.at[1, 'B'] = [1, 2, 3]
ValueError: setting an array element with a sequence

>>> df['B'] = df['B'].astype('object')
>>> df.at[1, 'B'] = [1, 2, 3]
>>> df
   A          B
0  1          1
1  2  [1, 2, 3]
2  3          3
Michael Hays
fonte
4
Eu tive que ter certeza de que o dtype do dataframe original foi definido como objeto para que isso funcionasse:df = pd.DataFrame(data, dtype=object)
Takver
2
precisa de um índice. Como me refiro à linha usando outra correspondência de valor de atributo; por exemplo: para a linha com A = 2 no exemplo acima?
bikashg de
8
Isso retorna outro erro ValueError: setting an array element with a sequence.; veja uma resposta por @ cs95 se obtiver o erro.
Blaszard
39

df3.set_value(1, 'B', abc)funciona para qualquer dataframe. Tome cuidado com o tipo de dados da coluna 'B'. Por exemplo. uma lista não pode ser inserida em uma coluna flutuante, nesse caso df['B'] = df['B'].astype(object)pode ajudar.

Ragesz
fonte
6
Observe que este comando está obsoleto . Há uma atualização logo abaixo.
Thomas
35

Pandas> = 0,21

set_valuefoi descontinuado. Agora você pode usar DataFrame.atpara definir por rótulo e DataFrame.iatpara definir por posição inteira.

Definir valores de células com at/iat

# Setup
df = pd.DataFrame({'A': [12, 23], 'B': [['a', 'b'], ['c', 'd']]})
df

    A       B
0  12  [a, b]
1  23  [c, d]

df.dtypes

A     int64
B    object
dtype: object

Se você quiser definir um valor na segunda linha do "B" para alguma nova lista, use DataFrane.at:

df.at[1, 'B'] = ['m', 'n']
df

    A       B
0  12  [a, b]
1  23  [m, n]

Você também pode definir por posição inteira usando DataFrame.iat

df.iat[1, df.columns.get_loc('B')] = ['m', 'n']
df

    A       B
0  12  [a, b]
1  23  [m, n]

E se eu conseguir ValueError: setting an array element with a sequence?

Vou tentar reproduzir isso com:

df

    A   B
0  12 NaN
1  23 NaN

df.dtypes

A      int64
B    float64
dtype: object

df.at[1, 'B'] = ['m', 'n']
# ValueError: setting an array element with a sequence.

Isso ocorre porque o seu objeto é do tipo float64d, enquanto as listas são objects, então há uma incompatibilidade aí. O que você teria que fazer nessa situação é converter a coluna em objeto primeiro.

df['B'] = df['B'].astype(object)
df.dtypes

A     int64
B    object
dtype: object

Então, funciona:

df.at[1, 'B'] = ['m', 'n']
df

    A       B
0  12     NaN
1  23  [m, n]

Possível, mas Hacky

Ainda mais maluco, descobri que você pode hackear DataFrame.locpara conseguir algo semelhante se passar em listas aninhadas.

df.loc[1, 'B'] = [['m'], ['n'], ['o'], ['p']]
df

    A             B
0  12        [a, b]
1  23  [m, n, o, p]

Você pode ler mais sobre por que isso funciona aqui.

cs95
fonte
2

Solução rápida

Simplesmente coloque a lista dentro de uma nova lista, como feito para col2 no quadro de dados abaixo. A razão de funcionar é que o python pega a lista externa (de listas) e a converte em uma coluna como se ela contivesse itens escalares normais, que são listas em nosso caso e não escalares normais.

mydict={'col1':[1,2,3],'col2':[[1, 4], [2, 5], [3, 6]]}
data=pd.DataFrame(mydict)
data


   col1     col2
0   1       [1, 4]
1   2       [2, 5]
2   3       [3, 6]
Pallavi Jindal
fonte
0

Também recebendo

ValueError: Must have equal len keys and value when setting with an iterable,

usar .at em vez de .loc não fez nenhuma diferença no meu caso, mas impor o tipo de dados da coluna do dataframe funcionou:

df['B'] = df['B'].astype(object)

Então eu poderia definir listas, matrizes numpy e todos os tipos de coisas como valores de uma única célula em meus dataframes.

Maxime Beau
fonte