Pandas Python: preencher um quadro de dados linha por linha

133

A tarefa simples de adicionar uma linha a um pandas.DataFrameobjeto parece ser difícil de realizar. Existem três perguntas sobre o stackoverflow relacionadas a isso, nenhuma das quais fornece uma resposta útil.

Aqui está o que estou tentando fazer. Eu tenho um DataFrame do qual eu já conheço a forma e os nomes das linhas e colunas.

>>> df = pandas.DataFrame(columns=['a','b','c','d'], index=['x','y','z'])
>>> df
     a    b    c    d
x  NaN  NaN  NaN  NaN
y  NaN  NaN  NaN  NaN
z  NaN  NaN  NaN  NaN

Agora, tenho uma função para calcular os valores das linhas iterativamente. Como posso preencher uma das linhas com um dicionário ou um pandas.Series? Aqui estão várias tentativas que falharam:

>>> y = {'a':1, 'b':5, 'c':2, 'd':3} 
>>> df['y'] = y
AssertionError: Length of values does not match length of index

Aparentemente, ele tentou adicionar uma coluna em vez de uma linha.

>>> y = {'a':1, 'b':5, 'c':2, 'd':3} 
>>> df.join(y)
AttributeError: 'builtin_function_or_method' object has no attribute 'is_unique'

Mensagem de erro muito pouco informativa.

>>> y = {'a':1, 'b':5, 'c':2, 'd':3} 
>>> df.set_value(index='y', value=y)
TypeError: set_value() takes exactly 4 arguments (3 given)

Aparentemente, isso é apenas para definir valores individuais no quadro de dados.

>>> y = {'a':1, 'b':5, 'c':2, 'd':3} 
>>> df.append(y)
Exception: Can only append a Series if ignore_index=True

Bem, eu não quero ignorar o índice, caso contrário, aqui está o resultado:

>>> df.append(y, ignore_index=True)
     a    b    c    d
0  NaN  NaN  NaN  NaN
1  NaN  NaN  NaN  NaN
2  NaN  NaN  NaN  NaN
3    1    5    2    3

Alinhou os nomes das colunas com os valores, mas perdeu os rótulos das linhas.

>>> y = {'a':1, 'b':5, 'c':2, 'd':3} 
>>> df.ix['y'] = y
>>> df
                                  a                                 b  \
x                               NaN                               NaN
y  {'a': 1, 'c': 2, 'b': 5, 'd': 3}  {'a': 1, 'c': 2, 'b': 5, 'd': 3}
z                               NaN                               NaN

                                  c                                 d
x                               NaN                               NaN
y  {'a': 1, 'c': 2, 'b': 5, 'd': 3}  {'a': 1, 'c': 2, 'b': 5, 'd': 3}
z                               NaN                               NaN

Isso também falhou miseravelmente.

Então como você faz isso ?

xApple
fonte

Respostas:

92

df['y'] irá definir uma coluna

desde que você deseja definir uma linha, use .loc

Observe que .ixaqui é equivalente, o seu falhou porque você tentou atribuir um dicionário a cada elemento da linha, yprovavelmente não o que você deseja; a conversão para uma série informa aos pandas que você deseja alinhar a entrada (por exemplo, você não precisa especificar todos os elementos)

In [7]: df = pandas.DataFrame(columns=['a','b','c','d'], index=['x','y','z'])

In [8]: df.loc['y'] = pandas.Series({'a':1, 'b':5, 'c':2, 'd':3})

In [9]: df
Out[9]: 
     a    b    c    d
x  NaN  NaN  NaN  NaN
y    1    5    2    3
z  NaN  NaN  NaN  NaN
Jeff
fonte
Entendo. Portanto, o locatributo do quadro de dados define um especial __setitem__que faz a mágica que eu suponho.
XApple
Você pode construir isso de uma só vez (ou seja, com colunas, índice ey)?
Andy Hayden
5
Portanto, se eu posso gerar uma linha por vez, como construiria o quadro de dados de maneira ideal?
XApple
Estava esperando alguma variante de df = pd.DataFrame({'y': pd.Series(y)}, columns=['a','b','c','d'], index=['x','y','z'])funcionar?
Andy Hayden
@xApple prov melhor para você construir uma lista de dicts (ou lista), em seguida, basta passar para o construtor, será muito mais eficiente
Jeff
71

Minha abordagem foi, mas não posso garantir que esta seja a solução mais rápida.

df = pd.DataFrame(columns=["firstname", "lastname"])
df = df.append({
     "firstname": "John",
     "lastname":  "Johny"
      }, ignore_index=True)
fluxo
fonte
4
Isso funcionou de maneira brilhante para mim e eu gosto do fato de você explicitamente appendos dados no quadro de dados.
Jonny Brooks
1
Observe que esta resposta precisa que cada linha tenha o nome da coluna anexado. O mesmo para a resposta aceita.
Pashute
Isso funciona também se você não souber o número de linhas com antecedência.
irene 26/05
34

Esta é uma versão mais simples

import pandas as pd
df = pd.DataFrame(columns=('col1', 'col2', 'col3'))
for i in range(5):
   df.loc[i] = ['<some value for first>','<some value for second>','<some value for third>']`
Satheesh
fonte
4
só quero perguntar, essa CPU e memória são eficientes?
Czxttkl
1
como eu sei a última linha do df, então eu anexo à última linha de cada vez?
Pashute
25

Se suas linhas de entrada são listas e não dicionários, a seguir é uma solução simples:

import pandas as pd
list_of_lists = []
list_of_lists.append([1,2,3])
list_of_lists.append([4,5,6])

pd.DataFrame(list_of_lists, columns=['A', 'B', 'C'])
#    A  B  C
# 0  1  2  3
# 1  4  5  6
stackoverflowuser2010
fonte
mas o que faço se tiver um índice múltiplo? df1 = pd.DataFrame (lista_de_listas, colunas ['A', 'B', 'C']], índice = ['A', 'B']) não funciona. Forma errada. Então como?
Pashute