Suelta las columnas cuyo nombre contiene una cadena específica de pandas DataFrame


106

Tengo un marco de datos de pandas con los siguientes nombres de columna:

Resultado1, Prueba1, Resultado2, Prueba2, Resultado3, Prueba3, etc ...

Quiero eliminar todas las columnas cuyo nombre contenga la palabra "Prueba". El número de tales columnas no es estático sino que depende de una función previa.

¿Cómo puedo hacer eso?

Respuestas:


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

2
El OP no especificó que la eliminación no debe distinguir entre mayúsculas y minúsculas.
Phillip Cloud

162

Esta es una buena forma de hacerlo:

df = df[df.columns.drop(list(df.filter(regex='Test')))]

47
O directamente en el lugar:df.drop(list(df.filter(regex = 'Test')), axis = 1, inplace = True)
Axel

7
Esta es una solución mucho más elegante que la respuesta aceptada. Lo desglosaría un poco más para mostrar por qué, principalmente extrayendo list(df.filter(regex='Test'))para mostrar mejor lo que está haciendo la línea. También optaría por la df.filter(regex='Test').columnsconversión por encima de la lista
Charles

2
Esta es mucho más elegante que la respuesta aceptada.
profundización

4
Realmente me pregunto qué significan los comentarios que dicen que esta respuesta es "elegante". Yo mismo lo encuentro bastante ofuscado, cuando el código de Python debería ser legible primero. También es dos veces más lento que la primera respuesta. Y usa la regexpalabra clave cuando la likepalabra clave parece ser más adecuada.
Jacquot

2
En realidad, esta no es una respuesta tan buena como la gente afirma. El problema filteres que devuelve una copia de TODOS los datos como columnas que desea eliminar. Es un desperdicio si solo está pasando este resultado a drop(que nuevamente devuelve una copia) ... una mejor solución sería str.startswith(agregué una respuesta con eso aquí).
cs95

40

Más barato, más rápido e idiomático: str.contains

En versiones recientes de pandas, puede usar métodos de cadena en el índice y las columnas. Aquí, str.startswithparece una buena opción.

Para eliminar todas las columnas que comienzan con una subcadena determinada:

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

Para la coincidencia que no distingue entre mayúsculas y minúsculas, puede utilizar la coincidencia basada en expresiones regulares str.containscon un ancla 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 los tipos mixtos son una posibilidad, especifique na=Falsetambién.


15

Puede filtrar las columnas que SÍ desea usando 'filtro'

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

Ahora filtrar

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

Obtener..

   result1  result34
0   2.0     NaN
1   NaN     10.0

4
¡La mejor respuesta! Gracias. ¿Cómo filtra lo opuesto? not like='result'
stallingOne

2
luego haz esto: df = df.drop (df.filter (like = 'result', axis = 1) .columns, axis = 1)
Amir

14

Esto se puede hacer perfectamente en una línea con:

df = df.drop(df.filter(regex='Test').columns, axis=1)

1
Del mismo modo (y más rápido):df.drop(df.filter(regex='Test').columns, axis=1, inplace=True)
Max Ghenis

9

Usa el DataFrame.selectmétodo:

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

Y la operación no especificó que un número tenía que seguir a 'Prueba': quiero eliminar todas las columnas cuyo nombre contiene la palabra "Prueba" .
7 de

La suposición de que un número sigue a Test es perfectamente razonable. Vuelve a leer la pregunta.
Phillip Cloud

2
viendo ahora:FutureWarning: 'select' is deprecated and will be removed in a future release. You can use .loc[labels.map(crit)] as a replacement
flutefreak7

Recuerde de import reantemano.
ijoseph

5

Este método hace todo en su lugar. Muchas de las otras respuestas crean copias y no son tan eficientes:

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


2

No dejes caer. Captura lo contrario de lo que quieres.

df = df.filter(regex='^((?!badword).)*$').columns

1

la forma más corta de hacerlo es:

resdf = df.filter(like='Test',axis=1)

Esto ya estaba cubierto por esta respuesta .
Gino Mempin

1
Si bien la respuesta vinculada en el comentario anterior es similar, no es la misma. De hecho, es casi lo contrario.
Makyen

0

Solución al eliminar una lista de nombres de columnas que contienen expresiones regulares. Prefiero este enfoque porque con frecuencia edito la lista desplegable. Utiliza una expresión regular de filtro negativa para la lista desplegable.

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)
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.