Фильтруйте Dataframe с помощью ~ isin ([list_of_substrings]) - PullRequest
2 голосов
/ 13 февраля 2020

Учитывая данные, заполненные электронными письмами, я хочу отфильтровать строки, содержащие потенциально заблокированные доменные имена или явно поддельные электронные письма. Кадр данных ниже представляет пример моих данных.

>> print(df)

        email                number
1   fake@fake.com              2
2   real.email@gmail.com       1
3   no.email@email.com         5
4   real@yahoo.com             2  
5   rich@money.com             1            

Я хочу отфильтровать по двум спискам. Первый список fake_lst = ['noemail', 'noaddress', 'fake', ... 'no.email']. Второй список - это просто набор from disposable_email_domains import blocklist, преобразованный в список (или сохраненный как набор).

Когда я использую df = df[~df['email'].str.contains('noemail')], он работает нормально и отфильтровывает эту запись. Тем не менее, когда я делаю df = df[~df['email'].str.contains(fake_lst)], я получаю TypeError: unhashable type: 'list'.

Очевидный ответ заключается в использовании df = df[~df['email'].isin(fake_lst)], как и во многих других вопросах, связанных со стековым потоком, например, Фильтр Pandas Кадр данных на основе списка подстрок или pandas, фильтрация с использованием функции isin но в итоге это не дает никакого эффекта.

Полагаю, я мог бы использовать str.contains('string') для каждой возможной записи в списке, но это нелепо громоздко.

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

В приведенном выше примере фрейм данных после фильтрация будет:

>> print(df)

        email                number
2   real.email@gmail.com       1
4   real@yahoo.com             2  
5   rich@money.com             1            

Ответы [ 2 ]

1 голос
/ 13 февраля 2020

Вот потенциальное решение, если у вас есть следующие параметры: df и fake_lst

df = pd.DataFrame({
    'email': ['fake@fake.com', 'real.email@gmail.com', 'no.email@email.com',
              'real@yahoo.com', 'rich@money.com'],
    'number': [2, 1, 5, 2, 1]
})

fake_lst = ['fake', 'money']

Опция 1:

Отфильтровать строки, имеющие любой из fake_lst слов в электронной почте с apply:

df.loc[
    ~df['email'].apply(lambda x: any([i in x for i in fake_lst]))
]
                  email  number
1  real.email@gmail.com       1
2    no.email@email.com       5
3        real@yahoo.com       2

Вариант 2:

Отфильтровать без apply

df.loc[
    [not any(i) for i in zip(*[df['email'].str.contains(word) for word in fake_lst])]
]
                  email  number
1  real.email@gmail.com       1
2    no.email@email.com       5
3        real@yahoo.com       2
0 голосов
/ 13 февраля 2020

Используйте DataFrame.isin , чтобы проверить, содержится ли каждый элемент в DataFrame в значениях. Другая проблема состоит в том, что ваш поддельный список содержит имя без домена, поэтому вам нужно использовать str.split для удаления символов, с которыми вы не соответствуете.

Примечание: str.contains тесты, если шаблон или регулярное выражение содержится в строка серии и, следовательно, ваш код df ['email']. str.contains ('noemail') работает нормально, но не работает для списка

df[~df['email'].str.split('@').str[0].isin(fake_lst)]


    email                   number
0   fake@fake.com           2
1   real.email@gmail.com    1
3   real@yahoo.com          2
4   rich@money.com          1
...