Insérer une ligne dans le cadre de données pandas

112

J'ai un dataframe:

s1 = pd.Series([5, 6, 7])
s2 = pd.Series([7, 8, 9])

df = pd.DataFrame([list(s1), list(s2)],  columns =  ["A", "B", "C"])

   A  B  C
0  5  6  7
1  7  8  9

[2 rows x 3 columns]

et je dois ajouter une première ligne [2, 3, 4] pour obtenir:

   A  B  C
0  2  3  4
1  5  6  7
2  7  8  9

J'ai essayé append()et concat()fonctionne mais je ne trouve pas la bonne façon de le faire.

Comment ajouter / insérer des séries dans dataframe?

Meloun
la source
6
notez qu'il est préférable d'utiliser s1.valuesplutôt list(s1)que de créer une liste entièrement nouvelle en utilisant list(s1).
acushner
7
Je ne comprends pas pourquoi tout le monde aime tant les pandas alors que quelque chose qui devrait être si simple est une telle douleur dans le cul et si lent.
MattCochrane

Réponses:

145

Attribuez simplement une ligne à un index particulier, en utilisant loc:

 df.loc[-1] = [2, 3, 4]  # adding a row
 df.index = df.index + 1  # shifting index
 df = df.sort_index()  # sorting by index

Et vous obtenez, comme vous le souhaitez:

    A  B  C
 0  2  3  4
 1  5  6  7
 2  7  8  9

Voir dans la documentation Pandas Indexation: Réglage avec agrandissement .

Piotr Migdal
la source
2
Si vous ne voulez pas définir avec l'agrandissement, mais insérez à l'intérieur du dataframe, jetez un œil à stackoverflow.com/questions/15888648
...
6
alternative d'index de décalage: df.sort (). reset_index (drop = True)
Meloun
2
df.sort est obsolète, utilisez df.sort_index ()
GBGOLC
1
@Piotr - cela fonctionne très bien, mais que se passe-t-il lorsque vous souhaitez dupliquer une ligne de votre bloc de données, par exemple df.loc[-1] = df.iloc[[0]], et l'insérer? Le cadre est livré avec une colonne d'index supplémentaire donnant une erreur ValueError: cannot set a row with mismatched columns (voir stackoverflow.com/questions/47340571/… )
Growler
5
Je pense que df.loc[-1] = [2, 3, 4] # adding a rowc'est un peu trompeur, -1pas plus que la dernière ligne / élément, comme c'est le cas pour les tableaux Python.
flow2k
26

Je ne sais pas comment vous appeliez, concat()mais cela devrait fonctionner tant que les deux objets sont du même type. Peut-être que le problème est que vous devez convertir votre deuxième vecteur dans une trame de données? L'utilisation du df que vous avez défini fonctionne pour moi:

df2 = pd.DataFrame([[2,3,4]], columns=['A','B','C'])
pd.concat([df2, df])
mgilbert
la source
Meilleure réponse ^ :)
Cam.Davidson.Pilon
23

Une façon d'y parvenir est

>>> pd.DataFrame(np.array([[2, 3, 4]]), columns=['A', 'B', 'C']).append(df, ignore_index=True)
Out[330]: 
   A  B  C
0  2  3  4
1  5  6  7
2  7  8  9

En général, il est plus facile d'ajouter des dataframes, pas des séries. Dans votre cas, puisque vous voulez que la nouvelle ligne soit "en haut" (avec l'identifiant de départ), et qu'il n'y a pas de fonction pd.prepend(), je crée d'abord la nouvelle dataframe, puis j'ajoute l'ancienne.

ignore_indexignorera l'ancien index en cours dans votre dataframe et s'assurera que la première ligne commence réellement par index 1au lieu de redémarrer avec index 0.

Avertissement typique: Cetero censeo ... l'ajout de lignes est une opération assez inefficace. Si vous vous souciez des performances et que vous pouvez en quelque sorte vous assurer de créer d'abord un dataframe avec l'index correct (plus long), puis d' insérer simplement la ligne supplémentaire dans le dataframe, vous devez absolument le faire. Voir:

>>> index = np.array([0, 1, 2])
>>> df2 = pd.DataFrame(columns=['A', 'B', 'C'], index=index)
>>> df2.loc[0:1] = [list(s1), list(s2)]
>>> df2
Out[336]: 
     A    B    C
0    5    6    7
1    7    8    9
2  NaN  NaN  NaN
>>> df2 = pd.DataFrame(columns=['A', 'B', 'C'], index=index)
>>> df2.loc[1:] = [list(s1), list(s2)]

Jusqu'à présent, nous avons ce que vous aviez comme df:

>>> df2
Out[339]: 
     A    B    C
0  NaN  NaN  NaN
1    5    6    7
2    7    8    9

Mais maintenant, vous pouvez facilement insérer la ligne comme suit. Puisque l'espace a été préalloué, c'est plus efficace.

>>> df2.loc[0] = np.array([2, 3, 4])
>>> df2
Out[341]: 
   A  B  C
0  2  3  4
1  5  6  7
2  7  8  9
FooBar
la source
C'est une belle solution de contournement, j'essayais d'insérer des séries dans le dataframe. C'est assez bien pour moi pour le moment.
Meloun
J'aime le plus la dernière option. Cela correspond vraiment à ce que je veux vraiment faire. Merci @FooBar!
Jade Cacho
13

J'ai mis en place une fonction courte qui permet un peu plus de flexibilité lors de l'insertion d'une ligne:

def insert_row(idx, df, df_insert):
    dfA = df.iloc[:idx, ]
    dfB = df.iloc[idx:, ]

    df = dfA.append(df_insert).append(dfB).reset_index(drop = True)

    return df

qui pourrait être abrégé en:

def insert_row(idx, df, df_insert):
    return df.iloc[:idx, ].append(df_insert).append(df.iloc[idx:, ]).reset_index(drop = True)

Ensuite, vous pouvez utiliser quelque chose comme:

df = insert_row(2, df, df_new)

2est la position d'index à l' dfendroit où vous souhaitez insérer df_new.

elPasteur
la source
7

Nous pouvons utiliser numpy.insert. Cela présente l'avantage de la flexibilité. Il vous suffit de spécifier l'index dans lequel vous souhaitez insérer.

s1 = pd.Series([5, 6, 7])
s2 = pd.Series([7, 8, 9])

df = pd.DataFrame([list(s1), list(s2)],  columns =  ["A", "B", "C"])

pd.DataFrame(np.insert(df.values, 0, values=[2, 3, 4], axis=0))

    0   1   2
0   2   3   4
1   5   6   7
2   7   8   9

Pour np.insert(df.values, 0, values=[2, 3, 4], axis=0), 0 indique à la fonction l'emplacement / l'index dans lequel vous souhaitez placer les nouvelles valeurs.

Tai
la source
6

cela peut sembler trop simple mais c'est incroyable qu'une simple fonction d'insertion de nouvelle ligne ne soit pas intégrée. J'ai beaucoup lu sur l'ajout d'un nouveau df à l'original, mais je me demande si ce serait plus rapide.

df.loc[0] = [row1data, blah...]
i = len(df) + 1
df.loc[i] = [row2data, blah...]
Aaron Melgar
la source
Vouliez-vous dire "ajouter un nouveau df" ou simplement "ajouter une nouvelle ligne", comme le montre votre code?
smci
désolé ma phrase n'était pas claire. J'ai lu d'autres solutions de personnes qui concatent / ajoutent un tout nouveau dataframe avec une seule ligne. mais dans ma solution, il ne s'agit que d'une seule ligne dans le dataframe existant, pas besoin de créer un dataframe supplémentaire
Aaron Melgar
6

Vous trouverez ci-dessous le meilleur moyen d'insérer une ligne dans le cadre de données pandas sans trier et réinitialiser un index:

import pandas as pd

df = pd.DataFrame(columns=['a','b','c'])

def insert(df, row):
    insert_loc = df.index.max()

    if pd.isna(insert_loc):
        df.loc[0] = row
    else:
        df.loc[insert_loc + 1] = row

insert(df,[2,3,4])
insert(df,[8,9,0])
print(df)
Sagar Rathod
la source
pourquoi diriez-vous que c'est la meilleure façon?
Yuca
alors ce serait bien de fournir des preuves à l'appui de cette affirmation, avez-vous temps?
Yuca
1
vous pouvez utiliser pd.isna pour éviter d'importer numpy
kato2
2

Il est assez simple d'ajouter une ligne dans un pandas DataFrame:

  1. Créez un dictionnaire Python régulier avec les mêmes noms de colonnes que votre Dataframe;

  2. Utilisez pandas.append()method et transmettez le nom de votre dictionnaire, où .append()est une méthode sur les instances DataFrame;

  3. Ajoutez ignore_index=Truejuste après le nom de votre dictionnaire.

Pepe
la source
C'est probablement l'option la plus préférable (vers 2020).
David Golembiowski
1

concat()semble être un peu plus rapide que l'insertion et la réindexation de la dernière ligne. Au cas où quelqu'un s'interrogerait sur la vitesse de deux approches principales:

In [x]: %%timeit
     ...: df = pd.DataFrame(columns=['a','b'])
     ...: for i in range(10000):
     ...:     df.loc[-1] = [1,2]
     ...:     df.index = df.index + 1
     ...:     df = df.sort_index()

17,1 s ± 705 ms par boucle (moyenne ± écart standard de 7 courses, 1 boucle chacune)

In [y]: %%timeit
     ...: df = pd.DataFrame(columns=['a', 'b'])
     ...: for i in range(10000):
     ...:     df = pd.concat([pd.DataFrame([[1,2]], columns=df.columns), df])

6,53 s ± 127 ms par boucle (moyenne ± écart standard de 7 courses, 1 boucle chacune)

M. Viaz
la source
0

Vous pouvez simplement ajouter la ligne à la fin du DataFrame, puis ajuster l'index.

Par exemple:

df = df.append(pd.DataFrame([[2,3,4]],columns=df.columns),ignore_index=True)
df.index = (df.index + 1) % len(df)
df = df.sort_index()

Ou utilisez concatcomme:

df = pd.concat([pd.DataFrame([[1,2,3,4,5,6]],columns=df.columns),df],ignore_index=True)
Xinyi Li
la source
-1

Le moyen le plus simple d'ajouter une ligne dans une trame de données pandas est:

DataFrame.loc[ location of insertion ]= list( )

Exemple :

DF.loc[ 9 ] = [ ´Pepe , 33, ´Japan ]

NB: la longueur de votre liste doit correspondre à celle de la trame de données.

Pepe
la source
a fait l'affaire pour moi!
Sam Shaw le