Python/Pandas: удалить строки из фрейма данных из строки из списка

У меня есть .csv файл контактной информации, который я импортирую как фрейм данных pandas.

>>> import pandas as pd
>>> 
>>> df = pd.read_csv('data.csv')
>>> df.head()

  fName   lName                    email   title
0  John   Smith         [email protected]     CEO
1   Joe   Schmo      [email protected]  Bagger
2  Some  Person  [email protected]   Clerk

После импорта данных я хотел бы удалить строки, где одно поле содержит одну из нескольких подстрок в списке. Например:

to_drop = ['Clerk', 'Bagger']

for i in range(len(df)):
    for k in range(len(to_drop)):
        if to_drop[k] in df.title[i]:
            # some code to drop the rows from the data frame

df.to_csv("results.csv")

Каков предпочтительный способ сделать это в Pandas? Должен ли этот шаг быть пост-обработкой или предпочтительнее фильтровать это до записи в фрейм данных в первую очередь? Я думал, что это будет проще манипулировать один раз в объекте фрейма данных.

Ответ 1

Используйте isin и передайте свой список терминов для поиска, затем вы можете отменить булевую маску с помощью ~, и это будет отфильтровывать эти строки:

In [6]:

to_drop = ['Clerk', 'Bagger']
df[~df['title'].isin(to_drop)]
Out[6]:
  fName  lName             email title
0  John  Smith  [email protected]   CEO

Другим методом является объединение терминов, поэтому оно становится регулярным выражением и использует векторизованный str.contains:

In [8]:

df[~df['title'].str.contains('|'.join(to_drop))]
Out[8]:
  fName  lName             email title
0  John  Smith  [email protected]   CEO

IMO будет проще и, вероятно, быстрее выполнить фильтрацию в качестве этапа пост-обработки, потому что, если вы решите фильтровать во время чтения, то вы итеративно увеличиваете число кадров, которое неэффективно.

В качестве альтернативы вы можете прочитать фрагменты csv, отфильтровать строки, которые вы не хотите, и добавить фрагменты к выходу csv

Ответ 2

Другой способ: query

In [961]: to_drop = ['Clerk', 'Bagger']

In [962]: df.query('title not in @to_drop')
Out[962]:
  fName  lName             email title
0  John  Smith  [email protected]   CEO