【问题标题】:Filter dataframe with dictionary values while assigning dictionary keys to matching rows?使用字典值过滤数据框,同时将字典键分配给匹配的行?
【发布时间】:2018-02-10 22:56:48
【问题描述】:

我有一个带有“链接”列的数据框,其中包含数千篇在线文章的 URL。每个观察都有一个 URL。

urls_list = ['http://www.ajc.com/news/world/atlan...',
             'http://www.seattletimes.com/sports/...',
             'https://www.cjr.org/q_and_a/washing...',
             'https://www.washingtonpost.com/grap...',
             'https://www.nytimes.com/2017/09/01/...',
             'http://www.oregonlive.com/silicon-f...']

df = pd.DataFrame(urls_list,columns=['Links'])

我还有一个字典,其中包含 出版物名称 作为键和 域名 作为值。

urls_dict = dict({'Atlanta Journal-Constitution':'ajc.com',
                  'The Washington Post':'washingtonpost.com',
                  'The New York Times':'nytimes.com'})

我想过滤数据框以仅获取那些“链接”列包含字典值中的域的观察结果,同时同时在字典键中分配出版物名称到新列“出版物”。我的设想是使用下面的代码创建“发布”列,然后从该列中删除None 以在事后过滤数据框。

pub_list = []

for row in df['Links']:
    for k,v in urls_dict.items():
        if row.find(v) > -1:
            publication = k
        else:
            publication = None
        pub_list.append(publication)

但是,我得到的回报列表pub_list - 虽然似乎按照我的意愿行事 - 是我的数据帧的三倍。有人可以建议如何修复上述代码吗?或者,或者,建议一个更清洁的解决方案,可以(1)使用字典值(域名)过滤我的数据框的“链接”列,同时(2)创建字典键的新“发布”列(出版物名称) ? (请注意,为简洁起见,此处创建的 df 只有一列;实际文件将有很多列,因此我必须能够指定要过滤的列。)

编辑:我想澄清一下 RagingRoosevelt 的 答案。我想避免使用合并,因为某些域可能不完全匹配。例如,对于ajc.com,我还希望能够捕获myajc.com,对于washingtonpost.com,我还希望获得像live.washingtonpost.com 这样的子域。因此,我希望使用str.contains()find()in 运算符找到一种“在字符串中查找子字符串”的解决方案。

【问题讨论】:

    标签: python python-3.x dictionary for-loop dataframe


    【解决方案1】:

    我能够使用嵌套字典理解(或者使用嵌套列表理解)以及一些额外的数据框操作来清理列并删除空白行来解决这个问题。

    使用嵌套字典推导(或者,更具体地说,嵌套在列表推导中的字典推导):

    df['Publication'] = [{k: k for k,v in urls_dict.items() if v in row} for row in df['Links']]
    
    # Format the 'Publication' column to get rid of duplicate 'key' values
    df['Publication'] = df['Publication'].astype(str).str.strip('{}').str.split(':',expand=True)[0]
    
    # Remove blank rows from 'Publication' column
    df = df[df['Publication'] != '']
    

    同样,使用嵌套列表推导

    # First converting dict to a list of lists 
    urls_list_of_lists = list(map(list,urls_dict.items()))
    
    # Nested list comprehension using 'in' operator 
    df['Publication'] = [[item[0] for item in urls_list_of_lists if item[1] in row] for row in df['Links']]
    
    # Format the 'Publication' column to get rid of duplicate brackets
    df['Publication'] = df['Publication'].astype(str).str.strip('[]')
    
    # Remove blank rows from 'Publication' column
    df = df[df['Publication'] != '']
    

    【讨论】:

      【解决方案2】:

      这是我要做的:

      1. 使用DataFrame.apply 将新列添加到仅包含域的数据框中。

      2. 使用DataFrame.merge(带有how='inner' 选项)合并域字段中的两个数据框。

      如果它们只是在列或行上迭代,那么使用循环对数据帧做一些事情有点脏,而且通常有一个 DataFrame 方法可以更干净地做同样的事情。

      如果你愿意,我可以用例子来扩展它。

      编辑这就是它的样子。请注意,我使用了相当糟糕的正则表达式进行域捕获。

      def domain_extract(row):
          s = row['Links']
          p = r'(?:(?:\w+)?(?::\/\/)(?:www\.)?)?([A-z0-9.]+)\/.*'
          m = re.match(p, s)
          if m is not None:
              return m.group(1)
          else:
              return None
      
      df['Domain'] = df.apply(domain_extract, axis=1)
      
      dfo = pd.DataFrame({'Name': ['Atlanta Journal-Constitution', 'The Washington Post', 'The New York Times'], 'Domain': ['ajc.com', 'washingtonpost.com', 'nytimes.com']})
      
      df.merge(dfo, on='Domain', how='inner')[['Links', 'Domain', 'Name']]
      

      【讨论】:

      • 谢谢。这可行,但我想避免使用 merge,因为某些域可能不是 exact 匹配项。例如,对于ajc.com,我还希望能够捕获myajc.com,对于washingtonpost.com,我还希望获得像live.washingtonpost.com 这样的子域。因此,我希望有一种带有str.contains()find() 的“在字符串中查找子字符串”解决方案,以增加灵活性。
      • 看起来应该可以做模糊匹配stackoverflow.com/questions/13636848/…
      猜你喜欢
      • 2019-01-23
      • 2020-09-10
      • 2021-10-25
      • 1970-01-01
      • 2022-10-14
      • 1970-01-01
      • 1970-01-01
      • 2020-05-19
      • 1970-01-01
      相关资源
      最近更新 更多