2016-03-25 18 views
4

目的関数に対して変数のセットを最適化する必要があります。関数の解析勾配があり、最適化ルーチンでそれを使用したいと思います。目的と勾配にはいくつかの一般的な計算があり、可能な限り最も効率的な方法で関数を定義したいと思います。以下の例は、この問題を示しています。Rでの最適化 - 目的関数と勾配の効率的計算

f_obj,f_gradおよびf_commonをそれぞれ目的関数、勾配関数および共通計算の関数とする。最適化はベクトルxを超えています。以下のコードは、多項式y^3 - 3*y^2 + 6*y + 1の根を求めます。yは、c(x[1], x[2])の関数です。関数f_commonf_objf_gradの両方で呼び出されます。私の実際の問題では、一般的な計算ははるかに長くなるので、f_commonへの呼び出し回数を最小にするように、f_objf_gradを定義する方法を探しています。

f_common <- function(x) x[1]^3*x[2]^3 - x[2] 

f_obj <- function(x) { 
    y <- f_common(x) 
    return ((y^3 - 3*y^2 + 6*y + 1)^2) 
} 

f_grad <- function(x) { 
    y <- f_common(x) 
    return (2 * (y^3 - 3*y^2 + 6*y + 1) * (3*y^2 - 6*y + 6)* c(3*x[1]^2*x[2]^3, 3*x[1]^3*x[2]^2 - 1)) 
} 

optim(par = c(100,100), fn = f_obj, gr = f_grad, method = "BFGS") 

UPDATE

私はパッケージnloptrを入力し、目的関数とリストとしてその勾配を、施設を提供していますことを見つけます。同様の方法で他のオプティマイザ(optimoptimx、など)を定義する方法はありますか?

ありがとうございました。

+0

あなたは何をしたいですか?コードは機能します。 f_commonの呼び出しを最小限に抑えたい場合は、関数内でyを呼び出す代わりに、ハードコードする必要があります。 –

+0

両方の関数で共通の計算をハードコーディングするのは、f_common(実行時間の点で)を呼び出すのと同じです。私は余分な計算を排除する方法を探しています。私のコードでは、最適化ルーチンが点 'x'で' f_obj'を計算し、その点でその勾配を見つけるのであれば、 'f_common'を二度呼び出す必要がありますが、' y'を一度計算するだけです。 – user3294195

+3

[memoise](https://cran.r-project.org/web/packages/memoise/index.html)のようなパッケージを使って、 'f_common'の結果をキャッシュすることができます。 – sgibb

答えて

1

ストア、以下のように、後続の関数呼び出しが利用できるようにするグローバル変数に共通の関数の値:

f_common <- function(x) x[1]^3*x[2]^3 - x[2] 

f_obj <- function(x) { 
    y <<- f_common(x) # <<- operator stores in parent scope 
    return ((y^3 - 3*y^2 + 6*y + 1)^2) 
} 

f_grad <- function(x) { 
    return (2 * (y^3 - 3*y^2 + 6*y + 1) * (3*y^2 - 6*y + 6)* c(3*x[1]^2*x[2]^3, 3*x[1]^3*x[2]^2 - 1)) 
} 

y<<-0 

optim(par = c(100,100), fn = f_obj, gr = f_grad, method = "BFGS") 

ノートのカップルは、このソリューションについて加える価値があります。

1)最初に、< < - 演算子を使用すると、厳密にはグローバル変数に割り当てられるのではなく、関数の親スコープ(つまり、呼び出されたスコープ)に割り当てられます。通常、これはしばしばグローバルスコープです。これはここでうまく動作し、より良いアプローチです。 assign()関数を使用してグローバルスコープを明示的に使用することもできますが、ここでその必要はありません。

2)グローバル変数は、同じ変数名を別の場所で使用すると予期しない副作用が発生する可能性があるため、通常はグローバル変数を使用することはお勧めしません。可能性のある副作用を避けるために、私はglobal.f_commonなどの変数名を使用することをお勧めします。これは決して他の場所では使用されず、副作用の危険はありません。この例では、元の質問の命名法と一致するように名前yを使用しました。これは、まれに望ましい動作を実現するのが難しいため、関数の外で可変スコープを指定することが正当化される場合があります。上記のように、慎重に使用し、一意の名前(global.f_commonなど)を使用するようにしてください。

+1

xを使ったグラディエント関数の呼び出しの後に、常に同じxの目的関数の呼び出しが続くことは確かですか?例えば、grad(x2)がobj(x1)を計算した直後に計算していると、問題が発生します。 'optim'関数内のすべての手順を理解しない限り危険に見えます。 –

+0

私はobjとgrad関数内でprint(y)を使用し、Optimでトレースオプションを使用していくつかのチェックを行いました。結論は、このアプローチがOPと同じようにyを2回計算するのと同じ最適化経路に従うことである。また、目的関数が既に計算されている場所以外では、勾配を計算しないことが重要であることに気づくことも重要です。 – dww

関連する問題