numpy に反復を処理させる、つまりベクトル化することができます。
def local_maxima(xval, yval):
xval = np.asarray(xval)
yval = np.asarray(yval)
sort_idx = np.argsort(xval)
yval = yval[sort_idx]
gradient = np.diff(yval)
maxima = np.diff((gradient > 0).view(np.int8))
return np.concatenate((([0],) if gradient[0] < 0 else ()) +
(np.where(maxima == -1)[0] + 1,) +
(([len(yval)-1],) if gradient[-1] > 0 else ()))
EDITしたがって、コードは最初にすべてのポイントから nex( gradient
) までの変動を計算します。次のステップは少しトリッキーです...そうするとnp.diff((gradient > 0)
、結果のブール配列は、成長する( )から成長しない( )にTrue
変化する場所です。boolean配列と同じサイズのsigned intにすることで、成長から非成長への遷移( )とその逆( )を区別することができます。ブール配列と同じ dtype サイズの符号付き整数型を取得することで、データのコピーを回避できます。> 0
<= 0
-1
+1
.view(np.int8)
.astype(int)
. あとは、最初と最後の点を処理し、すべての点を 1 つの配列に連結するだけです。今日わかったことの 1 つは、 に送信するタプルに空のリストを含めるとnp.concatenate
、 dtype の空の配列として出力np.float
され、結果の dtype になるため、空のタプルの連結がより複雑になることです。上記のコードで。
できます:
In [2]: local_maxima(xval, yval)
Out[2]: array([ 1, 6, 10], dtype=int64)
そしてかなり速いです:
In [3]: xval = np.random.rand(10000)
In [4]: yval = np.random.rand(10000)
In [5]: local_maxima(xval, yval)
Out[5]: array([ 0, 2, 4, ..., 9991, 9995, 9998], dtype=int64)
In [6]: %timeit local_maxima(xval, yval)
1000 loops, best of 3: 1.16 ms per loop
また、ほとんどの場合、データをリストから配列に変換して並べ替えています。データが既にソートされ、配列に保持されている場合、おそらく上記のパフォーマンスを 5 倍向上させることができます。