Pandas Python: remplissez un dataframe ligne par ligne

133

La simple tâche d'ajouter une ligne à un pandas.DataFrameobjet semble être difficile à accomplir. Il y a 3 questions de stackoverflow liées à cela, dont aucune ne donne de réponse fonctionnelle.

Voici ce que j'essaye de faire. J'ai un DataFrame dont je connais déjà la forme ainsi que les noms des lignes et des colonnes.

>>> 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

Maintenant, j'ai une fonction pour calculer les valeurs des lignes de manière itérative. Comment puis-je remplir l'une des lignes avec un dictionnaire ou un pandas.Series? Voici différentes tentatives qui ont échoué:

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

Apparemment, il a essayé d'ajouter une colonne au lieu d'une ligne.

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

Message d'erreur très peu informatif.

>>> 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)

Apparemment, ce n'est que pour définir des valeurs individuelles dans le dataframe.

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

Eh bien, je ne veux pas ignorer l'index, sinon voici le résultat:

>>> 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

Il a aligné les noms de colonne avec les valeurs, mais a perdu les étiquettes de ligne.

>>> 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

Cela a également échoué lamentablement.

Alors, comment faites-vous cela?

xApple
la source

Réponses:

92

df['y'] va définir une colonne

puisque vous souhaitez définir une ligne, utilisez .loc

Notez que .ixc'est équivalent ici, le vôtre a échoué car vous avez essayé d'assigner un dictionnaire à chaque élément de la ligne yprobablement pas ce que vous vouliez; la conversion en série indique aux pandas que vous souhaitez aligner l'entrée (par exemple, vous n'avez pas à spécifier tous les éléments)

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
la source
Je vois. Donc, l' locattribut de la trame de données définit un spécial __setitem__qui fait la magie je suppose.
xApple
Pouvez-vous construire cela en un seul passage (c'est-à-dire avec des colonnes, un index et y)?
Andy Hayden
5
Donc, si je peux générer une ligne à la fois, comment pourrais-je construire le bloc de données de manière optimale?
xApple
Vous attendiez-vous à ce qu'une variante de df = pd.DataFrame({'y': pd.Series(y)}, columns=['a','b','c','d'], index=['x','y','z'])fonctionne?
Andy Hayden
@xApple prob le mieux pour vous de construire une liste de dictionnaires (ou liste), puis de passer simplement au constructeur, sera beaucoup plus efficace
Jeff
71

Mon approche était, mais je ne peux pas garantir que ce soit la solution la plus rapide.

df = pd.DataFrame(columns=["firstname", "lastname"])
df = df.append({
     "firstname": "John",
     "lastname":  "Johny"
      }, ignore_index=True)
couler
la source
4
Cela a fonctionné à merveille pour moi et j'aime le fait que vous appendintégriez explicitement les données au dataframe.
Jonny Brooks
1
Notez que cette réponse nécessite que chaque ligne ait le nom de colonne ajouté. Idem pour la réponse acceptée.
pashute
Cela fonctionne aussi si vous ne connaissez pas le nombre de lignes à l'avance.
irene
34

Ceci est une version plus simple

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
la source
4
Je veux juste demander, ce processeur et cette mémoire sont-ils efficaces?
czxttkl
1
Comment puis-je connaître la dernière ligne de df pour que j'ajoute à la dernière ligne à chaque fois?
pashute
25

Si vos lignes d'entrée sont des listes plutôt que des dictionnaires, voici une solution simple:

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
la source
mais que dois-je faire si j'ai un index multi? df1 = pd.DataFrame (list_of_lists, colonnes ['A', 'B', 'C'], index = ['A', 'B']) ne fonctionne pas. Mauvaise forme. Alors comment?
pashute