4

假设我有一个很大的浮点值列表,我只想选择其中一些查看另一个数组:

result = []
for x,s in zip(xlist, slist):
    if f(s): result.append(x)

在循环开始时,我可以粗略估计有多少条目将通过f选择

现在这很慢,我试图改变listarray但只看追加我变慢了

def f(v):
    for ii in a: v.append(ii)
a = range(int(1E7))
v = []
t = time(); f(v); print time()-t # -> 1.3
v = array.array('i')
t = time(); f(v); print time()-t # -> 3.4

我需要更快,因为这个循环在我的程序中真的很慢。可以numpy.array帮助我吗?没有append方法。

4

3 回答 3

3

对此可能有更好的 numpy 解决方案,但在纯 python 中,您可以尝试迭代器:

from itertools import izip

xlist = [1,2,3,4,5,6,7,8]
slist = [0,1,0,1,0,0,0,1]

def f(n):
    return n

results = (x for x,s in izip(xlist, slist) if f(s))

# results is an iterator--you don't have values yet
# and no extra memory is consumed
# you can retrieve results one by one with iteration
# or you can exhaust all values and store in a list

assert list(results)==[2,4,8]

# you can use an array too
# import array
# a = array.array('i', results)

您还可以将此方法与 numpy 数组结合使用,看看它是否更快。请参阅fromiter构造函数

但是,如果您可以重组代码以使用迭代器,则可以避免生成完整列表,从而完全避免使用append

不言而喻,您应该看看是否可以加快您的f()过滤功能,因为它会为每个元素调用一次。

于 2012-05-18T15:24:37.563 回答
2

根据您问题中的第一句话,您希望根据另一个列表或数组中的值来选择值。

在 numpy 中,您可以使用索引从数组中获取选定的值。我在示例中使用布尔索引。这避免了将值附加到现有数组的需要,但会为您提供所选值的副本作为数组。&您可以使用or|运算符、numpy中的逻辑函数或您自己的函数来组合多个条件。

In [1]: import numpy as np

In [2]: size = int(1E7)

In [3]: ar = np.arange(size)

In [4]: ar2 = np.random.randint(100, size=size)

In [5]: %timeit ar[(ar2 > 50) & (ar2 < 70) | (ar2 == 42)]
10 loops, best of 3: 249 ms per loop

如果您需要根据不同的条件(或评论中给出的范围)在单独的数组中进行每个选择,您可以执行以下操作:

conditions = [(10, 20), (20, 50)] # min, max as tuples in a list
results = {}
for condition in conditions:
    selection = ar[(ar2 > condition[0]) & (ar2 < condition[1])]
    # do something with the selection ?
    results[condition] = selection
print results

会给你类似的东西

{(20, 50): array([      2,       6,       7, ..., 9999993, 9999997, 9999998]),
 (10, 20): array([      1,       3,      66, ..., 9999961, 9999980, 9999999])}

一般来说,您应该避免循环遍历一个 numpy 数组,而是使用矢量化函数来操作您的数组。

于 2012-05-18T21:20:01.810 回答
1

尝试双端队列:http ://docs.python.org/library/collections.html#collections.deque

来自 python 文档:

双端队列是堆栈和队列的概括(名称发音为“deck”,是“双端队列”的缩写)。双端队列支持从双端队列的任一侧进行线程安全、内存高效的追加和弹出操作,在任一方向上的 O(1) 性能大致相同。

尽管列表对象支持类似的操作,但它们针对快速固定长度操作进行了优化,并且会为 pop(0) 和 insert(0, v) 操作带来 O(n) 内存移动成本,这些操作会改变底层数据表示的大小和位置.

在我的系统上(由于内存有限,我使用 1e6 的范围):

def f(v):
    for ii in a: v.append(ii)
a = range(int(1E6))
v = []
t = time(); f(v); print time()-t # -> .12
v = array.array('i')
t = time(); f(v); print time()-t # -> .25
v = collections.deque()
t = time(); f(v); print time()-t # -> .11
于 2012-05-18T15:33:07.543 回答