この短いコードをスピードアップしたいと思います
max_x=array([max(x[(id==dummy)]) for dummy in ids])
x
とid
は同じ次元ids
の多数の配列であり、より小さな次元の配列です。ベクトル演算を使用してそれを行うための高速な方法は何ですか?
この短いコードをスピードアップしたいと思います
max_x=array([max(x[(id==dummy)]) for dummy in ids])
x
とid
は同じ次元ids
の多数の配列であり、より小さな次元の配列です。ベクトル演算を使用してそれを行うための高速な方法は何ですか?
idに何らかの構造がない限り、これをさらにベクトル化するのは簡単ではありません(私が見る限り)。そうでなければ、ボトルネックがid==dummy
頻繁に発生する可能性がありますが、私が考えることができる唯一の解決策は、並べ替えの使用であり、np.max()のreduce機能がないため、まだかなりのPythonコードが必要です(編集:実際には、np.fmaxを使用したreduce関数が利用可能です)。これは、axが1000x1000でid / idが0..100の場合、約3倍高速ですが、かなり複雑であるため、多くのIDを使用するより大きな問題に対してのみ価値があります。
def max_at_ids(x, id, ids):
# create a 1D view of x and id:
r_x = x.ravel()
r_id = id.ravel()
sorter = np.argsort(r_id)
# create new sorted arrays:
r_id = r_id[sorter]; r_x = r_x[sorter]
# unfortunatly there is no reduce functionality for np.max...
ids = np.unique(ids) # create a sorted, unique copy, just in case
# w gives the places where the sorted arrays id changes:
w = np.where(r_id[:-1] != r_id[1:])[0] + 1
私はもともとスライス上で純粋なPythonループを実行するこのソリューションを提供しましたが、以下はより短い(そしてより速い)バージョンです:
# The result array:
max_x = np.empty(len(ids), dtype=r_x.dtype)
start_idx = 0; end_idx = w[0]
i_ids = 0
i_w = 0
while i_ids < len(ids) and i_w < len(w) + 1:
if ids[i_ids] == r_id[start_idx]:
max_x[i_ids] = r_x[start_idx:end_idx].max()
i_ids += 1
i_w += 1
elif ids[i_ids] > r_id[start_idx]:
i_w += 1
else:
i_ids += 1
continue # skip updating start_idx/end_idx
start_idx = end_idx
# Set it to None for the last slice (might be faster to do differently)
end_idx = w[i_w] if i_w < len(w) else None
return ids, max_x
編集:各スライスの最大値を計算するための改良版:
を使用してPythonループを削除する方法がありますnp.fmax.reduceat
。これは、スライスが小さい場合(実際には非常にエレガントな場合)、前のループよりも大幅に優れている可能性があります。
# just to 0 at the start of w
# (or calculate first slice by hand and use out=... keyword argument to avoid even
# this copy.
w = np.concatenate(([0], w))
max_x = np.fmin.reduceat(r_x, w)
return ids, max_x
これを少し速くすることができる小さなことがいくつかあるでしょう。id / idsに何らかの構造がある場合は、コードを単純化することが可能であり、おそらく別のアプローチを使用して、はるかに高速化を実現する必要があります。それ以外の場合は、多くの(一意の)IDが存在する(そしてx / id配列がそれほど小さくない)限り、このコードのスピードアップは大きくなるはずです。コードはnp.unique(ids)を強制することに注意してください。これは、おそらく適切な仮定です。
x[(id==dummy)].max()
ビルトインの代わりに使用すると、max
ある程度のスピードアップが得られるはずです。
scipy.ndimage.maximum
まさにそれを行います:
import numpy as np
from scipy import ndimage as nd
N = 100 # number of values
K = 10 # number of class
# generate random data
x = np.random.rand(N)
ID = np.random.randint(0,K,N) # random id class for each xi's
ids = np.random.randint(0,K,5) # select 5 random class
# do what you ask
max_per_id = nd.maximum(x,labels=ID,index=ids)
print dict(zip(ids,max_per_id))
すべてのIDの最大値を計算する場合は、次のようにします。ids = ID
の特定のクラスids
がに見つからない場合ID
(つまり、そのクラスによってxがラベル付けされていない場合)、そのクラスの最大リターンはです0
。