【问题标题】:How to efficiently search a list in python如何在python中有效地搜索列表
【发布时间】:2019-10-30 14:32:11
【问题描述】:

我有一个只有 4 个键 (mydictionary) 和一个列表 (mynodes) 的字典,如下所示。

    mydictionary = {0: {('B', 'E', 'G'), ('A', 'E', 'G'), ('A', 'E', 'F'), ('A', 'D', 'F'), ('C', 'D', 'F'), ('C', 'E', 'F'), ('A', 'D', 'G'), ('C', 'D', 'G'), ('C', 'E', 'G'), ('B', 'E', 'F')}, 
1: {('A', 'C', 'G'), ('E', 'F', 'G'), ('D', 'E', 'F'), ('A', 'F', 'G'), ('A', 'B', 'G'), ('B', 'D', 'F'), ('C', 'F', 'G'), ('A', 'C', 'E'), ('D', 'E', 'G'), ('B', 'F', 'G'), ('B', 'C', 'G'), ('A', 'C', 'D'), ('A', 'B', 'F'), ('B', 'D', 'G'), ('B', 'C', 'F'), ('A', 'D', 'E'), ('C', 'D', 'E'), ('A', 'C', 'F'), ('A', 'B', 'E'), ('B', 'C', 'E'), ('D', 'F', 'G')}, 
2: {('B', 'D', 'E'), ('A', 'B', 'D'), ('B', 'C', 'D')}, 
3: {('A', 'B', 'C')}}

mynodes = ['E', 'D', 'G', 'F', 'B', 'A', 'C']

我正在检查mynodes 列表中的每个节点在mydictionary 的每个键中出现了多少次。例如,考虑上面的字典和列表。

输出应该是;

{'E': [(0, 6), (1, 8), (2, 1), (3, 0)], 
'D': [(0, 4), (1, 8), (2, 3), (3, 0)], 
'G': [(0, 5), (1, 10), (2, 0), (3, 0)], 
'F': [(0, 5), (1, 10), (2, 0), (3, 0)], 
'B': [(0, 2), (1, 9), (2, 3), (3, 1)], 
'A': [(0, 4), (1, 9), (2, 1), (3, 1)], 
'C': [(0, 4), (1, 9), (2, 1), (3, 1)]}

例如,考虑E。在0键中出现6次,在1键中出现8次,在2键中出现2次,在3键中出现0次。

我目前的代码如下。

    triad_class_for_nodes = {}

    
    for node in mynodes:
        temp_list = []
                
        for key, value in mydictionary.items():                
            temp_counting = 0
            
            for triad in value:
                #print(triad[0])
                if node in triad:
                    temp_counting = temp_counting + 1
            temp_list.append(tuple((key, temp_counting)))
    
        triad_class_for_nodes.update({node: temp_list})
    print(triad_class_for_nodes)

这适用于小字典值。

但是,在我的真实数据集中,我的字典中的 4 个键中的每一个的值列表中都有数百万个元组。因此,我现有的代码效率非常低,需要几天才能运行。

当我搜索如何提高效率时,我遇到了这个问题 (Fastest way to search a list in python),它建议将值列表设置为一组。我也试过这个。但是,它也需要几天的时间才能运行。

我只是想知道在 python 中是否有更有效的方法来执行此操作。 我很高兴将我现有的数据格式转换为不同的结构(例如pandas dataframe)以提高效率。

下面附上mydictionarymynodes 的小样本用于测试目的。 https://drive.google.com/drive/folders/15Faa78xlNAYLPvqS3cKM1v8bV1HQzW2W?usp=sharing

  • mydictionary:见 triads.txt

    with open("triads.txt", "r") as file: mydictionary = ast.literal_eval(file.read)

mynodes:参见nodes.txt

with open("nodes.txt", "r") as file:  
   mynodes = ast.literal_eval(file.read) 

如果需要,我很乐意提供更多详细信息。

【问题讨论】:

    标签: python list


    【解决方案1】:

    既然你标记了pandas,首先我们需要将你的dict转换为pandas dataframe,然后我们stack it,并使用crosstab

    s=pd.DataFrame.from_dict(mydictionary,'index').stack()
    
    
    s = pd.DataFrame(s.values.tolist(), index=s.index).stack()
    pd.crosstab(s.index.get_level_values(0),s)
    col_0  A  B  C  D  E   F   G
    row_0                       
    0      4  2  4  4  6   5   5
    1      9  9  9  8  8  10  10
    2      1  3  1  3  1   0   0
    3      1  1  1  0  0   0   0
    

    更新

    s=pd.crosstab(s.index.get_level_values(0), s).stack().reset_index()
    
    s[['row_0',0]].apply(tuple,1).groupby(s['col_0']).agg(list).to_dict()
    

    【讨论】:

    • 感谢您的回答。您认为它比我现有的解决方案更有效吗?
    • @Emi 在效率方面我认为这取决于您的数据大小,但是 pd.crosstab 数据比元组列表的字典更好看
    • 谢谢。我将为我的实际数据集运行您的代码,并让您知道它的执行情况:)
    • 只是想知道如何将您的最终输出转换为如下内容:{'E': [(0, 6), (1, 8), (2, 1), (3, 0)], 'D': [(0, 4), (1, 8), (2, 3), (3, 0)], 'G': [(0, 5), (1, 10), (2, 0), (3, 0)], 'F': [(0, 5), (1, 10), (2, 0), (3, 0)], 'B': [(0, 2), (1, 9), (2, 3), (3, 1)], 'A': [(0, 4), (1, 9), (2, 1), (3, 1)], 'C': [(0, 4), (1, 9), (2, 1), (3, 1)]} 请让我知道您的想法:)
    • 我没有通过这个解决方案获得很多性能提升。但是,它是一个干净而漂亮的代码,与我的代码相比,我喜欢它:)
    【解决方案2】:

    如果您不使用 pandas,则可以使用来自集合的 Counter:

    from collections import Counter,defaultdict
    from itertools import product
    counts = Counter((c,k) for k,v in mydictionary.items() for t in v for c in t )
    result = defaultdict(list)
    for c,k in product(mynodes,mydictionary):
        result[c].append((k,counts[(c,k)]))
    
    print(result)
    {'E': [(0, 6), (1, 8), (2, 1), (3, 0)],
     'D': [(0, 4), (1, 8), (2, 3), (3, 0)],
     'G': [(0, 5), (1, 10), (2, 0), (3, 0)],
     'F': [(0, 5), (1, 10), (2, 0), (3, 0)],
     'B': [(0, 2), (1, 9), (2, 3), (3, 1)],
     'A': [(0, 4), (1, 9), (2, 1), (3, 1)],
     'C': [(0, 4), (1, 9), (2, 1), (3, 1)]}
    

    Counter 将为 mydictionary 键和节点的每个组合管理计数实例。然后,您可以使用这些计数来创建预期的输出。

    编辑扩展计数行:

    counts = Counter()                          # initialize Counter() object
    for key,tupleSet in mydictionary.items():   # loop through dictionary
        for tupl in tupleSet:                   # loop through tuple set of each key
            for node in tupl:                   # loop through node character in each tuple
                counts[(node,key]] += 1         # count 1 node/key pair
    

    【讨论】:

    • 您好,非常感谢您的回答。你认为这比我的代码更有效率吗? :) 我也会在我的数据集中测试它并告诉你。
    • 如果您能帮助我扩展此行counts = Counter((c,k) for k,v in mydictionary.items() for t in v for c in t ),将不胜感激。 `
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-26
    • 1970-01-01
    • 2015-04-02
    • 2019-05-23
    • 1970-01-01
    相关资源
    最近更新 更多