274 votes

Comment ajouter plusieurs colonnes à un dataframe pandas en une seule affectation ?

Je suis nouveau dans le monde des pandas et j'essaie de comprendre comment ajouter plusieurs colonnes aux pandas simultanément. Toute aide est la bienvenue. Idéalement, j'aimerais faire cela en une seule étape plutôt qu'en plusieurs étapes répétées...

import pandas as pd

df = {'col_1': [0, 1, 2, 3],
        'col_2': [4, 5, 6, 7]}
df = pd.DataFrame(df)

df[[ 'column_new_1', 'column_new_2','column_new_3']] = [np.nan, 'dogs',3]  #thought this would work here...

2 votes

Vous devez indiquer quelle erreur vous avez obtenue. Lorsque j'essaie de faire cela sur pandas 1.0, j'obtiens KeyError: "None of [Index(['column_new_1', 'column_new_2', 'column_new_3'], dtype='object')] are in the [columns]"

378voto

mfripp Points 46

Je me serais attendu à ce que votre syntaxe fonctionne également. Le problème se pose parce que lorsque vous créez de nouvelles colonnes avec la syntaxe de la liste de colonnes ( df[[new1, new2]] = ... ), pandas exige que le côté droit soit un DataFrame (notez que cela n'a pas d'importance si les colonnes du DataFrame ont les mêmes noms que les colonnes que vous créez).

Votre syntaxe fonctionne bien pour l'attribution de valeurs scalaires à existant et pandas est également heureux d'affecter des valeurs scalaires à une nouvelle colonne en utilisant la syntaxe à colonne unique ( df[new1] = ... ). La solution consiste donc soit à convertir ces données en plusieurs affectations à une seule colonne, soit à créer un DataFrame approprié pour le côté droit.

Voici plusieurs approches qui sera travail :

import pandas as pd
import numpy as np

df = pd.DataFrame({
    'col_1': [0, 1, 2, 3],
    'col_2': [4, 5, 6, 7]
})

Puis l'un des éléments suivants :

1) Trois missions en une, en utilisant le déballage de la liste :

df['column_new_1'], df['column_new_2'], df['column_new_3'] = [np.nan, 'dogs', 3]

2) DataFrame développe commodément une seule ligne pour correspondre à l'index, donc vous pouvez faire ceci :

df[['column_new_1', 'column_new_2', 'column_new_3']] = pd.DataFrame([[np.nan, 'dogs', 3]], index=df.index)

3) Créez un cadre de données temporaire avec de nouvelles colonnes, puis combinez-le avec le cadre de données original plus tard :

df = pd.concat(
    [
        df,
        pd.DataFrame(
            [[np.nan, 'dogs', 3]], 
            index=df.index, 
            columns=['column_new_1', 'column_new_2', 'column_new_3']
        )
    ], axis=1
)

4) Similaire au précédent, mais en utilisant join au lieu de concat (peut être moins efficace) :

df = df.join(pd.DataFrame(
    [[np.nan, 'dogs', 3]], 
    index=df.index, 
    columns=['column_new_1', 'column_new_2', 'column_new_3']
))

5) L'utilisation d'un dict est une manière plus "naturelle" de créer le nouveau cadre de données que les deux précédentes, mais les nouvelles colonnes seront triées par ordre alphabétique (au moins). avant Python 3.6 ou 3.7 ):

df = df.join(pd.DataFrame(
    {
        'column_new_1': np.nan,
        'column_new_2': 'dogs',
        'column_new_3': 3
    }, index=df.index
))

6) Utiliser .assign() avec plusieurs arguments de colonne.

J'aime beaucoup cette variante de la réponse de @zero, mais comme la précédente, les nouvelles colonnes seront toujours triées par ordre alphabétique, du moins avec les premières versions de Python :

df = df.assign(column_new_1=np.nan, column_new_2='dogs', column_new_3=3)

7) C'est intéressant (basé sur https://stackoverflow.com/a/44951376/3830997 ), mais je ne sais pas quand cela en vaudrait la peine :

new_cols = ['column_new_1', 'column_new_2', 'column_new_3']
new_vals = [np.nan, 'dogs', 3]
df = df.reindex(columns=df.columns.tolist() + new_cols)   # add empty cols
df[new_cols] = new_vals  # multi-column assignment works for existing cols

8) En fin de compte, il est difficile de battre trois missions distinctes :

df['column_new_1'] = np.nan
df['column_new_2'] = 'dogs'
df['column_new_3'] = 3

Remarque : bon nombre de ces options ont déjà été abordées dans d'autres réponses : Ajouter plusieurs colonnes à DataFrame et les rendre égales à une colonne existante , Est-il possible d'ajouter plusieurs colonnes à la fois à un DataFrame pandas ? , Ajouter plusieurs colonnes vides à un DataFrame pandas

0 votes

Ne s'approcherait pas du numéro 7 ( .reindex ) modifie l'index du cadre de données ? Pourquoi quelqu'un voudrait-il modifier inutilement l'index lors de l'ajout de colonnes, à moins que ce ne soit un objectif explicite...

1 votes

.reindex() est utilisé avec le columns de sorte qu'il ne modifie que l'"index" de la colonne (noms). Elle ne modifie pas l'index de la ligne.

0 votes

Pour certaines des approches, vous pouvez utiliser OrderedDict : par exemple, df.join(pd.DataFrame( OrderedDict([('column_new_2', 'dogs'),('column_new_1', np.nan),('column_new_3', 3)]), index=df.index ))

56voto

John Galt Points 1144

Vous pourriez utiliser assign avec une dictée de noms de colonnes et de valeurs.

In [1069]: df.assign(**{'col_new_1': np.nan, 'col2_new_2': 'dogs', 'col3_new_3': 3})
Out[1069]:
   col_1  col_2 col2_new_2  col3_new_3  col_new_1
0      0      4       dogs           3        NaN
1      1      5       dogs           3        NaN
2      2      6       dogs           3        NaN
3      3      7       dogs           3        NaN

0 votes

Existe-t-il un moyen de faire la même chose en maintenant un ordre spécifique des colonnes ?

2 votes

Vous pouvez maintenir un ordre spécifique avec les versions antérieures de Python en appelant assign plusieurs fois : df.assign(**{'col_new_1': np.nan}).assign(**{'col2_new_2': 'dogs'}).assign(**{'col3_new_3': 3})

0 votes

Si les noms de colonnes ne contiennent que des chaînes de caractères qui sont des noms de variables légaux : df.assign(col_new_1=np.nan, col2_new_2='dogs', col3_new_3=3) . Cela maintient l'ordre.

16voto

Nehal J. Wani Points 503

Grâce à l'utilisation de concat :

In [128]: df
Out[128]: 
   col_1  col_2
0      0      4
1      1      5
2      2      6
3      3      7

In [129]: pd.concat([df, pd.DataFrame(columns = [ 'column_new_1', 'column_new_2','column_new_3'])])
Out[129]: 
   col_1  col_2 column_new_1 column_new_2 column_new_3
0    0.0    4.0          NaN          NaN          NaN
1    1.0    5.0          NaN          NaN          NaN
2    2.0    6.0          NaN          NaN          NaN
3    3.0    7.0          NaN          NaN          NaN

Pas très sûr de ce que vous vouliez faire avec [np.nan, 'dogs',3] . Peut-être les définir maintenant comme valeurs par défaut ?

In [142]: df1 = pd.concat([df, pd.DataFrame(columns = [ 'column_new_1', 'column_new_2','column_new_3'])])
In [143]: df1[[ 'column_new_1', 'column_new_2','column_new_3']] = [np.nan, 'dogs', 3]

In [144]: df1
Out[144]: 
   col_1  col_2  column_new_1 column_new_2  column_new_3
0    0.0    4.0           NaN         dogs             3
1    1.0    5.0           NaN         dogs             3
2    2.0    6.0           NaN         dogs             3
3    3.0    7.0           NaN         dogs             3

0 votes

S'il y avait un moyen de faire votre 2ème partie en une seule étape - oui des valeurs constantes dans les colonnes comme exemple.

3voto

piRSquared Points 159

L'utilisation de la compréhension des listes, pd.DataFrame y pd.concat

pd.concat(
    [
        df,
        pd.DataFrame(
            [[np.nan, 'dogs', 3] for _ in range(df.shape[0])],
            df.index, ['column_new_1', 'column_new_2','column_new_3']
        )
    ], axis=1)

enter image description here

0 votes

Notez que concat générera un nouveau cadre de données au lieu d'ajouter des colonnes à celui qui existe déjà.

2voto

halfmoonhalf Points 1

Je veux juste signaler que l'option 2 de la réponse de @Matthias Fripp

(2) Je ne m'attendais pas nécessairement à ce que DataFrame fonctionne de cette façon, mais c'est le cas.

df[['colonne_neuve_1', 'colonne_neuve_2', 'colonne_neuve_3']] = pd.DataFrame([[np.nan, 'chiens', 3]], index=df.index)

est déjà documentée dans la propre documentation de pandas http://pandas.pydata.org/pandas-docs/stable/indexing.html#basics

Vous pouvez passer une liste de colonnes à [] pour sélectionner les colonnes dans cet ordre. Si une colonne n'est pas contenue dans le DataFrame, une exception sera levée. Plusieurs colonnes peuvent également être définies de cette manière. Vous pouvez trouver cela utile pour appliquer une transformation ( en place ) à un sous-ensemble de colonnes.

0 votes

Je pense que c'est assez standard pour une affectation à plusieurs colonnes. Ce qui m'a surpris, c'est que pd.DataFrame([[np.nan, 'dogs', 3]], index=df.index) réplique la ligne qui lui est donnée pour créer un cadre de données complet de la même longueur que l'index.

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