以最pythonic的方式迭代和比较两个python字典,以便快速执行

2024-10-08 20:20:14 发布

您现在位置:Python中文网/ 问答频道 /正文

def formoutput(teams_id, patent_team):
    """
    The function to compare team_id and patent_teams to form the default dictionary matching values
    :param teams_id: {('3879797-2', '3930281-2'): 1, ('3930282-1', '3930282-2'): 2, ('3930288-1', '3930288-2'): 3, ... }
    :param patent_team: {3930281: [[('3879797-2', '3930281-2')]], 3930282: [[('3930282-1', '3930282-2')]], 3930288: [[('3930288-1', '3930288-2')]], ... }
    :return: defaultdict(<function formoutput.<locals>.<lambda> at 0x0000022A45228240>, {3930281: defaultdict(<class 'list'>, {'3879797-2': [1], '3930281-2': [1]}), 3930282: defaultdict(<class 'list'>, {'3930282-1': [2], '3930282-2': [2]}), 3930288: defaultdict(<class 'list'>, {'3930288-1': [3], '3930288-2': [3]}), 3930292: defaultdict(<class 'list'>, {'3861607-1': [4], '3861607-2': [4]}), ..}

    """
    print("Forming Output")
    print("Teams id =", teams_id)
    print("Patent_team=", patent_team)
    output_dict = defaultdict(lambda: defaultdict(list))
    try:
        for k,v in teams_id.items():
            for a,b in patent_team.items():
                for i in b:
                    if k in i:
                        for z in k:
                            output_dict[a][z].append(v)
    except Exception as e:
        print(e)
    return output_dict

我有一个函数,我以python字典的形式向它传递两个参数。第一个字典的键作为第二个字典的值出现。我需要比较第一个字典中的每个键在第二个字典中是否存在一个值,然后使用键、第一个字典中的值和第二个字典中的键将值附加到defaultdict中。请看一下上面的代码,这将有助于更好地理解代码。 多个嵌套循环使得代码非常慢。我在第一本字典里有超过5000万个键值对。在第二个字典里有超过300万个键,每个键平均包含3个值。你知道吗

代码背后的整个思想是找到所有可能的发明人对,他们曾经以某种组合的方式参与过一项专利的工作,这些组合需要作为{patent\u id:inventor\u team,team\u id}的输出。目前,执行相同的代码需要几个小时。我运行了100000个键值对,大约花了2000秒,这是很长的时间。你知道吗

请为我提供一个最好的整体解决方案可能的方法。还有,处理如此海量数据的最佳方式是什么?你知道吗


Tags: 代码inidforoutput字典dictteam
2条回答

两种改进方法,看哪一种对你方便:

首先我要颠倒你的循环顺序:

for a,b in patent_team.items():
    for i in b:
        for k in i:
            if k in teams_id:
                for z in k:
                    output_dict[a][z].append(teams_id[k])

因为我假设patent_teams是一个比teams_id更小的dict,我可以使用teams_id上的O(1)查找,而不是每个项上的O(n)迭代。你知道吗

第二种方法是在合并之前转换数据。您可以尝试将这两个字典整理成表格形式,并将其放入DataFrame中,甚至可以将它们保存到数据库中(在本例中,SQLite会很方便)。这样做的好处是,您可能会从Python解释器中卸载表连接/数据帧合并操作。这样更快。你知道吗

如果列表包装确实是多余的,并且忽略了相应键不在team_ids中的情况,则可以在此处显著减少循环和成员资格测试的数量:

def formoutput(teams_id, patent_team):
    """
    The function to compare team_id and patent_teams to form the default dictionary matching values
    :param teams_id: {('3879797-2', '3930281-2'): 1, ('3930282-1', '3930282-2'): 2, ('3930288-1', '3930288-2'): 3, ... }
    :param patent_team: {3930281: [[('3879797-2', '3930281-2')]], 3930282: [[('3930282-1', '3930282-2')]], 3930288: [[('3930288-1', '3930288-2')]], ... }
    :return: defaultdict(<function defaultdict.copy>, {3930281: defaultdict(list, {'3879797-2': [1], '3930281-2': [1]}), 3930282: defaultdict(list, {'3930282-1': [2], '3930282-2': [2]}), 3930288: defaultdict(list, {'3930288-1': [3], '3930288-2': [3]}), 3930292: defaultdict(list, {'3861607-1': [4], '3861607-2': [4]}), ..}
    ...:
    """
    print("Forming Output")
    print("Teams id =", teams_id)
    print("Patent_team=", patent_team)
    # I hate lambdas, and as it happens, we don't need'em;
    # defaultdict(list).copy is cleaner and faster
    output_dict = defaultdict(defaultdict(list).copy)
    try:
        # [[pvs]] unpacks the superfluous(?) lists wrapping the tuple we care about
        for pk, [[pvs]] in patent_team.items():
            # Get the value to set once up front
            try:
                v = teams_id[pvs]
            except KeyError:
                continue  # Don't have a value to set, so move to next
            # Perform the first layer of dict lookup once since the key is the same
            # each time to avoid cost of repeated lookup
            pkdict = output_dict[pk]
            for pv in pvs:
                pkdict[pv].append(v)
    except Exception as e:
        print(e)
    return output_dict

在反向循环中,由于patent_teams键是外部结果defaultdict的键,因此首先循环patent_teams是有意义的,避免对每个patent_teams键重复查找output_dict。这也意味着您可以使用patent_teams中的值直接从teams_id中查找所需内容,而不是通过teams_id进行迭代搜索。你知道吗

如果list包装不是多余的,请替换:

for pk, [[pvs]] in patent_team.items():

使用:

for pk, pvs_lists in patent_team.items():
    for pvs in chain.from_iterable(pvs_lists):

确保在文件的顶部包含importfrom itertools import chain。你知道吗

相关问题 更多 >

    热门问题