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?

Alexis Eggermont
fuente

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
Nic
fuente
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')))]
Bindiya12
fuente
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.

cs95
fuente
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
SAH
fuente
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)
Warren O'Neill
fuente
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
Phillip Cloud
fuente
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)

ba0101
fuente
2

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

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

la forma más corta de hacerlo es:

resdf = df.filter(like='Test',axis=1)
ZacNt
fuente
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)
BSalita
fuente