[ターン] Pythonで時系列ローリングソート関数(TS_RANK)の効率を改善するにはどうすればよいですか?

Pythonで時系列ローリングソート関数(TS_RANK)の効率を向上させる方法は?

1. TS_RANKとは何ですか?

TS_RANK(X、n)関数は、時系列Xでのこのウィンドウ内の各固定ウィンドウの最後の値のランキング値の循環計算を参照します。簡単に言えば、過去の各瞬間における時系列Xの現在値の順序を調べることです。この関数は、マイニング信号での使用頻度がまだ非常に高いため、慎重に説明されています。

たとえば、固定ウィンドウが3の時系列[1,2,3,4,5,6]がある場合、フォワードトレースのデータ長が不十分なため、最初の2つの添え字は計算されません。 [1、2、3]、3が最大であるため、注文値は3です。同様に、[2,3,4]、[3,4,5]、[4,5,6]の場合、最後の値のシーケンス値も3です。最後に[3,3,3,3]を取得します。

固定ウィンドウが同じではないことを考えると、計算結果を比較するのは難しいので、毎回得られるシーケンス値をウィンドウの長さで割って、結果を[0,1]に正規化することができます。上記の例の場合、結果は[1、1,1,1]になります。別の例[1,6,5,2,4,3]を与えると、[0.66、0.33、0.66、0.33]が得られます。

2.TS_RANKのPython実装

過去には、人々はpandas.rolling()を使用して、時系列でローリングと循環計算のこの種のシンボリック関数を実装することを好みます。価格データフレームがdfであると仮定すると、一般的な記述は次のようになります。

df.rolling(n).apply(lambda x: get_sort_value(x)/n)

パンダには、ローリングと組み合わせてソート値を取得するための独自の組み込み関数がないため、apply + lambdaを使用してから、自己記述のget_sort_valueを使用して最後の要素のソート値を取得する必要があります。要件に応じて、get_sort_valueは配列を渡し、最後の要素のソート値を返す関数です。ここで、nで除算するのは正則化です。

コアのget_sort_valueには、実装できる多くのメソッドがあります。これらのコードは、https://github.com/pandas-dev/pandas/issues/9481での議論からのものです。いくつかの小さなエラーがあり、作成者が作成しました。変更します。

def rollingRankOnSeries(array):
    s = pd.Series(array)
    return s.rank(method='min', ascending=False)[len(s)-1]

def rollingRankSciPy(array):
     return array.size + 1 - sc.stats.rankdata(array)[-1]

def rollingRankBottleneck(array):
    return array.size + 1 - bd.rankdata(array)[-1]

def rollingRankArgSort(array):
    return array.size - array.argsort().argsort()[-1]

その中で、最初の実装はパンダランク関数を使用することです。配列をシリーズに変換する効率については説明されていないため、2番目の実装はscipyランクデータ関数を使用し、3番目の実装はボトルネックライブラリ関数を使用します。最後の実装はOneです。 numpyの組み込み関数argsortです。

実験により、BottleNeckのランクデータ効率はScipyとNumpyのランクデータ効率よりもわずかに高く、平均時間は4Sであるのに対し、ScipyとNumpyは6Sを必要とすることが証明されています。

3.スピードアップ

実際、私たちはもっと速くなければなりません。これは、以前の操作ではウィンドウシーケンスを毎回個別に処理するため、毎回O(nlogn)ソートが行われるためです。しかし、実際には、前後の時系列が一致しているため、この時点で並べ替えに使用した時系列は、前の瞬間から1要素だけ離れています。

たとえば、時系列[1,2,3,4,5,6]とウィンドウ値4の場合、[1,2,3,4]を並べ替えた後は、[1,2,3]から並べ替えるだけで済みます。 、4]次回、3,4]、1を削除し、5を追加してから、シーケンス値5を取得します。そのため、実際にはより良いデータ構造を使用して目標を達成できることがわかりました。このデータ構造の要件は、時系列を保存でき、順序の追加、削除、取得の操作を効率的に実装できることです。

アイデアは良いですが、Pythonの実装の速度も考慮する必要があります。効率的なライブラリ関数はC / C ++に基づいて実装されているため、適切なライブラリ関数が見つからない場合は、自分で選択するのが遅くなります。簡単な検索の後、作者はかろうじてOKなメソッドSortedListを見つけました。SortedListは、sortedcontainersパッケージの関数であり、追加およびポップ操作中にソート特性を維持できます。

@jit
def TS_RANK(x, n):
    sl = SortedList(x[:n])
    for i in range(n,len(x)):
        sl.add(x[i])
        res.append(sl.bisect_left(x[i]) / n)
        res.pop(0)
    return res

新しいTS_RANK関数は、numbaアクセラレーションを使用して上記のように実装されます。テスト後、速度は0.11Sに増加します。これは、激しいnumpyの50倍以上の速度です。

幸い、Pythonは依然としてより洗練された使用法を提供し、前述のボトルネックライブラリで、move_dataは移動ウィンドウの最後の値のランク値を計算でき、書き込み方法は単純です。

bk.move_data(x)

テスト後の速度は0.09Sで、手書きバージョンと同等です。

ただし、この関数にも欠点があります。つまり、最初のn個の要素の操作能力が一般的であり、すべての欠落値が割り当てられます。nが大きい場合、いくつかの問題が発生します。自己記述関数の場合、ニーズに応じて最初のn個の値の割り当てルールを柔軟に変更できます。したがって、どちらを使用するかは、すべての人が慎重に検討する必要があります。

4.結論

この記事は、numpy +優れたアルゴリズムのアイデア+ numbaが他のCバージョンを大幅に近似できることを証明しています。同時に、ほとんどのPython初心者は、4〜6のプライマリソリューションに到達できない可能性があります。データ量が急激に増加すると、これもクオンツの研究効率に大きく影響します。

おすすめ

転載: blog.csdn.net/weixin_52071682/article/details/115148717
おすすめ