La bonne façon ™ de créer un DataFrame
TLDR; (il suffit de lire le texte en gras)
La plupart des réponses ici vous diront comment créer un DataFrame vide et le remplir, mais personne ne vous dira que c'est une mauvaise chose à faire.
Voici mon conseil: attendez jusqu'à ce que vous soyez sûr d'avoir toutes les données dont vous avez besoin pour travailler. Utilisez une liste pour collecter vos données, puis initialisez un DataFrame lorsque vous êtes prêt.
data = []
for a, b, c in some_function_that_yields_data():
data.append([a, b, c])
df = pd.DataFrame(data, columns=['A', 'B', 'C'])
Il est toujours moins coûteux d'ajouter à une liste et de créer un DataFrame en une seule fois que de créer un DataFrame vide (ou l'un des NaN) et de l'ajouter encore et encore. Les listes prennent également moins de mémoire et sont une structure de données beaucoup plus légère avec laquelle travailler , ajouter et supprimer (si nécessaire).
L'autre avantage de cette méthode est dtypes
automatiquement déduit (plutôt que de les affecter object
à tous).
Le dernier avantage est que a RangeIndex
est automatiquement créé pour vos données , c'est donc une chose de moins à s'inquiéter (jetez un œil aux pauvres append
et aux loc
méthodes ci-dessous, vous verrez des éléments dans les deux qui nécessitent une gestion appropriée de l'index).
Choses que vous ne devriez PAS faire
append
ou à l' concat
intérieur d'une boucle
Voici la plus grosse erreur que j'ai vue des débutants:
df = pd.DataFrame(columns=['A', 'B', 'C'])
for a, b, c in some_function_that_yields_data():
df = df.append({'A': i, 'B': b, 'C': c}, ignore_index=True) # yuck
# or similarly,
# df = pd.concat([df, pd.Series({'A': i, 'B': b, 'C': c})], ignore_index=True)
La mémoire est réattribuée pour chaque append
ou concat
opération que vous avez. Ajoutez à cela une boucle et vous aurez une opération de complexité quadratique . Depuis la df.append
page doc :
L'ajout itératif de lignes à un DataFrame peut nécessiter plus de calculs qu'un simple concaténé. Une meilleure solution consiste à ajouter ces lignes à une liste, puis à concaténer la liste avec le DataFrame d'origine à la fois.
L'autre erreur associée df.append
est que les utilisateurs ont tendance à oublier que l' ajout n'est pas une fonction sur place , donc le résultat doit être attribué à nouveau. Vous devez également vous soucier des dtypes:
df = pd.DataFrame(columns=['A', 'B', 'C'])
df = df.append({'A': 1, 'B': 12.3, 'C': 'xyz'}, ignore_index=True)
df.dtypes
A object # yuck!
B float64
C object
dtype: object
Traiter des colonnes d'objets n'est jamais une bonne chose, car les pandas ne peuvent pas vectoriser les opérations sur ces colonnes. Vous devrez le faire pour le réparer:
df.infer_objects().dtypes
A int64
B float64
C object
dtype: object
loc
à l'intérieur d'une boucle
J'ai également vu loc
utilisé pour ajouter à un DataFrame créé vide:
df = pd.DataFrame(columns=['A', 'B', 'C'])
for a, b, c in some_function_that_yields_data():
df.loc[len(df)] = [a, b, c]
Comme précédemment, vous n'avez pas pré-alloué la quantité de mémoire dont vous avez besoin à chaque fois, donc la mémoire est agrandie chaque fois que vous créez une nouvelle ligne . C'est aussi mauvais queappend
et encore plus laid.
Cadre de données vide de NaNs
Et puis, il y a la création d'un DataFrame de NaNs, et toutes les mises en garde qui y sont associées.
df = pd.DataFrame(columns=['A', 'B', 'C'], index=range(5))
df
A B C
0 NaN NaN NaN
1 NaN NaN NaN
2 NaN NaN NaN
3 NaN NaN NaN
4 NaN NaN NaN
Il crée un DataFrame de colonnes d'objets, comme les autres.
df.dtypes
A object # you DON'T want this
B object
C object
dtype: object
L'ajout a toujours tous les problèmes comme les méthodes ci-dessus.
for i, (a, b, c) in enumerate(some_function_that_yields_data()):
df.iloc[i] = [a, b, c]
La preuve est dans le pudding
La synchronisation de ces méthodes est le moyen le plus rapide de voir à quel point elles diffèrent en termes de mémoire et d'utilité.
Code de référence pour référence.