【问题标题】:The best way to know the size of a group of True value in a very large Python bitarray了解非常大的 Python 位数组中一组 True 值大小的最佳方法
【发布时间】:2016-04-25 19:13:34
【问题描述】:

我有一个非常大的 Python bitarray(大小超过一亿)。

我想知道一组 True 值每次出现的偏移量以及每组的大小(连续“1”的数量)。例如:

在一个bitarray(["0001110000110"])中,一组True值第一次出现在偏移量3,大小为3,第二次出现在偏移量10,大小为2。

我尝试循环遍历数组并手动对其进行计数,但循环遍历非常大的位数组似乎不是一种安全的方法。我已经看过 bitarray 的文档,但是我无法从 bitarray 的功能中找到有效的方法。

因此,我想知道是否有任何有效的方法可以做到这一点。

【问题讨论】:

  • 对于一个 1 亿位、5000 万个 True 值的数组,您希望平均找到多少个 True 值?较少的?更多的?也许某种稀疏容器更适合您的用例。

标签: python loops bitarray


【解决方案1】:

如果您正在寻找一种有效的方法来做到这一点,您可以在 C 中做到这一点。这个函数会这样做并返回一个元组数组(位置、长度)。

static PyObject *
bitarray_searchOnes(bitarrayobject *self)
{
    idx_t p = 0;
    idx_t s = 0;

    PyObject *list = PyList_New(0);

    while (p < self->nbits) {
        if (GETBIT(self, p) == 1) {
            s+=1;
        }
        else {
            if (s != 0) {
                PyList_Append(list, (PyTuple_Pack(2,PyLong_FromLongLong(p-s),PyLong_FromLongLong(s))));
                s=0;
            }
        }
        p++;
    }
    if (s != 0) {
        PyList_Append(list, (PyTuple_Pack(2,PyLong_FromLongLong(p-s),PyLong_FromLongLong(s))));
        s=0;
    }
    return list;
}

您可以将其添加到源中的_bitarray.c 并在bitarray_methods 中定义它。你将在 python 中拥有a.searchOne()

编辑:更简单的方法是在 python 中遍历位数组。

def searchOnes(bitarray)
    s=0
    ind=0
    arr=[]
    for i in bitarray:
        if i:
            s+=1
        elif s:
            arr.append((ind-s,s))
            s=0
        ind+=1
    if(s):
        arr.append((ind-s,s))
    return arr

但是在对 23,000,000 位进行一些基准测试之后,这种方法在我的 intel i7 机器上平均占用了大约 3.6 seconds,而 c 实现只占用了 1 second

编辑:这就是我做基准测试的方式:

from bitarray import bitarray
from timeit import timeit
from random import choice

def test_searchOnes():
    ba=bitarray(''.join(choice('01') for _ in xrange(23000000)))
    print timeit(lambda:searchOnes(ba),number=1)  # the python version
    print timeit(lambda:ba.searchOnes(),number=1) # the C version

结果是:

3.37723302841     # the python version
0.754848003387    # the C version

【讨论】:

  • 您能否发布您的基准测试代码,即您生成 2300 万位的方式以及您如何计时运行时?
  • @FrerichRaabe 已编辑。谢谢。
【解决方案2】:

这是一个纯 Python 实现(适用于 Python 2),也许效果更好?

import itertools

def frerich(a):
    groups = ((k, sum(1 for _ in g)) for k, g in itertools.groupby(a))
    offset = 0
    for k, l in groups:
        if k:
            yield (offset, l)
        offset += l

我们的想法是,我们不是单独迭代每个位,而是让itertools.groupbysum 为我们这样做(假设它们非常有效),然后仅迭代连续元素组,yielding True 组的偏移量和长度。此外,该函数不会基于您甚至不需要内存中的列表的假设来构建列表。相反,它是一个生成器。

【讨论】:

    猜你喜欢
    • 2017-01-10
    • 1970-01-01
    • 2020-10-24
    • 1970-01-01
    • 2022-12-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-09
    相关资源
    最近更新 更多