使用字典值过滤数据帧,同时将字典键分配给匹配的行?

时间:2017-09-01 20:33:34

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

我有一个带有列的数据框'链接'包含几千个在线文章的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'})

我希望过滤数据框,只获得那些“链接”的观察结果。 column包含字典值中的域,而同时将字典键中的发布名称分配给新列' Publication。'我设想的是使用以下代码来创建出版物'列然后从该列中删除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运算符的解决方案。

2 个答案:

答案 0 :(得分:1)

这就是我要做的事情:

  1. 使用DataFrame.merge向仅包含域的数据框添加新列。

  2. 使用can't use bind variables(使用how='inner'选项)合并您域域中的两个数据框。

  3. 如果他们只是在列或行上进行迭代,那么使用循环对数据帧执行操作会有点脏,而且通常会有一个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']]
    

答案 1 :(得分: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'] != '']