Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/301.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在Python中优化大型布尔值集(75000项)上的操作?_Python_Optimization_Python 2.6_Large Data - Fatal编程技术网

如何在Python中优化大型布尔值集(75000项)上的操作?

如何在Python中优化大型布尔值集(75000项)上的操作?,python,optimization,python-2.6,large-data,Python,Optimization,Python 2.6,Large Data,有一个脚本称为,我正在尝试调整和优化一点。不过,我对Python完全陌生,所以这并不容易 当前的问题似乎与脚本中名为RevisionSet的类有关。本质上,它所做的是创建一个包含整数键控布尔值的大型哈希表(?)。在最坏的情况下,SVN存储库中的每个版本都有一个版本,现在已经接近75000 然后,它对如此巨大的数组执行集合运算——加法、减法、求交等等。该实现是最简单的O(n)实现,在如此大的集合上自然会变得非常慢。由于连续值的跨度较长,因此可以优化整个数据结构。例如,从1到74000的所有键都可能

有一个脚本称为,我正在尝试调整和优化一点。不过,我对Python完全陌生,所以这并不容易

当前的问题似乎与脚本中名为
RevisionSet
的类有关。本质上,它所做的是创建一个包含整数键控布尔值的大型哈希表(?)。在最坏的情况下,SVN存储库中的每个版本都有一个版本,现在已经接近75000

然后,它对如此巨大的数组执行集合运算——加法、减法、求交等等。该实现是最简单的O(n)实现,在如此大的集合上自然会变得非常慢。由于连续值的跨度较长,因此可以优化整个数据结构。例如,从1到74000的所有键都可能包含
true
。另外,该脚本是为Python2.2编写的,这是一个非常旧的版本,我们使用的是2.6,因此在这方面也可能有所收获


我可以自己尝试拼凑起来,但这将是困难的,需要很多时间——更不用说它可能已经在某处实现了。虽然我喜欢学习经验,但现在结果更重要。您建议我怎么做?

您可以尝试使用numpy而不是普通python。我发现像这样的操作速度非常快

例如:

# Create 1000000 numbers between 0 and 1000, takes 21ms
x = numpy.random.randint(0, 1000, 1000000)

# Get all items that are larger than 500, takes 2.58ms
y = x > 500

# Add 10 to those items, takes 26.1ms
x[y] += 10
由于行数要多得多,我认为75000也不应该是问题:)

例如,从1到74000的所有键都包含true

为什么不研究一个子集呢?到最后只有74001


修剪74/75%的数据要比尝试编写一个比O(n)更聪明的算法容易得多。

您应该重写修订集以获得一组修订。我认为修订的内部表示应该是一个整数,并且应该根据需要创建修订范围


没有令人信服的理由使用支持python 2.3及更早版本的代码。

只是一个想法。我过去常常在二值图像处理中使用运行编码来做这种事情。也就是说,将每个集合存储为一系列数字:关闭位数、打开位数、关闭位数等


然后,您可以在一个简单的合并算法上对它们执行各种布尔运算作为装饰。

这里有一个快速替换修订集的方法,可以将其转换为一个集合。应该快得多。我没有完全测试它,但它与我所做的所有测试一起工作。毫无疑问,还有其他方法可以加快速度,但我认为这确实会有所帮助,因为它实际上利用了集合的快速实现,而不是像原始代码在函数
\uuuuu sub\uuu
\uu和
中那样在Python中执行循环。唯一的问题是迭代器没有排序。您可能需要更改一点代码来说明这一点。我相信还有其他方法可以改善这一点,但希望它能给你一个好的开始

class RevisionSet(set):
    """
    A set of revisions, held in dictionary form for easy manipulation. If we
    were to rewrite this script for Python 2.3+, we would subclass this from
    set (or UserSet).  As this class does not include branch
    information, it's assumed that one instance will be used per
    branch.
    """
    def __init__(self, parm):
        """Constructs a RevisionSet from a string in property form, or from
        a dictionary whose keys are the revisions. Raises ValueError if the
        input string is invalid."""


        revision_range_split_re = re.compile('[-:]')

        if isinstance(parm, set):
            print "1"
            self.update(parm.copy())
        elif isinstance(parm, list):
            self.update(set(parm))
        else:
            parm = parm.strip()
            if parm:
                for R in parm.split(","):
                    rev_or_revs = re.split(revision_range_split_re, R)
                    if len(rev_or_revs) == 1:
                        self.add(int(rev_or_revs[0]))
                    elif len(rev_or_revs) == 2:
                        self.update(set(range(int(rev_or_revs[0]),
                                         int(rev_or_revs[1])+1)))
                    else:
                        raise ValueError, 'Ill formatted revision range: ' + R

    def sorted(self):
        return sorted(self)

    def normalized(self):
        """Returns a normalized version of the revision set, which is an
        ordered list of couples (start,end), with the minimum number of
        intervals."""
        revnums = sorted(self)
        revnums.reverse()
        ret = []
        while revnums:
            s = e = revnums.pop()
            while revnums and revnums[-1] in (e, e+1):
                e = revnums.pop()
            ret.append((s, e))
        return ret

    def __str__(self):
        """Convert the revision set to a string, using its normalized form."""
        L = []
        for s,e in self.normalized():
            if s == e:
                L.append(str(s))
            else:
                L.append(str(s) + "-" + str(e))
        return ",".join(L)
添加:
顺便说一句,我比较了原始修订集和上面我的修订集的并集、交集和减法,上面的代码在操作两个有75000个元素的修订集时,这些操作的速度从3倍提高到7倍。我知道其他人都在说numpy是一个不错的选择,但是如果您对Python不是很有经验,正如您的评论所指出的,那么您可能不想走这条路,因为它将涉及更多的更改。我建议试试我的代码,看看它是否有效,如果有效,然后看看它是否足够快。如果不是,那么我会尝试分析,看看需要改进什么。只有这样,我才会考虑使用NUMPY(这是我经常使用的一个很好的包)。< /P>您想在布尔值列表上执行哪些操作?布尔数的numpy数组能帮到你吗?这个集合实现看起来像是O(n),而不是O(n*m)
如果rs中的r
其中的
rs
是一个dict,那么它是一个O(1)运算,而不是O(len(rs))。@Baffe Boyois-true,想想看。修复了问题文本。至少用内置的(可能是C实现的)替换旧的Python支持(rsplit等)是值得的。好的,我来看看。如果我最终使用它,我会接受你的答案。就我个人而言,我不认为这里真的需要numpy。我认为Python的内置集已经足够了,如果你想减少内存占用,你可以告诉numpy也使用8位整数。但是,我不确定是否可以使用randint函数实现这一点@GWW:不能直接使用randint,但你甚至可以告诉numpy将其转换为
bool
如下:
numpy.array(numpy.random.randint(0,210000),dtype='bool')
@Justin Peel:是的。但我猜numpy在大多数操作中会更快。它是专门为这样的大规模操作而设计的。@Vilx:怎么会这样?你只需要把事情细分。我想你可能误解了我。这些不是真实的数字,只是我当场编造的。我的意思是,相同的布尔值有很大的间隔。@Vilx:我想你可能误解了我的意思。如果你有不重要的范围,想办法过滤掉它们。此外,在你的问题中尽量坚持事实——误导性的数值会给你误导性的答案。好的,用“可能”一词更新问题。无论如何,这正是我想做的-更改这个类(只有这个类,我不想更改它在代码中的使用方式),以便优化范围。@Vlix:删除未使用的值不是“优化”吗?添加一个过滤器什么都不做有什么不对?@Vilx,如果你只是用just sorted(theRevSet)替换文件中调用sorted方法的类似3个点,那么这不是递归堆栈溢出?我开始阅读python教程