Solte as colunas cujo nome contém uma string específica do pandas DataFrame

106

Eu tenho um dataframe do pandas com os seguintes nomes de coluna:

Resultado1, Teste1, Resultado2, Teste2, Resultado3, Teste3, etc ...

Desejo eliminar todas as colunas cujo nome contém a palavra "Teste". O número dessas colunas não é estático, mas depende de uma função anterior.

Como eu posso fazer isso?

Alexis Eggermont
fonte

Respostas:

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
fonte
2
O OP não especificou que a remoção não diferencia maiúsculas de minúsculas.
Phillip Cloud
163

Esta é uma boa maneira de fazer isso:

df = df[df.columns.drop(list(df.filter(regex='Test')))]
Bindiya12
fonte
47
Ou diretamente no local:df.drop(list(df.filter(regex = 'Test')), axis = 1, inplace = True)
Axel de
7
Esta é uma solução muito mais elegante do que a resposta aceita. Eu dividiria um pouco mais para mostrar o porquê, principalmente extraindo list(df.filter(regex='Test'))para mostrar melhor o que a linha está fazendo. Eu também optaria pela df.filter(regex='Test').columnsconversão de lista
Charles,
2
Esta é muito mais elegante do que a resposta aceita.
deepelement
4
Eu realmente me pergunto o que significam os comentários que dizem que essa resposta é "elegante". Eu mesmo acho isso bastante ofuscado, quando o código python deveria ser lido pela primeira vez. Também é duas vezes mais lento do que a primeira resposta. E ele usa a regexpalavra - chave quando a likepalavra - chave parece ser mais adequada.
Jacquot
2
Esta não é uma resposta tão boa quanto as pessoas afirmam. O problema filteré que ele retorna uma cópia de TODOS os dados como colunas que você deseja eliminar. É um desperdício se você estiver apenas passando esse resultado para drop(que novamente retorna uma cópia) ... uma solução melhor seria str.startswith(adicionei uma resposta com isso aqui).
cs95
41

Mais barato, mais rápido e idiomático: str.contains

Em versões recentes do pandas, você pode usar métodos de string no índice e nas colunas. Aqui, str.startswithparece um bom ajuste.

Para remover todas as colunas começando com uma determinada substring:

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 correspondência que não diferencia maiúsculas de minúsculas, você pode usar a correspondência baseada em regex str.containscom uma âncora 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

se os tipos mistos forem uma possibilidade, especifique na=Falsetambém.

cs95
fonte
15

Você pode filtrar as colunas que deseja 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

Agora filtrar

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

Obter..

   result1  result34
0   2.0     NaN
1   NaN     10.0
SAH
fonte
4
Melhor resposta! Obrigado. Como você filtra o oposto? not like='result'
stallingOne
2
então faça isto: df = df.drop (df.filter (like = 'resultado', eixo = 1) .colunas, eixo = 1)
Amir
14

Isso pode ser feito perfeitamente em uma linha com:

df = df.drop(df.filter(regex='Test').columns, axis=1)
Warren O'Neill
fonte
1
Da mesma forma (e mais rápido):df.drop(df.filter(regex='Test').columns, axis=1, inplace=True)
Max Ghenis
9

Use o 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
fonte
E a op não especificou que um número deve seguir 'Teste': Eu quero descartar todas as colunas cujo nome contém a palavra "Teste" .
7 de
A suposição de que um número segue Test é perfeitamente razoável. Releia a pergunta.
Phillip Cloud
2
vendo agora:FutureWarning: 'select' is deprecated and will be removed in a future release. You can use .loc[labels.map(crit)] as a replacement
flutefreak7
Lembre-se de import reantes.
ijoseph
5

Este método faz tudo no local. Muitas das outras respostas criam cópias e não são tão eficientes:

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

ba0101
fonte
2

Não deixe cair. Pegue o oposto do que você deseja.

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

a maneira mais curta de fazer é:

resdf = df.filter(like='Test',axis=1)
ZacNt
fonte
Isso já foi coberto por esta resposta .
Gino Mempin
1
Embora a resposta vinculada no comentário acima seja semelhante, não é a mesma. Na verdade, é quase o oposto.
Makyen
0

Solução ao eliminar uma lista de nomes de colunas contendo regex. Prefiro essa abordagem porque frequentemente edito a lista suspensa. Usa um regex de filtro negativo para a lista suspensa.

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
fonte