【问题标题】:How to make this search and count much faster?如何使搜索和计数更快?
【发布时间】:2020-02-02 08:38:09
【问题描述】:
def count_occurrences(string):
    count = 0
    for text in GENERIC_TEXT_STORE:
        count += text.count(string)
    return count

GENERIC_TEXT_STORE 是一个字符串列表。例如:

GENERIC_TEXT_STORE = ['this is good', 'this is a test', 'that's not a test']

给定一个字符串'text',我想找出文本(即'this')在GENERIC_TEXT_STORE 中出现的次数。如果我的 GENERIC_TEXT_STORE 很大,这很慢。有什么方法可以更快地进行搜索和计数?例如,如果我将大 GENERIC_TEXT_STORE 列表拆分为多个较小的列表,那会更快吗?

如果多处理模块在这里有用,如何使它成为可能?

【问题讨论】:

  • 你的函数应该只计算单词(例如isgoodnotthat's),还是应该计算子字符串(例如is g、@987654328 @、t a tesgood)?
  • 我会附议您的要求以澄清您的要求。如果您多次搜索同一个大字符串集合,并且 string 参数始终是一个单词,您可以将集合存储为单词计数的字典。如果string 可以是像 "rbitrary s" 这样的任意子字符串,则可以考虑将其存储为 trie。如果您只在 GENERIC_STRING_STORE 的值更改之前搜索一次,我认为您的代码在一般情况下不容易改进。

标签: python list search


【解决方案1】:

首先,按照上面 cmets 中的建议,检查您的算法是否确实在执行您想要的操作。 count() 方法正在检查子字符串的相等性,如果您想要的是重构代码以仅测试完整的单词,您可能会获得很大的改进。像这样的东西可以作为你的条件。

any((word==string for word in text.split()))

多处理可能会有所帮助,因为您可以将列表拆分为更小的列表(每个内核一个),然后在每个进程完成时将所有结果相加(避免在执行期间进行进程间通信)。我从测试中发现,Python 中的多处理在操作系统之间存在很大差异,Windows 和 Mac 可能需要很长时间才能真正产生进程,而 Linux 似乎做得更快。有人说使用 pstools 为每个进程设置 CPU 亲和性很重要,但我发现这对我的情况没有太大影响。

另一个答案是考虑使用 Cython 将你的 Python 编译成 C 程序,或者用更快的语言重写整个东西,但是当你标记这个答案 Python 时,我假设你并不那么热衷于那个.

【讨论】:

  • 如果搜索是基于单词而不是基于子字符串的(并且取决于具体的用例),人们还可以预处理信息并建立一个索引,其中每个单词都指向它出现的子字符串列表在。
【解决方案2】:

您可以使用re

In [2]: GENERIC_TEXT_STORE = ['this is good', 'this is a test', 'that\'s not a test']

In [3]: def count_occurrences(string):
   ...:     count = 0
   ...:     for text in GENERIC_TEXT_STORE:
   ...:         count += text.count(string)
   ...:     return count

In [6]: import re

In [7]: def count(_str):
   ...:     return len(re.findall(_str,''.join(GENERIC_TEXT_STORE)))
   ...:
In [28]: def count1(_str):
    ...:     return ' '.join(GENERIC_TEXT_STORE).count(_str)
    ...:

现在使用timeit来分析执行时间。

GENERIC_TEXT_STORE 的大小为3 时。

In [9]: timeit count('this')
1.27 µs ± 57.1 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

In [10]: timeit count_occurrences('this')
697 ns ± 25.5 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

In [33]: timeit count1('this')
385 ns ± 22.9 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

GENERIC_TEXT_STORE 的大小为15000 时。

In [17]: timeit count('this')
1.07 ms ± 118 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

In [18]: timeit count_occurrences('this')
3.35 ms ± 279 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

In [37]: timeit count1('this')
275 µs ± 18.2 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

GENERIC_TEXT_STORE 的大小为150000

In [20]: timeit count('this')
5.7 ms ± 2.39 ms per loop (mean ± std. dev. of 7 runs, 100 loops each)

In [21]: timeit count_occurrences('this')
33 ms ± 3.26 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

In [40]: timeit count1('this')
3.98 ms ± 211 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

GENERIC_TEXT_STORE 的大小超过一百万时 (1500000)

In [23]: timeit count('this')
50.3 ms ± 7.21 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

In [24]: timeit count_occurrences('this')
283 ms ± 12.7 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

In [43]: timeit count1('this')
40.7 ms ± 1.09 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

count1

GENERIC_TEXT_STORE 的大小很大时,countcount1 几乎比count_occurrences 快4 到5 倍。

【讨论】:

    猜你喜欢
    • 2014-11-14
    • 2014-07-28
    • 1970-01-01
    • 1970-01-01
    • 2012-02-19
    • 2013-06-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多