167 votes

Python pandas : remplir un dataframe ligne par ligne

La simple tâche consistant à ajouter une ligne à un pandas.DataFrame semble être difficile à réaliser. Il y a 3 questions sur stackoverflow à ce sujet, mais aucune ne donne une réponse fonctionnelle.

Voici ce que j'essaie 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 rangées avec un dictionnaire ou un fichier pandas.Series ? Voici diverses 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, cela ne sert qu'à définir des valeurs individuelles dans le cadre de données.

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

Bon, 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 des colonnes avec les valeurs, mais a perdu les étiquettes des lignes.

>>> 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 aussi échoué lamentablement.

Alors comment faites-vous ?

1 votes

Notez qu'il est assez inefficace d'ajouter des données ligne par ligne et pour de grands ensembles de données. Il serait beaucoup plus rapide de charger d'abord les données dans une liste de listes, puis de construire le DataFrame en une seule ligne à l'aide de la commande df = pd.DataFrame(data, columns=header)

0 votes

Pourquoi est-il plus efficace de créer l'ensemble de données dans des listes et de dupliquer l'ensemble de données en mémoire sous la forme d'un DataFrame ? Cela semble très inefficace en termes d'utilisation de la mémoire - et serait probablement un problème pour les très grands ensembles de données.

0 votes

@xApple, je pense que vous avez rencontré le même problème que moi (pendant des jours), où je ne comprenais pas la différence entre Columns et Index - je pensais en termes de tableaux, où ceux-ci pouvaient être en fait row/col ou vice versa, sans différence. Je suis tout à fait d'accord avec vous pour dire que cette théorie de base sur la façon dont le dataframe est censé être utilisé et sur la façon de générer un DF ligne par ligne (typique lors de la lecture de données provenant d'une autre source) est remarquablement peu claire !

122voto

Jeff Points 27612

df['y'] définira une colonne

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

Notez que .ix est équivalent ici, le vôtre a échoué parce que vous avez essayé d'assigner un dictionnaire à chaque élément de la ligne y Ce n'est probablement pas ce que vous voulez ; la conversion en série indique à pandas que vous voulez aligner l'entrée (par exemple, vous n'avez pas besoin de spécifier tous les éléments).

In [6]: import pandas as pd

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

In [8]: df.loc['y'] = pd.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

0 votes

Je vois. Ainsi, le loc de la trame de données définit un attribut __setitem__ qui fait la magie, je suppose.

0 votes

Pouvez-vous construire cela en une seule fois (c'est-à-dire avec les colonnes, l'index et le y) ?

5 votes

Si je peux générer une ligne à la fois, comment puis-je construire le cadre de données de manière optimale ?

101voto

flow Points 1426

Mise à jour : parce que append a été déprécié

df = pd.DataFrame(columns=["firstname", "lastname"])

entry = pd.DataFrame.from_dict({
     "firstname": ["John"],
     "lastname":  ["Johny"]
})

df = pd.concat([df, entry], ignore_index=True)

7 votes

Cela a très bien fonctionné pour moi et j'apprécie le fait que vous ayez explicitement append les données dans le cadre de données.

2 votes

Notez que cette réponse nécessite que le nom de la colonne soit ajouté à chaque ligne. Il en va de même pour la réponse acceptée.

1 votes

Cette méthode fonctionne également si vous ne connaissez pas le nombre de lignes à l'avance.

45voto

Satheesh Points 643

Voici 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>']`

6 votes

Je voudrais juste savoir si ce système est efficace en termes de CPU et de mémoire ?

2 votes

Comment puis-je connaître la dernière ligne de df afin de l'ajouter à la dernière ligne à chaque fois ?

0 votes

Par rapport aux deux autres options de append() (qui duplique éventuellement toute la base de données (que vous réaffectez à elle-même) à chaque itération de la boucle), et l'autre option courante qui consiste à créer deux structures de données identiques (une List et ensuite un DataFrame ) des mêmes données, cela semble beaucoup plus "efficace" en termes d'utilisation de la mémoire, mais la vitesse peut être un tout autre problème.

34voto

Si vos lignes d'entrée sont des listes plutôt que des dictionnaires, la solution suivante est 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

0 votes

Mais que faire si j'ai un index multiple ? df1 = pd.DataFrame(list_of_lists, columns['A', 'B', 'C'], index=['A', 'B']) ne fonctionne pas. Mauvaise forme. Comment faire ?

2voto

Subham Points 125

La logique derrière ce code est assez simple et directe.

Faire un df avec 1 ligne en utilisant le dictionnaire

Ensuite, créez un df de forme (1, 4) qui ne contient que des NaN et possède les mêmes colonnes que les clés du dictionnaire.

Puis concaténer un nan df avec le dict df et ensuite un autre nan df

import pandas as pd
import numpy as np

raw_datav = {'a':1, 'b':5, 'c':2, 'd':3} 

datav_df = pd.DataFrame(raw_datav, index=[0])

nan_df = pd.DataFrame([[np.nan]*4], columns=raw_datav.keys())

df = pd.concat([nan_df, datav_df, nan_df], ignore_index=True)

df.index = ["x", "y", "z"]

print(df)

donne

a    b    c    d
x  NaN  NaN  NaN  NaN
y  1.0  5.0  2.0  3.0
z  NaN  NaN  NaN  NaN

[Program finished]

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X