【问题标题】:Python - keep rows in dataframe based on partial string matchPython - 根据部分字符串匹配在数据框中保留行
【发布时间】:2020-07-12 17:32:57
【问题描述】:

我有 2 个数据框:
df1 是邮箱和电子邮件 ID 的列表
df2 显示已批准域的列表

我从 Excel 表中读取了两个数据框

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

我只想在 df1[Email_Id] 包含 df2[approved_domain] 的 df1 中保留记录

    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'

我花了很多时间研究论坛的解决方案,但找不到我要找的东西。感谢所有帮助。

【问题讨论】:

  • 粘贴你的代码,尤其是df1和df2的定义
  • 更新了帖子,我从 excel 选项卡中读取并使用我在主帖子中放入的代码将其加载到 df 中

标签: python string dataframe contains partial


【解决方案1】:

所以这些是你需要遵循的步骤来为你的两个数据框做你想做的事情

1.将您的 email_address 列拆分为两个单独的列

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

2.然后删除添加列以保持数据框干净

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

3.通过不在“domain”列中选择与“approved_doman”列不匹配的任何值来获取仅包含您想要的值的新数据框

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

4。删除 df_new 中的“域”列

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

这就是结果

    mailbox     email_address
1   mailbox2    def@yahoo.com
2   mailbox3    ghi@msn.com

【讨论】:

    【解决方案2】:

    您可以使用动态创建的正则表达式在列表中搜索有效域并最终将其过滤掉。

    这是供我们参考的代码。

     # -*- 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
    

    【讨论】:

      【解决方案3】:

      解决方案

      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')}                                                                                                                                                             
      
      

      一些注意事项:

      这段代码的大部分基本上只是用于解析数据结构。压缩和解压缩仅用于将列列表转换为行列表并返回。如果你已经有一个行列表,你只需要做过滤部分

      【讨论】:

        猜你喜欢
        • 2021-09-08
        • 1970-01-01
        • 2021-04-17
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多