【问题标题】:Python dictionary too slow for crosscomparison, improvements? [closed]Python 字典对于交叉比较来说太慢了,改进? [关闭]
【发布时间】:2016-03-21 09:56:50
【问题描述】:

我目前在使用 Python 字典时遇到性能问题。我有一些巨大的字典(最多 30k 个条目),我想对这些条目进行交叉比较。所以,如果给定一个条目(标识符是一个键),那么还有多少其他字典包含这个带有这个键的条目呢?目前在我的机器上最多需要 5 小时,但它应该在大约几分钟内工作,以便对我的工具有意义。我已经尝试删除条目以提高搜索效率。

all_cached_data 是一个包含这些字典列表的列表。 sources 是一个列表,其中包含有关 all_cached_data 中列表的信息。

appearsin_list = []

# first, get all the cached data
sources = sp.get_sources()
all_cachedata = [0]*len(sources)
for source in sources:
    iscached = source[8]
    sourceid = int(source[0])
    if iscached == "True":
        cachedata, _ = get_local_storage_info(sourceid)
    else:
        cachedata = []
    all_cachedata[sourceid-1] = cachedata

# second, compare cache entries
# iterate over all cached sources
for source in sources:
    sourceid = int(source[0])
    datatype = source[3]
    iscached = source[8]
    if verbose:
        print("Started comparing entries from source " + str(sourceid) +
              " with " + str(len(all_cachedata[sourceid-1])) + " entries.")

    if iscached == "True":
        # iterate over all other cache entries
        for entry in all_cachedata[sourceid-1]:
            # print("Comparing source " + str(sourceid) + " with source " + str(cmpsourceid) + ".")
            appearsin = 0
            for cmpsource in sources:
                cmpsourceid = int(cmpsource[0])
                cmpiscached = cmpsource[8]
                # find entries for same potential threat
                if cmpiscached == "True" and len(all_cachedata[cmpsourceid-1]) > 0 and cmpsourceid != sourceid:
                        for cmpentry in all_cachedata[cmpsourceid-1]:
                            if datatype in cmpentry:
                                if entry[datatype] == cmpentry[datatype]:
                                    appearsin += 1
                                    all_cachedata[cmpsourceid-1].remove(cmpentry)
                                    break

            appearsin_list.append(appearsin)
            if appearsin > 0:
                if verbose:
                    print(entry[datatype] + " appears also in " + str(appearsin) + " more source/s.")
            all_cachedata[sourceid-1].remove(entry)

avg = float(sum(appearsin_list)) / float(len(appearsin_list))

print ("Average appearance: " + str(avg))
print ("Median: " + str(numpy.median(numpy.array(appearsin_list))))
print ("Minimum: " + str(min(appearsin_list)))
print ("Maximum: " + str(max(appearsin_list)))

非常感谢您提供一些加快速度的提示。

【问题讨论】:

  • 是什么让您认为脚本语言中的四重嵌套循环是处理 30k 数据的好方法?
  • 这正是我的问题,遗憾的是,我知道这不是一个好方法,所以我来到这里。但作为一个矩阵乘法,这似乎就是这样:不是很快,也不是真的,以算法的方式,可增加的。所以我必须处理它,也许有更快的东西。我已经考虑过 numpy,但我不知道如何将我的数据映射到 numpy 数组中。
  • 你需要修正你的算法。目前尚不清楚代码的哪些部分重要,哪些不重要,例如cmpsource[8]。与其解释所有术语,不如编写一些新代码,这正是您想要的机制,即比较和删除,并带有一些简单的数据。了解如何创建minimal reproducible example
  • 感谢您的建设性回复。

标签: python performance dictionary comparison iteration


【解决方案1】:

我认为你的算法可以改进;在这种情况下,嵌套循环不是很好。我还认为 Python 可能不是这个特定目的的最佳选择:使用 SQL 在大量数据中进行比较和搜索。您可以使用 sqlite_object 之类的东西将您的数据集转换为 SQLite 数据库并进行查询。 如果你想继续使用纯 Python,你可以尝试用 Cython 编译你的脚本;您可以在速度上有一些合理的改进。

http://docs.cython.org/src/tutorial/pure.html

然后你可以通过一些静态类型提示来改进你的代码:

http://docs.cython.org/src/tutorial/pure.html#static-typing

【讨论】:

  • 非常感谢。在这种情况下,可以使用 SQL,但我真的没有考虑过。应该比它快很多。
猜你喜欢
  • 1970-01-01
  • 2020-08-08
  • 1970-01-01
  • 1970-01-01
  • 2018-12-16
  • 2016-05-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多