6

と が与えられた場合、 (数値的に安定した方法で)計算したいと思いlog(a)ます。log(b)log(a+b)

私はこれのために小さな関数を書きました:

def log_add(logA,logB):
    if logA == log(0):
        return logB
    if logA<logB:
        return log_add(logB,logA)
    return log( 1 + math.exp(logB-logA) ) + logA

これが最も時間のかかるコードであるプログラムを作成しました。明らかに、最適化を試みることができます (たとえば、再帰呼び出しを排除します)。

とから計算するための標準mathまたは関数を知っていますか?numpylog(a+b)log(a)log(b)

そうでない場合、この関数の単一の C++ フックを作成する簡単な方法を知っていますか? これは複雑な関数ではなく (float を使用します)、前述のとおり、実行時間の大部分を占めています。

よろしくお願いします、数値法忍者!

4

2 に答える 2

8

注: 今までの最良の答えは、単純に を使用することnumpy.logaddexp(logA,logB)です。

と正確に比較するのはなぜlog(0)ですか?これは に等しく-numpy.inf、この場合、log(1 + math.exp(-inf-logB) ) + logBWhich は自分自身を logB に還元します。この呼び出しは常に非常に遅い警告メッセージを表示します。

このワンライナーを思いつくことができました。ただし、これが実際に高速かどうかを確認するには、実際に測定する必要があります。使用する2つの代わりに1つの「複雑な」計算関数のみを使用し、再帰は発生していません。ifまだそこにありますが、fabs/に隠されています(そしておそらく最適化されています) maximum

def log_add(logA,logB):
    return numpy.logaddexp(0,-numpy.fabs(logB-logA)) + numpy.maximum(logA,logB)

編集:

次の結果で簡単な timeit() を実行しました。

  1. 元のバージョンには約 120 秒かかりました
  2. 私のバージョンは約30秒かかりました
  3. あなたのバージョンから log(0) との比較を削除したところ、20 秒になりました
  4. 私は自分のコードを編集して を保持しましたlogaddexpが、再帰的な if も処理し、18 秒になりました。

更新されたコード、インラインの更新された式で再帰呼び出しを切り替えることもできますが、これは私のタイミングテストではほとんど違いがありませんでした:

def log_add2(logA, logB):
    if logA < logB:
        return log_add2(logB, logA)
    return numpy.logaddexp(0,logB-logA)+logA

編集2:

pv がコメントで指摘したように、実際には、 which がもちろん に等しいことnumpy.logaddexp(logA, logB)を計算するだけで実行できます。(上記と同じマシンで)時間を計ったところ、さらに約10秒になりました。つまり、約 1/12 になりました。悪くはありません ;)。log(exp(logA)+exp(logB))log(A+B)

于 2011-09-20T07:05:15.070 に答える
-1
def log_add(logA, logB): 
    return math.log(math.exp(logA) + math.exp(logB))

遅すぎる?または不正確ですか?

于 2011-09-20T07:05:10.973 に答える