2012-05-18 25 views
3

假设我有浮点值的大名单,我想只选择其中的一些寻找一个其他数组:追加更快的方法值

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方法。

回答

2

根据你的问题的第一句话,你要基于另一个值来选择值列表或数组。

在numpy中,您可以使用索引从数组中获取选定的值。在本例中我使用Boolean indexing。这样可以避免将值附加到现有数组,但可以将所选值的副本作为数组提供给您。 您可以使用来自numpy或您自己的函数的&|运算符,logic functions来组合多个条件。

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数组,而是使用向量化函数来操纵你的数组。

+0

好的,这听起来不错。假设我有很多选择。如果该值通过'selection1',则将其放入'ar1'中,如果将'selection2'放入'ar2',....选项类似于'10

+0

@wiso我改编了这个例子。 – bmu

+0

谢谢,但这不是我在我的评论中提出的。作为输出我需要不同的集合,一个用于'10

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 constructor

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

不言而喻,你应该看看你是否可以加快你的过滤函数,因为它对每个元素都被调用一次。

+0

谢谢,'fromiter'确实快得多 –

1

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

从python文档:

双端是栈和队列(的一般化的名字的发音是“甲板”,是短期的“双端队列” )。 Deques支持线程安全,高效的内存追加,并从双侧出现,并且在任一方向都具有大致相同的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