Supprimer les colonnes dont le nom contient une chaîne spécifique de pandas DataFrame

106

J'ai un dataframe pandas avec les noms de colonnes suivants:

Résultat1, Test1, Résultat2, Test2, Résultat3, Test3, etc ...

Je souhaite supprimer toutes les colonnes dont le nom contient le mot "Test". Le nombre de ces colonnes n'est pas statique mais dépend d'une fonction précédente.

Comment puis je faire ça?

Alexis Eggermont
la source

Réponses:

74
import pandas as pd

import numpy as np

array=np.random.random((2,4))

df=pd.DataFrame(array, columns=('Test1', 'toto', 'test2', 'riri'))

print df

      Test1      toto     test2      riri
0  0.923249  0.572528  0.845464  0.144891
1  0.020438  0.332540  0.144455  0.741412

cols = [c for c in df.columns if c.lower()[:4] != 'test']

df=df[cols]

print df
       toto      riri
0  0.572528  0.144891
1  0.332540  0.741412
Nic
la source
2
Le PO n'a pas précisé que la suppression devait être insensible à la casse.
Phillip Cloud
164

Voici une façon de procéder:

df = df[df.columns.drop(list(df.filter(regex='Test')))]
Bindiya12
la source
47
Ou directement sur place:df.drop(list(df.filter(regex = 'Test')), axis = 1, inplace = True)
Axel du
7
C'est une solution beaucoup plus élégante que la réponse acceptée. Je le décomposerais un peu plus pour montrer pourquoi, principalement en extrayant list(df.filter(regex='Test'))pour mieux montrer ce que fait la ligne. J'opterais également pour df.filter(regex='Test').columnsla conversion sur liste
Charles
2
Celui-ci est bien plus élégant que la réponse acceptée.
deepelement
4
Je me demande vraiment ce que signifient les commentaires disant que cette réponse est «élégante». Je le trouve moi-même assez obscur, quand le code python devrait d'abord être lisible. Elle est également deux fois plus lente que la première réponse. Et il utilise le regexmot - clé lorsque le likemot - clé semble être plus adéquat.
Jacquot
2
Ce n'est pas vraiment une réponse aussi bonne que les gens le prétendent. Le problème avec filterest qu'il renvoie une copie de TOUTES les données sous forme de colonnes que vous souhaitez supprimer. C'est un gaspillage si vous ne transmettez ce résultat qu'à drop(qui renvoie à nouveau une copie) ... une meilleure solution serait str.startswith(j'ai ajouté une réponse ici).
cs95
42

Moins cher, plus rapide et idiomatique: str.contains

Dans les versions récentes de pandas, vous pouvez utiliser des méthodes de chaîne sur l'index et les colonnes. Ici, str.startswithsemble être un bon ajustement.

Pour supprimer toutes les colonnes commençant par une sous-chaîne donnée:

df.columns.str.startswith('Test')
# array([ True, False, False, False])

df.loc[:,~df.columns.str.startswith('Test')]

  toto test2 riri
0    x     x    x
1    x     x    x

Pour la correspondance insensible à la casse, vous pouvez utiliser la correspondance basée sur les expressions régulières avec str.containsavec une ancre SOL:

df.columns.str.contains('^test', case=False)
# array([ True, False,  True, False])

df.loc[:,~df.columns.str.contains('^test', case=False)] 

  toto riri
0    x    x
1    x    x

si les types mixtes sont une possibilité, spécifiez na=Falseégalement.

cs95
la source
15

Vous pouvez filtrer les colonnes que vous voulez en utilisant «filtre»

import pandas as pd
import numpy as np

data2 = [{'test2': 1, 'result1': 2}, {'test': 5, 'result34': 10, 'c': 20}]

df = pd.DataFrame(data2)

df

    c   result1     result34    test    test2
0   NaN     2.0     NaN     NaN     1.0
1   20.0    NaN     10.0    5.0     NaN

Maintenant filtre

df.filter(like='result',axis=1)

Avoir..

   result1  result34
0   2.0     NaN
1   NaN     10.0
SAH
la source
4
Meilleure réponse! Merci. Comment filtrez-vous le contraire? not like='result'
stallingOne
2
puis faites ceci: df = df.drop (df.filter (like = 'result', axis = 1) .columns, axis = 1)
Amir
14

Cela peut être fait en une seule ligne avec:

df = df.drop(df.filter(regex='Test').columns, axis=1)
Warren O'Neill
la source
1
De même (et plus rapide):df.drop(df.filter(regex='Test').columns, axis=1, inplace=True)
Max Ghenis le
9

Utilisez la DataFrame.selectméthode:

In [38]: df = DataFrame({'Test1': randn(10), 'Test2': randn(10), 'awesome': randn(10)})

In [39]: df.select(lambda x: not re.search('Test\d+', x), axis=1)
Out[39]:
   awesome
0    1.215
1    1.247
2    0.142
3    0.169
4    0.137
5   -0.971
6    0.736
7    0.214
8    0.111
9   -0.214
Phillip Cloud
la source
Et l'op n'a pas précisé qu'un nombre devait suivre 'Test': je veux supprimer toutes les colonnes dont le nom contient le mot "Test" .
7stud
L'hypothèse qu'un nombre suit Test est parfaitement raisonnable. Relisez la question.
Phillip Cloud
2
voir maintenant:FutureWarning: 'select' is deprecated and will be removed in a future release. You can use .loc[labels.map(crit)] as a replacement
flutefreak7
N'oubliez pas d' import reavance.
ijoseph
5

Cette méthode fait tout en place. La plupart des autres réponses créent des copies et ne sont pas aussi efficaces:

df.drop(df.columns[df.columns.str.contains('Test')], axis=1, inplace=True)

ba0101
la source
2

Ne laissez pas tomber. Attrapez le contraire de ce que vous voulez.

df = df.filter(regex='^((?!badword).)*$').columns
Roy Assis
la source
1

le moyen le plus court est de:

resdf = df.filter(like='Test',axis=1)
ZacNt
la source
Cela était déjà couvert par cette réponse .
Gino Mempin
1
Bien que la réponse liée dans le commentaire ci-dessus soit similaire, ce n'est pas la même chose. En fait, c'est presque le contraire.
Makyen
0

Solution lors de la suppression d'une liste de noms de colonnes contenant des regex. Je préfère cette approche car je modifie fréquemment la liste déroulante. Utilise une expression régulière de filtre négatif pour la liste déroulante.

drop_column_names = ['A','B.+','C.*']
drop_columns_regex = '^(?!(?:'+'|'.join(drop_column_names)+')$)'
print('Dropping columns:',', '.join([c for c in df.columns if re.search(drop_columns_regex,c)]))
df = df.filter(regex=drop_columns_regex,axis=1)
BSalita
la source