2016-10-25 4 views
0

scipy.misc.comb(n, a)/n**bを最大にするnの値を見つけることによって、集団のサイズをestimateにする必要があります。ここで、abは定数です。 n,aおよびbはすべて整数です。整数最適化/ numpyでの最大化

明らかに、私はちょうどrange(SOME_HUGE_NUMBER)のループを持つことができ、各nの値を計算し、カーブの変曲点に達するとループから脱出することができます。しかし、numpy/scipyでこれを行うエレガントな方法があるのか​​、純粋なPythonでこれを行う他のエレガントな方法があるのだろうか(例えばニュートンの方法と同じ整数のようなもの)

+0

「n」はどれくらいの大きさになると思いますか?リンクされた答えのような181のオーダー、または地球上の75億人のオーダーのオーダー? – jotasi

+0

私は実際のデータを実行するまで、私は絶対に知る方法がないが、n <1000、そして確かに<< 10000を期待するだろう! – TimGJ

+0

'comb 'をガンマ関数を介して(またはスターリングの公式で近似することによって)実数上の関数に変換することができます。その後、数値解法を実行して、近傍の整数が最大であるかどうかを調べることができます。 – strubbly

答えて

1

Asあなたの番号nが適度に小さい(約1500より小さい)限り、これを行うための最速の方法は、実際にすべての可能な値を試すことです。あなたはnumpyを使用することで、すぐに行うことができます。

import numpy as np 
import scipy.misc as misc 

nMax = 1000 
a = 77 
b = 100 
n = np.arange(1, nMax+1, dtype=np.float64) 
val = misc.comb(n, a)/n**b 
print("Maximized for n={:d}".format(int(n[val.argmax()]+0.5))) 
# Maximized for n=181 

これは特にエレガントけどnのその範囲のためにかなり速くありません。問題は、n>1484の場合、分子がすでに大きくて、floatに格納することができないということです。このメソッドは、オーバーフローに陥るので失敗します。しかし、これはnumpy.ndarrayの問題だけでなく、pythonの整数でも動作しません。あなたはPythonでfloatは(私のシステムでmax_10_exp = 1024を保持できる最大値より大きな2つの数のあなたの部門のフロート結果を持つようにしたいと

misc.comb(10000, 1000, exact=True)/10000**1001 

参照してください:でも彼らと、あなたは計算することができません。 sys.float_info()。)。その場合はrangeを使用することはできません。あなたが本当にそのようなことをしたいのであれば、数値的にもっと注意を払う必要があります。

+0

ありがとうございます。私は、ブルートフォースがそれを行う最も効率的な方法であると想定していると思うだろう(これは対立関係ではない)。私が知っているデータからは、nが100から500の間のどこかになることが示唆されていますが、ソフトウェアを実行するまではわかりません。しかし、私はちょうどそれを行う簡単/エレガントな方法があるかどうかを知りたがっていました。 (奇妙なことに昨夜、私はBrian KernighanがAMPLについて話していたYouTubeのビデオを見ていた。これはまさにこの種の問題を解決することができるようなものだ)。 – TimGJ

+0

@TimGJおそらくもっと洗練されたソリューションがあります。とにかく、大きな数値で数値を慎重に扱う必要があります。 – jotasi

+0

分子を計算してから除算することを避けることで、より大きな数の関数を計算することができます。代わりに 'comb 'を計算するための反復的なアプローチを使用すると、中間値のサイズを制御するために、' n'で繰り返し分割することができます。このようにして、全体的な結果が大きすぎない限り、任意に大きな値の 'n'の関数を評価することができます。 – strubbly

0

本質的には、最大限にしたい、きれいに平滑な関数nがあります。 nは不可欠である必要がありますが、代わりに関数を実数の関数と見なすことができます。この場合、最大積分値nは、最大値の真値に近い(隣)になければなりません。

ガンマ関数を使ってcombを実際の関数に変換し、数値最適化技術を使用して最大値を見つけることができました。別のアプローチは、階乗をStirlingの近似で置き換えることです。これは中程度に複雑であるが扱いやすい代数表現を与える。この表現は、微分するのが難しくなく、極値を見つけるためにゼロに設定されていません。

私はこれをしなかったと

n * (b + (n-a) * log((n-a)/n)) = a * b - a/2 

これは(あなたが提案として、例えば、ニュートン法を使用して)数値的に代数的には十分に簡単に解決することは簡単ではありませんを取得しました。

私は代数を間違えているかもしれませんが、私はa = 77、b = 100の例をWolfram Alphaに入力して、180.58を得ました。