Удалите столбцы, имя которых содержит определенную строку из pandas DataFrame


107

У меня есть фреймворк pandas со следующими именами столбцов:

Результат1, Тест1, Результат2, Тест2, Результат3, Тест3 и т. Д.

Я хочу удалить все столбцы, в названии которых есть слово «Тест». Количество таких столбцов не является статическим, а зависит от предыдущей функции.

Как я могу это сделать?

Ответы:


76
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
OP не указал, что удаление должно производиться без учета регистра.
Филлип Клауд

170

Вот один из способов сделать это:

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

47
Или прямо на месте:df.drop(list(df.filter(regex = 'Test')), axis = 1, inplace = True)
Аксель

7
Это гораздо более элегантное решение, чем принятый ответ. Я бы немного разбил его, чтобы показать почему, в основном извлечение, list(df.filter(regex='Test'))чтобы лучше показать, что делает строка. Я бы также предпочел df.filter(regex='Test').columnsпреобразование списков
Чарльз

3
Этот более элегантный, чем принятый ответ.
deepelement

4
Мне действительно интересно, что означают комментарии, в которых говорится, что этот ответ «элегантный». Я сам нахожу это довольно запутанным, когда код Python сначала должен быть читаемым. Это также вдвое медленнее, чем первый ответ. И он использует regexключевое слово, когда likeключевое слово кажется более подходящим.
Жако

2
На самом деле это не такой хороший ответ, как утверждают люди. Проблема в filterтом, что он возвращает копию ВСЕХ данных в виде столбцов, которые вы хотите удалить. Было бы расточительно, если бы вы только передавали этот результат drop(который снова возвращает копию) ... лучшим решением было бы str.startswith(я добавил ответ с этим здесь).
cs95

43

Дешевле, быстрее и идиоматичнее: str.contains

В последних версиях pandas вы можете использовать строковые методы для индекса и столбцов. Здесь str.startswithвроде как хорошо подходит.

Чтобы удалить все столбцы, начинающиеся с заданной подстроки:

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

Для сопоставления без учета регистра вы можете использовать сопоставление на основе регулярных выражений str.containsс привязкой 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

если возможны смешанные типы, также укажите na=False.


15

Вы можете отфильтровать нужные столбцы с помощью фильтра

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

Теперь фильтровать

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

Получить..

   result1  result34
0   2.0     NaN
1   NaN     10.0

4
Лучший ответ! Спасибо. Как фильтровать противоположное? not like='result'
stallingOne

2
затем сделайте это: df = df.drop (df.filter (like = 'result', axis = 1) .columns, axis = 1)
Amir

14

Это можно сделать аккуратно в одной строке с:

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

1
Аналогично (и быстрее):df.drop(df.filter(regex='Test').columns, axis=1, inplace=True)
Макс Генис,

9

Используйте DataFrame.selectметод:

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

И операционная система не указала, что число должно следовать за «Тестом»: я хочу удалить все столбцы, имя которых содержит слово «Тест» .
7stud

Предположение, что число следует за тестом, вполне разумно. Перечитайте вопрос.
Филлип Клауд

2
теперь вижу:FutureWarning: 'select' is deprecated and will be removed in a future release. You can use .loc[labels.map(crit)] as a replacement
flutefreak7

Не забудьте import reзаранее.
ijoseph

5

Этот метод делает все на месте. Многие другие ответы создают копии и не так эффективны:

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


2

Не роняйте. Поймайте противоположное тому, что хотите.

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

1

Самый короткий способ сделать это:

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

Это уже было рассмотрено в этом ответе .
Джино Мемпин,

1
Хотя ответ, связанный с приведенным выше комментарием, похож, это не то же самое. На самом деле все почти наоборот.
Макиен

0

Решение при удалении списка имен столбцов, содержащих регулярное выражение. Я предпочитаю этот подход, потому что я часто редактирую выпадающий список. Использует регулярное выражение отрицательного фильтра для выпадающего списка.

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)
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.