【问题标题】:Efficient way to convert dictionary of list to pair list of key and value将列表字典转换为键值对列表的有效方法
【发布时间】:2016-06-16 18:26:06
【问题描述】:

我有如下列表的字典(它可以超过1M个元素,也假设字典是按键排序的)

import scipy.sparse as sp
d = {0: [0,1], 1: [1,2,3], 
     2: [3,4,5], 3: [4,5,6], 
     4: [5,6,7], 5: [7], 
     6: [7,8,9]}

我想知道将其转换为行和列索引列表的最有效方法(大型字典的最快方法)是:

r_index = [0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 6, 6, 6]
c_index = [0, 1, 1, 2, 3, 3, 4, 5, 4, 5, 6, 5, 6, 7, 7, 7, 8, 9]

以下是我目前的一些解决方案:

  1. 使用迭代

    row_ind = [k for k, v in d.iteritems() for _ in range(len(v))] # or d.items() in Python 3
    col_ind = [i for ids in d.values() for i in ids]
    
  2. 使用熊猫库

    import pandas as pd
    df = pd.DataFrame.from_dict(d, orient='index')
    df = df.stack().reset_index()
    row_ind = list(df['level_0'])
    col_ind = list(df[0])
    
  3. 使用迭代工具

    import itertools
    indices = [(x,y) for x, y in itertools.chain.from_iterable([itertools.product((k,), v) for k, v in d.items()])]
    indices = np.array(indices)
    row_ind = indices[:, 0]
    col_ind = indices[:, 1]
    

如果我的字典中有很多元素,我不确定哪种方法是处理这个问题的最快方法。谢谢!

【问题讨论】:

  • 出于好奇,你为什么要这样做?
  • 高效在什么方面?代码行?执行时间处理时间?可维护性?访问权限?其他?
  • @nbryans 一个例子是将其转换为稀疏矩阵,即csr_matrix((data, (row_ind, col_ind))。我还想使用 pandas 将此格式插入到 SQL 表中。普通列表格式将采用更易于使用的格式。
  • @Prune 抱歉,我应该说“最快”的执行方式(执行时间)。效率不高。我马上改标题。
  • 那么为什么不自己测量时间并在这里发布呢?该线程可能更适合 stackexchange。

标签: python dictionary itertools


【解决方案1】:

python 中优化的第一条经验法则是,确保将最内层的循环外包给某个库函数。这仅适用于 cpython - pypy 是一个完全不同的故事。 在您的情况下,使用 extend 可以显着加快速度。

import time
l = range(10000)
x = dict([(k, list(l)) for k in range(1000)])

def org(d):
    row_ind = [k for k, v in d.items() for _ in range(len(v))]
    col_ind = [i for ids in d.values() for i in ids]

def ext(d):
    row_ind = [k for k, v in d.items() for _ in range(len(v))]
    col_ind = []
    for ids in d.values():
        col_ind.extend(ids)

def ext_both(d):
    row_ind = []
    for k, v in d.items():
        row_ind.extend([k] * len(v))
    col_ind = []
    for ids in d.values():
        col_ind.extend(ids)

functions = [org, ext, ext_both]
for func in functions:
    begin = time.time()
    func(x)
    elapsed = time.time() - begin
    print(func.__name__ + ": "  + str(elapsed))

使用python2时的输出:

org: 0.512559890747
ext: 0.340406894684
ext_both: 0.149670124054

【讨论】:

    【解决方案2】:

    您可以更改基准的输入大小:

    import time
    l = xrange(10000)
    x = dict([(k, list(l)) for k in xrange(1000)])
    
    
    def f(d):
        row_ind = [k for k, v in d.iteritems() for _ in range(len(v))]
        col_ind = [i for ids in d.values() for i in ids]
    
    
    def ff(d):
        import pandas as pd
        df = pd.DataFrame.from_dict(d, orient='index')
        df = df.stack().reset_index()
        row_ind = list(df['level_0'])
        col_ind = list(df[0])
    
    
    def fff(d):
        import itertools
        import numpy as np
        indices = [(x, y) for x, y in itertools.chain.from_iterable(
            [itertools.product((k,), v) for k, v in d.items()])]
        indices = np.array(indices)
        row_ind = indices[:, 0]
        col_ind = indices[:, 1]
    
    alternatives = [f, ff, fff]
    for func in alternatives:
        begin = time.time()
        func(x)
        print time.time() - begin
    

    输出:

    0.977538108826
    5.26920008659
    6.98472499847
    

    以目前的样本量,第一种方法似乎更好。但是,如果您有更多时间来选择样本大小并等待执行完成,则可能会有不同的结果。使用库可能会更好。

    【讨论】:

    • 非常感谢测试 sn-p @kardaj!我有同样的问题,我不知道哪个代码在更大范围内运行速度最快。
    • 不确定具体的用例,但在这些比较中包含import时间可能公平也可能不公平,我知道pandasnumpy、@987654326之类的东西@-ing 可能需要一点时间。在这种情况下,它看起来不会对结果产生太大影响,但我想我会提到这是需要考虑的事情。
    【解决方案3】:

    有一个函数叫做装饰器。装饰器总是在 def 或 class 函数之上。在您的代码上使用import timer @timer.Timer() 或类似的东西。你可以谷歌更多。或者去这个链接:https://wiki.python.org/moin/PythonDecorators

    【讨论】:

    • 装饰器与这些有什么关系?
    猜你喜欢
    • 2021-12-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多