Python - сохранить строки в кадре данных на основе частичного совпадения строк - PullRequest
1 голос
/ 01 апреля 2020

У меня есть 2 кадра данных:
df1 - список почтовых ящиков и идентификаторов электронной почты
df2 показывает список разрешенных доменов

Я прочитал оба кадра данных с листа Excel

    xls = pd.ExcelFile(input_file_shared_mailbox)
    df = pd.read_excel(xls, sheet_name = sheet_name_shared_mailbox)

я хочу хранить записи только в df1, где df1 [Email_Id] содержит df2 [одобренный_домен]

    print(df1)  
        Mailbox Email_Id  
    0   mailbox1   abc@gmail.com  
    1   mailbox2   def@yahoo.com  
    2   mailbox3   ghi@msn.com  

    print(df2)  
        approved_domain  
    0   msn.com  
    1   gmail.com  

и я хочу df3, который в основном показывает

    print (df3)  
        Mailbox Email_Id  
    0   mailbox1   abc@gmail.com  
    1   mailbox3   ghi@msn.com  

это код, который у меня есть сейчас, который я думаю, близок, но я не могу понять точную проблему в синтаксисе

df3 = df1[df1['Email_Id'].apply(lambda x: [item for item in x if item in df2['Approved_Domains'].tolist()])]

Но получите эту ошибку

TypeError: unhashable type: 'list'

Я потратил много времени на поиски решения для форума, но не смог найти то, что искал. ценим всю помощь.

Ответы [ 3 ]

2 голосов
/ 01 апреля 2020

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

1. Разделить столбец email_address на два отдельных столбца

     df1['add'], df1['domain'] = df1['email_address'].str.split('@', 1).str

2 Затем удалите столбец добавления, чтобы сохранить ваш фрейм данных в чистоте

      df1 = df1.drop('add',axis =1)

3.Получить новый фрейм данных только с теми значениями, которые вам нужны, не выбирая в столбце «домен» никакого значения, которое не соответствует «. Столбец утвержденных_домен

      df_new = df1[~df1['domain'].isin(df2['approved_domain'])]

4. Удалите столбец 'domain' в df_new

      df_new = df_new.drop('domain',axis = 1)

Вот каков будет результат

    mailbox     email_address
1   mailbox2    def@yahoo.com
2   mailbox3    ghi@msn.com
2 голосов
/ 01 апреля 2020

Вы можете использовать динамически создаваемое регулярное выражение для поиска допустимого домена в списке и последующей его фильтрации.

Вот код для нашей справки.

 # -*- coding: utf-8 -*-

import pandas as pd
import re

mailbox_list = [
        ['mailbox1', 'abc@gmail.com'],
        ['mailbox2', 'def@yahoo.com'],
        ['mailbox3', 'ghi@msn.com']]

valid_domains = ['msn.com', 'gmail.com']

df1 = pd.DataFrame(mailbox_list, columns=['Mailbox', 'EmailID'])
df2 = pd.DataFrame(valid_domains)

valid_list = []

for index, row in df1.iterrows():
    for idx, record in df2.iterrows():
        if re.search(rf"@{record[0]}", row[1], re.IGNORECASE):
            valid_list.append([row[0], row[1]])

df3 = pd.DataFrame(valid_list, columns=['Mailbox', 'EmailID'])
print(df3)

Вывод это:

    Mailbox        EmailID
0  mailbox1  abc@gmail.com
1  mailbox3    ghi@msn.com
1 голос
/ 01 апреля 2020

Решение

df1 = {'MailBox': ['mailbox1', 'mailbox2', 'mailbox3'], 'Email_Id': ['abc@gmail.com', 'def@yahoo.com', 'ghi@msn.com']}
df2 = {'approved_domain':['msn.com', 'gmail.com']}

mailboxes, emails = zip( # unzip the columns
    *filter( # filter 
        lambda i: any([  # i = ('mailbox1', 'abc@gmail.com')
            approved_domain in i[1] for approved_domain in df2['approved_domain']
        ]),
        zip(df1['MailBox'], df1['Email_Id']) # zip the columns
    )
)

df3 = {
    'MailBox': mailboxes, 
    'Email_I': emails
}
print(df3)

Вывод:

> {'Email_ID': ('abc@gmail.com', 'ghi@msn.com'), 'MailBox': ('mailbox1', 'mailbox3')}                                                                                                                                                             

Некоторые примечания:

Большая часть этого кода в основном только для анализа структуры данных. Zip и распаковка только для того, чтобы преобразовать список столбцов в список строк и обратно. Если у вас уже есть список строк, вам просто нужно выполнить часть фильтрации

...