2017-01-18 3 views
3

私はPythonを使い始めました。これまでの経験はすべてC++言語でした。条件付きループの配列のためのPythonicコード

"良い" Pythonを学ぼうとして、私はこのCのような関数をPythonに変換しようとしていました。

var MMI(var *Data,int Length) 
{ 
    var m = Median(Data,Length); 
    int i, nh=0, nl=0; 
    for(i=1; i<Length; i++) { 
    if(Data[i] > m && Data[i] > Data[i-1]) 
     nl++; 
    else if(Data[i] < m && Data[i] < Data[i-1]) 
     nh++; 
    } 
    return 100.*(nl+nh)/(Length-1); 
} 

私はforループで簡単にそれを行うことができますかなり確信しているが、私は、配列の一連の操作ではなく、明示的なループを使用してそれを実行しようとしてきました。私が思い付いた:

import numpy as np 
import pandas as pd 
from pandas import Series 

def MMI(buffer, mmi_length): 
    window = Series(buffer[:mmi_length]) 
    m  = window.median() 

    nh = np.logical_and([window > m], [window > window.shift(1)]) 
    nl = np.logical_and([window < m], [window < window.shift(1)]) 
    nl = np.logical_and([not nh], [nl]) 

    return 100 * (nh.sum() + nl.sum())/mmi_length 

最終np.logical_and([not nh], [n])が、私は理解していない「真理値あいまいな」エラーを与えるが、より重要なのは、私はこのアプローチは、実際にPythonで有効な結果をもたらすかどうかはわからないんだけど。

誰かがこれをエレガントにコーディングしなければならないか、頭の中で私を叩いて、ループを使用するように指示しなければならないのでしょうか?

イアン

+0

Ian、あなたの示された興味がML&algo-tradingの両方に入ると、むしろ** 'numpy' strided-tricks >>> http://www.scipy-lectures.org/を楽しむことができますadvanced/advanced_numpy /#indexing-scheme-strides **シリーズでは、両方のquant&MLモデルですぐにInRAM処理で実現不可能な形状に成長します。そのため、膨大な量のデータをパンダの抽象化に再パッケージングしても、生き残ることはできません。疑わしい場合は、1M、10M、100Mのデータ行のコードをベンチマークして、パフォーマンスの緩和を見てください(これは明らかに小さくて小さな行列のサイズには寛容に思えるかもしれません...)。 – user3666197

+0

ありがとうございます - 私は見ていますが、正直言って私は大規模なデータセットに適用するのに役立つものはまだありません。 –

答えて

4

Pythonはあなたがほとんどすべてを宣言する必要がC++とは異なり、暗黙的です。 Python、numpy/pandasなどのモジュールには、大量の最適化された機能が組み込まれています。ループや値の比較をせずに作業できるようにするためです(モジュールはバックグラウンドで何をするのですか?しかし、それは必然的に速いとは思わない、それはしばしばかなりのカバーです)。

さあ、あなたのコード

import numpy as np # no need for pandas here 


def MMI(buffer, mmi_length): 
    # we will need to define two arrays here, 
    # shift(n) does not do what you want 
    window = np.asarray(buffer[1:mmi_length]) 
    window_shifted = np.asarray(buffer[:mmi_length-1]) 
    m = np.median(window) 

    # instead using all these explicit functions simply do: 
    nh = (window > m) & (window > window_shifted) 
    nl = (window < m) & (window < window_shifted) 
    nl = ~nh & nl        # ~ inverts a lot of things, 
               # one of them are boolean arrays 

    # this does the right thing 
    return 100*(nh.sum()+nl.sum())/mmi_length 

を見てみましょうそれでは、説明しましょう:

Aシリーズは、シリーズはやり過ぎのように思えるこの文脈では、基本的には配列です。このようなオブジェクトをスカラと比較すると、条件を満たす値とない値を表現するブール値の配列が得られます(2つの配列を比較する場合も同じですが、値の比較によって値を表現するブール値の配列になります) )。

最初のステップでは、配列をスカラー(ブール値の配列であることに注意してください)と別の配列を別の配列(私たちはシフト部分に移動します)に比較し、論理的に結合したい比較の結果。良いことは、2つのブール値配列を結合したいということです。これは、&操作によって暗黙的に機能します。 2番目の手順は類似しており、暗黙的に同じように動作します。

第3ステップでは、ブール値配列を反転し、別のブール値配列と組み合わせたいとします。反転は~演算子によって行われ、他の場所のロット(たとえば、サブセットの選択を反転するなど)で使用できます。 not演算子は、その引数を真理値(True/False)に変換し、その逆を返しますが、配列の真理値はどうですか?すべてのコンポーネントの論理と組み合わせ?定義されていないため、ambiguousエラーが発生します。

ブール値配列のsum()は、配列内の値が常にTrueであるため、正しい結果が得られます。

コードで唯一問題があるのは、このシリーズに​​を適用すると、NaNの前に、等しい長さのオブジェクトで終わるようにシリーズの最後の要素が切り捨てられます。numpy.NaNと比較されるものはFalseを返すので、あなたの比較はもうあなたが望むものを生み出すことはできません。 これを克服するには、前にwindowで使用していたのと同じ構文を使用して、最初に2番目の配列を定義するだけです(これでパンダが廃止されます)。


PS:numpyの配列はPythonのリストではありません(上記のすべてがnumpyの配列です!)numpyの配列は、これらすべての操作が可能になり、複雑なオブジェクトである、標準のPythonのリストで、あなたが仕事をしなければなりませんあなた自身のループのために

+0

ありがとうございます - これは信じられないほど役に立ち、本当に私の理解を進めました。私の人生の間、私は逆演算子がPythonで何であるか把握できなかったからです!最後のサンプルコードでは、 'm = window.median()'はSeriesにmedian()メソッドしかないので動作しないので、これを 'm = np.median(window)'に置き換えました –

関連する問題