4

float 値の大きなリストがあり、他の配列を見てそれらの一部のみを選択したいとします。

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()言うまでもなく、フィルタリング関数はすべての要素に対して 1 回呼び出されるため、高速化できるかどうかを確認する必要があります。

于 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

deque を試してください: http://docs.python.org/library/collections.html#collections.deque

Python ドキュメントから:

Deque は、スタックとキューを一般化したものです (名前は「デッキ」と発音され、「ダブルエンド キュー」の略です)。Deques は、deque の両側からのスレッドセーフでメモリ効率の高い追加とポップをサポートし、どちらの方向でもほぼ同じ 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 に答える