Usuń kolumny, których nazwa zawiera określony ciąg z pand DataFrame

106

Mam ramkę danych pandy z następującymi nazwami kolumn:

Wynik1, Test1, Wynik2, Test2, Wynik3, Test3, itd ...

Chcę usunąć wszystkie kolumny, których nazwa zawiera słowo „Test”. Numery takich kolumn nie są statyczne, ale zależą od poprzedniej funkcji.

Jak mogę to zrobić?

Alexis Eggermont
źródło

Odpowiedzi:

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
źródło
2
W OP nie określono, że przy usuwaniu nie będzie rozróżniana wielkość liter.
Phillip Cloud,
165

Oto jeden sposób, aby to zrobić:

df = df[df.columns.drop(list(df.filter(regex='Test')))]
Bindiya12
źródło
47
Lub bezpośrednio na miejscu:df.drop(list(df.filter(regex = 'Test')), axis = 1, inplace = True)
Axel
7
To znacznie bardziej eleganckie rozwiązanie niż przyjęta odpowiedź. Rozbiłbym to nieco bardziej, aby pokazać dlaczego, głównie wyodrębniając, list(df.filter(regex='Test'))aby lepiej pokazać, co robi linia. Wybrałbym również df.filter(regex='Test').columnskonwersję ponad listy
Charles
2
Ta jest o wiele bardziej elegancka niż przyjęta odpowiedź.
deepelement
4
Naprawdę zastanawiam się, co oznaczają komentarze mówiące, że ta odpowiedź jest „elegancka”. Osobiście uważam to za dość zaciemnione, kiedy kod Pythona powinien być najpierw czytelny. Jest również dwukrotnie wolniejszy niż pierwsza odpowiedź. I używa regexsłowa kluczowego, gdy likewydaje się, że jest bardziej adekwatne.
Jacquot
2
W rzeczywistości nie jest to tak dobra odpowiedź, jak twierdzą ludzie. Problem filterpolega na tym, że zwraca kopię WSZYSTKICH danych jako kolumny , które chcesz usunąć. Jest to marnotrawstwo, jeśli przekazujesz ten wynik tylko do drop(co ponownie zwraca kopię) ... lepszym rozwiązaniem byłoby str.startswith(dodałem tutaj odpowiedź z tym).
cs95
42

Tańsze, szybsze i idiomatyczne: str.contains

W najnowszych wersjach pand możesz używać metod ciągów w indeksie i kolumnach. Tutaj,str.startswith wydaje się że dobrze pasuje.

Aby usunąć wszystkie kolumny zaczynające się od danego podciągu:

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

Aby dopasować bez rozróżniania wielkości liter, możesz użyć dopasowania opartego na wyrażeniach regularnych z str.contains z kotwicą 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

jeśli typy mieszane są możliwe, określ na=Falserównież.

cs95
źródło
15

Możesz odfiltrować wybrane kolumny za pomocą „filtru”

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

Teraz filtruj

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

Dostać..

   result1  result34
0   2.0     NaN
1   NaN     10.0
SAH
źródło
4
Najlepsza odpowiedź! Dzięki. Jak filtrujesz przeciwnie? not like='result'
przeciągnięcie 1
2
następnie zrób to: df = df.drop (df.filter (jak = 'wynik', oś = 1). kolumny, oś = 1)
Amir
14

Można to zrobić zgrabnie w jednej linii za pomocą:

df = df.drop(df.filter(regex='Test').columns, axis=1)
Warren O'Neill
źródło
1
Podobnie (i szybciej):df.drop(df.filter(regex='Test').columns, axis=1, inplace=True)
Max Ghenis
9

Użyj DataFrame.selectmetody:

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
źródło
A operacja nie określiła, że ​​po „Test” musi następować liczba: chcę usunąć wszystkie kolumny, których nazwa zawiera słowo „Test” .
7stud
Założenie, że po teście następuje liczba, jest całkowicie uzasadnione. Przeczytaj ponownie pytanie.
Phillip Cloud,
2
teraz widzę:FutureWarning: 'select' is deprecated and will be removed in a future release. You can use .loc[labels.map(crit)] as a replacement
flutefreak7
Pamiętaj o tym import rewcześniej.
ijoseph
5

Ta metoda robi wszystko na swoim miejscu. Wiele innych odpowiedzi tworzy kopie i nie jest tak wydajnych:

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

ba0101
źródło
2

Nie upuszczaj. Złap przeciwieństwo tego, czego chcesz.

df = df.filter(regex='^((?!badword).)*$').columns
Roy Assis
źródło
1

najkrótsza droga to:

resdf = df.filter(like='Test',axis=1)
ZacNt
źródło
To było już objęte tą odpowiedzią .
Gino Mempin
1
Chociaż odpowiedź, do której link znajduje się w powyższym komentarzu, jest podobna, nie jest taka sama. W rzeczywistości jest prawie odwrotnie.
Makyen
0

Rozwiązanie w przypadku usuwania listy nazw kolumn zawierających wyrażenie regularne. Wolę to podejście, ponieważ często edytuję listę rozwijaną. Używa negatywnego wyrażenia regularnego filtru dla listy rozwijanej.

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
źródło