假设我有一个很大的浮点值列表,我想只选择其中一些查看另一个数组:
result = []
for x,s in zip(xlist, slist):
if f(s): result.append(x)
在循环开始时,我可以粗略估计有多少条目将通过f
选择
现在这很慢,我试图将list
更改为array
,但只看附加我变慢
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
方法。
答案 0 :(得分:3)
可能有一个更好的numpy解决方案,但在pure-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
。
不言而喻,您应该看看是否可以加快f()
过滤功能,因为每个元素都会调用一次。
答案 1 :(得分: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数组,而是使用向量化函数来操作数组。
答案 2 :(得分:1)
尝试deque:http://docs.python.org/library/collections.html#collections.deque
来自python docs:
Deques是堆栈和队列的概括(名称发音为“deck”,是“双端队列”的缩写)。 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