Supprimer la colonne de pandas DataFrame

1334

Lors de la suppression d'une colonne dans un DataFrame que j'utilise:

del df['column_name']

Et cela fonctionne très bien. Pourquoi ne puis-je pas utiliser les éléments suivants?

del df.column_name

Puisqu'il est possible d'accéder à la colonne / série en tant que df.column_name, je m'attendais à ce que cela fonctionne.

John
la source
2
Notez que cette question est en cours de discussion sur Meta .
RM

Réponses:

863

Comme vous l'avez deviné, la bonne syntaxe est

del df['column_name']

Il est difficile de faire del df.column_namefonctionner simplement en raison des limitations syntaxiques de Python. del df[name]est traduit df.__delitem__(name)sous les couvertures par Python.

Wes McKinney
la source
25
Je me rends compte que c'est une "réponse" super ancienne, mais ma curiosité est piquée - pourquoi est-ce une limitation syntaxique de Python? class A(object): def __init__(self): self.var = 1met en place une classe, puis a = A(); del a.varfonctionne très bien ...
dwanderson
14
@dwanderson la différence est que lorsqu'une colonne doit être supprimée, le DataFrame doit avoir sa propre gestion pour "comment faire". Dans le cas de del df[name], il est traduit en df.__delitem__(name)une méthode que DataFrame peut implémenter et modifier selon ses besoins. Dans le cas de del df.name, la variable membre est supprimée sans possibilité d'exécution de code personnalisé. Prenons votre propre exemple - pouvez-vous obtenir del a.varune impression de "suppression de variable"? Si vous le pouvez, dites-moi comment. Je ne peux pas :)
Yonatan
8
@Yonatan Vous pouvez utiliser soit docs.python.org/3/reference/datamodel.html#object.__delattr__ ou des descripteurs pour cela: docs.python.org/3/howto/descriptor.html
Eugene Pakhomov
5
Le commentaire de @Yonatan Eugene s'applique également à Python 2; les descripteurs sont en Python 2 depuis la 2.2 et il est trivial de satisfaire vos besoins;)
CS
1
Cette réponse n'est pas vraiment correcte - les pandasdéveloppeurs ne l'ont pas fait , mais cela ne signifie pas que c'est difficile à faire.
wizzwizz4
2187

La meilleure façon de le faire chez les pandas est d'utiliser drop:

df = df.drop('column_name', 1)

1est le numéro de l' axe ( 0pour les lignes et les 1colonnes.)

Pour supprimer la colonne sans avoir à réaffecter, dfvous pouvez faire:

df.drop('column_name', axis=1, inplace=True)

Enfin, pour supprimer par numéro de colonne plutôt que par étiquette de colonne , essayez de supprimer, par exemple les 1ère, 2e et 4e colonnes:

df = df.drop(df.columns[[0, 1, 3]], axis=1)  # df.columns is zero-based pd.Index 

Fonctionne également avec la syntaxe "texte" pour les colonnes:

df.drop(['column_nameA', 'column_nameB'], axis=1, inplace=True)
LondonRob
la source
79
Est-ce recommandé delpour une raison quelconque?
beardc
20
Bien que cette méthode de suppression ait ses mérites, cette réponse ne répond pas vraiment à la question posée.
Paul
109
Vrai @Paul, mais en raison du titre de la question, la plupart des gens qui arrivent ici le feront en essayant de savoir comment supprimer une colonne.
LondonRob
24
@beardc un autre avantage de dropover delest qu'il dropvous permet de supprimer plusieurs colonnes à la fois, d'effectuer l'opération sur place ou non, et également de supprimer des enregistrements le long de n'importe quel axe (particulièrement utile pour une matrice 3D ou Panel)
plaques de cuisson
8
Un autre avantage de dropover delest que drop fait partie de l'API pandas et contient de la documentation.
modulitos
242

Utilisation:

columns = ['Col1', 'Col2', ...]
df.drop(columns, inplace=True, axis=1)

Cela supprimera une ou plusieurs colonnes en place. Notez que cela a inplace=Trueété ajouté dans pandas v0.13 et ne fonctionnera pas sur les anciennes versions. Vous devez attribuer le résultat dans ce cas:

df = df.drop(columns, axis=1)
Krishna Sankar
la source
3
Une note à propos de cette réponse: si une «liste» est utilisée, les crochets doivent être supprimés:df.drop(list,inplace=True,axis=1)
edesz
1
cela devrait vraiment être la réponse acceptée, car elle montre clairement la supériorité de cette méthode sur del- peut supprimer plus d'une colonne à la fois.
dbliss
111

Déposer par index

Supprimer les première, deuxième et quatrième colonnes:

df.drop(df.columns[[0,1,3]], axis=1, inplace=True)

Supprimer la première colonne:

df.drop(df.columns[[0]], axis=1, inplace=True)

Il existe un paramètre facultatif inplacepour que les données d'origine puissent être modifiées sans créer de copie.

Sauté

Sélection, ajout, suppression de colonnes

Supprimer la colonne column-name:

df.pop('column-name')

Exemples:

df = DataFrame.from_items([('A', [1, 2, 3]), ('B', [4, 5, 6]), ('C', [7,8, 9])], orient='index', columns=['one', 'two', 'three'])

print df:

   one  two  three
A    1    2      3
B    4    5      6
C    7    8      9

df.drop(df.columns[[0]], axis=1, inplace=True) print df:

   two  three
A    2      3
B    5      6
C    8      9

three = df.pop('three') print df:

   two
A    2
B    5
C    8
jezrael
la source
1
Comment puis-je faire une rangée dans les pandas?
Kennet Celeste
2
@Yugi Vous pouvez utiliser une trame de données transposée pour cela. ex - df.T.pop('A')
Clock Slave
@ClockSlave Cela ne modifie pas l'original df. Vous pourriez le faire df = df.T; df.pop(index); df = df.Tmais cela semble excessif.
cs95
Au lieu de df.drop(df.columns[[0]], axis=1, inplace=True)cela ne serait-il pas suffisant d'utiliser df.drop([0], axis=1)?
Anirban Mukherjee
1
@Anirban Mukherjee Cela dépend. Si vous souhaitez supprimer le nom de la colonne 0, cela df.drop(0, axis=1)fonctionne bien. Mais si vous ne connaissez pas le nom de la colonne et que vous devez supprimer la première colonne df.drop(df.columns[[0]], axis=1, inplace=True), vous avez besoin , sélectionnez la première colonne par position et déposez-la.
jezrael
71

La vraie question posée, manquée par la plupart des réponses ici est:

Pourquoi ne puis-je pas l'utiliser del df.column_name?

Au début, nous devons comprendre le problème, ce qui nous oblige à plonger dans les méthodes magiques de python .

Comme Wes le souligne dans sa réponse, il del df['column']mappe la méthode magique python df.__delitem__('column')qui est implémentée dans les pandas pour supprimer la colonne

Cependant, comme indiqué dans le lien ci-dessus sur les méthodes magiques de python :

En fait, __del__ne devrait presque jamais être utilisé en raison des circonstances précaires dans lesquelles il est appelé; utilisez-le avec prudence!

Vous pourriez dire que cela del df['column_name']ne devrait pas être utilisé ou encouragé, et del df.column_namene devrait donc même pas être pris en considération.

Cependant, en théorie, del df.column_namepourrait être implémenté pour fonctionner chez les pandas en utilisant la méthode magique__delattr__ . Cela introduit cependant certains problèmes, problèmes que la del df['column_name']mise en œuvre a déjà, mais dans une moindre mesure.

Exemple de problème

Et si je définis une colonne dans une trame de données appelée "dtypes" ou "colonnes".

Supposez ensuite que je souhaite supprimer ces colonnes.

del df.dtypesrendrait la __delattr__méthode confuse comme si elle devait supprimer l'attribut "dtypes" ou la colonne "dtypes".

Questions architecturales derrière ce problème

  1. Une trame de données est-elle une collection de colonnes ?
  2. Une trame de données est-elle une collection de lignes ?
  3. Une colonne est-elle un attribut d'une trame de données?

Pandas répond:

  1. Oui, dans tous les sens
  2. Non, mais si vous voulez qu'il soit, vous pouvez utiliser les .ix, .locou les .ilocméthodes.
  3. Peut-être, voulez-vous lire des données? Alors oui , sauf si le nom de l'attribut est déjà pris par un autre attribut appartenant à la trame de données. Voulez-vous modifier les données? Alors non .

TLDR;

Vous ne pouvez pas le faire del df.column_nameparce que les pandas ont une architecture assez développée qui doit être reconsidérée afin que ce type de dissonance cognitive ne se produise pas pour ses utilisateurs.

Protip:

N'utilisez pas df.column_name, c'est peut-être joli, mais cela provoque une dissonance cognitive

Citations Zen of Python qui s'inscrivent ici:

Il existe plusieurs façons de supprimer une colonne.

Il devrait y avoir une - et de préférence une seule - manière évidente de le faire.

Les colonnes sont parfois des attributs mais parfois non.

Les cas spéciaux ne sont pas assez spéciaux pour enfreindre les règles.

Ne del df.dtypessupprimez l'attribut dtypes ou la colonne dtypes?

Face à l'ambiguïté, refusez la tentation de deviner.

firelynx
la source
"En fait, __del__ne devrait presque jamais être utilisé en raison des circonstances précaires dans lesquelles il est appelé; utilisez-le avec prudence!" est complètement hors de propos ici, tout comme la méthode utilisée ici __delattr__.
pppery
1
@ppperry vous avez mal cité. c'est la fonction delintégrée qui est destinée, pas la .__del__méthode d'instance. Le delbuiltin est mappé __delattr__et sur __delitem__lequel je construis mon argument. Alors peut-être que vous voulez relire ce que j'ai écrit.
firelynx
1
__... __est interprété comme un marquage gras par StackExchange
pppery
2
"N'utilisez pas df.column_name, c'est peut-être joli, mais cela provoque une dissonance cognitive" Qu'est-ce que cela signifie? Je ne suis pas psychologue, je dois donc chercher cela pour comprendre ce que vous voulez dire. De plus, citer Le Zen n'a pas de sens car il existe des centaines de façons valables de faire la même chose chez les pandas.
cs95
58

Un ajout intéressant est la possibilité de supprimer des colonnes uniquement si elles existent . De cette façon, vous pouvez couvrir plus de cas d'utilisation et il ne supprimera que les colonnes existantes des étiquettes qui lui sont passées:

Ajoutez simplement errors = 'ignore' , par exemple .:

df.drop(['col_name_1', 'col_name_2', ..., 'col_name_N'], inplace=True, axis=1, errors='ignore')
  • Ceci est nouveau à partir des pandas 0.16.1. La documentation est ici .
eiTan LaVi
la source
41

à partir de la version 0.16.1, vous pouvez le faire

df.drop(['column_name'], axis = 1, inplace = True, errors = 'ignore')
sushmit
la source
3
Et cela prend également en charge la suppression de plusieurs colonnes, dont certaines n'ont pas besoin d'exister (c'est-à-dire sans générer d'erreur errors= 'ignore') df.drop(['column_1','column_2'], axis=1 , inplace=True,errors= 'ignore'), si une telle application le souhaite!
muon
31

Il est recommandé de toujours utiliser la []notation. Une des raisons est que la notation d'attribut ( df.column_name) ne fonctionne pas pour les indices numérotés:

In [1]: df = DataFrame([[1, 2, 3], [4, 5, 6]])

In [2]: df[1]
Out[2]:
0    2
1    5
Name: 1

In [3]: df.1
  File "<ipython-input-3-e4803c0d1066>", line 1
    df.1
       ^
SyntaxError: invalid syntax
Andy Hayden
la source
26

Pandas 0.21+ réponse

La version 0.21 de Pandas a droplégèrement modifié la méthode pour inclure à la fois les paramètres indexet columnsafin de correspondre à la signature des méthodes renameet reindex.

df.drop(columns=['column_a', 'column_c'])

Personnellement, je préfère utiliser le axisparamètre pour désigner des colonnes ou un index car c'est le paramètre de mot-clé prédominant utilisé dans presque toutes les méthodes pandas. Mais, maintenant, vous avez des choix supplémentaires dans la version 0.21.

Ted Petrou
la source
1
df.drop (['colonne_a', 'colonne_c'], axe = 1) | cela fonctionne pour moi pour l'instant
YouAreAwesome
21

Dans pandas 0.16.1+, vous ne pouvez supprimer des colonnes que si elles existent selon la solution publiée par @eiTanLaVi. Avant cette version, vous pouvez obtenir le même résultat via une compréhension de liste conditionnelle:

df.drop([col for col in ['col_name_1','col_name_2',...,'col_name_N'] if col in df], 
        axis=1, inplace=True)
Alexandre
la source
14

TL; DR

Beaucoup d'efforts pour trouver une solution légèrement plus efficace. Difficile de justifier la complexité supplémentaire tout en sacrifiant la simplicité dedf.drop(dlst, 1, errors='ignore')

df.reindex_axis(np.setdiff1d(df.columns.values, dlst), 1)

Préambule La
suppression d'une colonne équivaut sémantiquement à la sélection des autres colonnes. Je vais vous montrer quelques méthodes supplémentaires à considérer.

Je vais également me concentrer sur la solution générale de supprimer plusieurs colonnes à la fois et de permettre la tentative de suppression de colonnes non présentes.

L'utilisation de ces solutions est générale et fonctionnera également pour le cas simple.


Configuration
Considérez la pd.DataFrame dfet liste supprimerdlst

df = pd.DataFrame(dict(zip('ABCDEFGHIJ', range(1, 11))), range(3))
dlst = list('HIJKLM')

df

   A  B  C  D  E  F  G  H  I   J
0  1  2  3  4  5  6  7  8  9  10
1  1  2  3  4  5  6  7  8  9  10
2  1  2  3  4  5  6  7  8  9  10

dlst

['H', 'I', 'J', 'K', 'L', 'M']

Le résultat devrait ressembler à:

df.drop(dlst, 1, errors='ignore')

   A  B  C  D  E  F  G
0  1  2  3  4  5  6  7
1  1  2  3  4  5  6  7
2  1  2  3  4  5  6  7

Puisque j'assimile la suppression d'une colonne à la sélection des autres colonnes, je vais la diviser en deux types:

  1. Sélection d'étiquette
  2. Sélection booléenne

Sélection d'étiquette

Nous commençons par fabriquer la liste / tableau d'étiquettes qui représentent les colonnes que nous voulons conserver et sans les colonnes que nous voulons supprimer.

  1. df.columns.difference(dlst)

    Index(['A', 'B', 'C', 'D', 'E', 'F', 'G'], dtype='object')
  2. np.setdiff1d(df.columns.values, dlst)

    array(['A', 'B', 'C', 'D', 'E', 'F', 'G'], dtype=object)
  3. df.columns.drop(dlst, errors='ignore')

    Index(['A', 'B', 'C', 'D', 'E', 'F', 'G'], dtype='object')
  4. list(set(df.columns.values.tolist()).difference(dlst))

    # does not preserve order
    ['E', 'D', 'B', 'F', 'G', 'A', 'C']
  5. [x for x in df.columns.values.tolist() if x not in dlst]

    ['A', 'B', 'C', 'D', 'E', 'F', 'G']

Colonnes des étiquettes
Pour comparer le processus de sélection, supposons:

 cols = [x for x in df.columns.values.tolist() if x not in dlst]

Ensuite, nous pouvons évaluer

  1. df.loc[:, cols]
  2. df[cols]
  3. df.reindex(columns=cols)
  4. df.reindex_axis(cols, 1)

Que tous évaluent:

   A  B  C  D  E  F  G
0  1  2  3  4  5  6  7
1  1  2  3  4  5  6  7
2  1  2  3  4  5  6  7

Tranche booléenne

Nous pouvons construire un tableau / liste de booléens pour le découpage

  1. ~df.columns.isin(dlst)
  2. ~np.in1d(df.columns.values, dlst)
  3. [x not in dlst for x in df.columns.values.tolist()]
  4. (df.columns.values[:, None] != dlst).all(1)

Colonnes de Boolean
Par souci de comparaison

bools = [x not in dlst for x in df.columns.values.tolist()]
  1. df.loc[: bools]

Que tous évaluent:

   A  B  C  D  E  F  G
0  1  2  3  4  5  6  7
1  1  2  3  4  5  6  7
2  1  2  3  4  5  6  7

Synchronisation robuste

Les fonctions

setdiff1d = lambda df, dlst: np.setdiff1d(df.columns.values, dlst)
difference = lambda df, dlst: df.columns.difference(dlst)
columndrop = lambda df, dlst: df.columns.drop(dlst, errors='ignore')
setdifflst = lambda df, dlst: list(set(df.columns.values.tolist()).difference(dlst))
comprehension = lambda df, dlst: [x for x in df.columns.values.tolist() if x not in dlst]

loc = lambda df, cols: df.loc[:, cols]
slc = lambda df, cols: df[cols]
ridx = lambda df, cols: df.reindex(columns=cols)
ridxa = lambda df, cols: df.reindex_axis(cols, 1)

isin = lambda df, dlst: ~df.columns.isin(dlst)
in1d = lambda df, dlst: ~np.in1d(df.columns.values, dlst)
comp = lambda df, dlst: [x not in dlst for x in df.columns.values.tolist()]
brod = lambda df, dlst: (df.columns.values[:, None] != dlst).all(1)

Essai

res1 = pd.DataFrame(
    index=pd.MultiIndex.from_product([
        'loc slc ridx ridxa'.split(),
        'setdiff1d difference columndrop setdifflst comprehension'.split(),
    ], names=['Select', 'Label']),
    columns=[10, 30, 100, 300, 1000],
    dtype=float
)

res2 = pd.DataFrame(
    index=pd.MultiIndex.from_product([
        'loc'.split(),
        'isin in1d comp brod'.split(),
    ], names=['Select', 'Label']),
    columns=[10, 30, 100, 300, 1000],
    dtype=float
)

res = res1.append(res2).sort_index()

dres = pd.Series(index=res.columns, name='drop')

for j in res.columns:
    dlst = list(range(j))
    cols = list(range(j // 2, j + j // 2))
    d = pd.DataFrame(1, range(10), cols)
    dres.at[j] = timeit('d.drop(dlst, 1, errors="ignore")', 'from __main__ import d, dlst', number=100)
    for s, l in res.index:
        stmt = '{}(d, {}(d, dlst))'.format(s, l)
        setp = 'from __main__ import d, dlst, {}, {}'.format(s, l)
        res.at[(s, l), j] = timeit(stmt, setp, number=100)

rs = res / dres

rs

                          10        30        100       300        1000
Select Label                                                           
loc    brod           0.747373  0.861979  0.891144  1.284235   3.872157
       columndrop     1.193983  1.292843  1.396841  1.484429   1.335733
       comp           0.802036  0.732326  1.149397  3.473283  25.565922
       comprehension  1.463503  1.568395  1.866441  4.421639  26.552276
       difference     1.413010  1.460863  1.587594  1.568571   1.569735
       in1d           0.818502  0.844374  0.994093  1.042360   1.076255
       isin           1.008874  0.879706  1.021712  1.001119   0.964327
       setdiff1d      1.352828  1.274061  1.483380  1.459986   1.466575
       setdifflst     1.233332  1.444521  1.714199  1.797241   1.876425
ridx   columndrop     0.903013  0.832814  0.949234  0.976366   0.982888
       comprehension  0.777445  0.827151  1.108028  3.473164  25.528879
       difference     1.086859  1.081396  1.293132  1.173044   1.237613
       setdiff1d      0.946009  0.873169  0.900185  0.908194   1.036124
       setdifflst     0.732964  0.823218  0.819748  0.990315   1.050910
ridxa  columndrop     0.835254  0.774701  0.907105  0.908006   0.932754
       comprehension  0.697749  0.762556  1.215225  3.510226  25.041832
       difference     1.055099  1.010208  1.122005  1.119575   1.383065
       setdiff1d      0.760716  0.725386  0.849949  0.879425   0.946460
       setdifflst     0.710008  0.668108  0.778060  0.871766   0.939537
slc    columndrop     1.268191  1.521264  2.646687  1.919423   1.981091
       comprehension  0.856893  0.870365  1.290730  3.564219  26.208937
       difference     1.470095  1.747211  2.886581  2.254690   2.050536
       setdiff1d      1.098427  1.133476  1.466029  2.045965   3.123452
       setdifflst     0.833700  0.846652  1.013061  1.110352   1.287831

fig, axes = plt.subplots(2, 2, figsize=(8, 6), sharey=True)
for i, (n, g) in enumerate([(n, g.xs(n)) for n, g in rs.groupby('Select')]):
    ax = axes[i // 2, i % 2]
    g.plot.bar(ax=ax, title=n)
    ax.legend_.remove()
fig.tight_layout()

C'est relatif au temps qu'il faut pour s'exécuter df.drop(dlst, 1, errors='ignore'). Il semble qu'après tous ces efforts, nous n'améliorons que modestement les performances.

entrez la description de l'image ici

Si en fait les meilleures solutions utilisent reindexou reindex_axissur le hack list(set(df.columns.values.tolist()).difference(dlst)). Une seconde proche et toujours très légèrement meilleure que la dropprécédente np.setdiff1d.

rs.idxmin().pipe(
    lambda x: pd.DataFrame(
        dict(idx=x.values, val=rs.lookup(x.values, x.index)),
        x.index
    )
)

                      idx       val
10     (ridx, setdifflst)  0.653431
30    (ridxa, setdifflst)  0.746143
100   (ridxa, setdifflst)  0.816207
300    (ridx, setdifflst)  0.780157
1000  (ridxa, setdifflst)  0.861622
piRSquared
la source
2

La syntaxe des points fonctionne en JavaScript, mais pas en Python.

  • Python: del df['column_name']
  • JavaScript: del df['column_name'] ou del df.column_name
Médecin
la source
2

Si votre trame de données d'origine dfn'est pas trop volumineuse, vous n'avez pas de contraintes de mémoire et vous n'avez qu'à conserver quelques colonnes, alors vous pourriez aussi bien créer une nouvelle trame de données avec uniquement les colonnes dont vous avez besoin:

new_df = df[['spam', 'sausage']]
ccpizza
la source
2

Nous pouvons supprimer ou supprimer une colonne spécifiée ou des colonnes sprcified par la méthode drop () .

Supposons que df soit une trame de données.

Colonne à supprimer = colonne0

Code:

df = df.drop(column0, axis=1)

Pour supprimer plusieurs colonnes col1, col2,. . . , coln, nous devons insérer toutes les colonnes qui devaient être supprimées dans une liste. Supprimez-les ensuite par la méthode drop ().

Code:

df = df.drop([col1, col2, . . . , coln], axis=1)

J'espère que ce serait utile.

Littin Rajan
la source
df = df.drop([col1, col2, . . . , coln], axis=1)cela ne fonctionne pas si je spécifie un nom de variable à la place de col1, col2 etc. J'obtiens une colonne d'erreur non dans l'axe lorsqu'elle est définitivement présente. @Littin Pourriez-vous aider?
RSM
1

Une autre façon de supprimer une colonne dans Pandas DataFrame

si vous ne recherchez pas la suppression sur place, vous pouvez créer un nouveau DataFrame en spécifiant les colonnes en utilisant la DataFrame(...)fonction comme

my_dict = { 'name' : ['a','b','c','d'], 'age' : [10,20,25,22], 'designation' : ['CEO', 'VP', 'MD', 'CEO']}

df = pd.DataFrame(my_dict)

Créez un nouveau DataFrame en tant que

newdf = pd.DataFrame(df, columns=['name', 'age'])

Vous obtenez un résultat aussi bon que ce que vous obtenez avec del / drop

Daksh
la source
1
C'est techniquement correct, mais il semble idiot de devoir répertorier toutes les colonnes à conserver au lieu de la seule (ou quelques) colonnes que vous souhaitez supprimer.
cs95