これはかなり珍しい、探索的な質問だと思いますので、ご容赦ください。
ギブスサンプリングに重要性サンプリングのアイデアを適用できるかどうか疑問に思っています。意味は次のとおりです。ギブスサンプリングでは、一度に1つの変数(または変数のブロック)の値を変更し、残りの変数が与えられた条件付き確率からサンプリングします。
ただし、正確な条件付き確率からサンプリングすることは不可能または簡単ではない場合があります。そのため、代わりに提案分布からサンプリングし、たとえばMetropolis-Hastings(MH)を使用します。
ここまでは順調ですね。しかし、これは分岐したパスです:MHを使用する代わりに、重要度サンプリングで使用されたのと同じアイデアを使用するとどうなりますか?つまり、からサンプリングし、現在のサンプルの重要度重みを保持しますか?
より詳しく:となるように、変数と因数分解分布があるとます。各変数現在の値をサンプリングするために使用される提案確率を保持します。各ステップで、変数のサブセットを変更し、を更新します影響を受けると係数のみ)。サンプルとその重要度の重みを使用して、興味のある統計を計算します。
このアルゴリズムは正しいでしょうか?そうでない場合、なぜそうではないかという明確な理由はありますか?重要なサンプリングと同じことをしているように見えますが、代わりに依存するサンプルを使用しているので、直感的にそれは私には理にかなっています。
私はこれをガウスランダムウォークモデルに実装し、重みがどんどん小さくなる(ただし、単調ではない)ので、最初のサンプルの重要性が高くなりすぎて統計が支配的になることに気付きました。各ステップで、更新された重みを明示的なブルートフォース計算と比較するため、実装にバグがないと確信しています。重みは、であり、と両方が有限数の密度の積であるため、無制限にゼロに下がらないことに注意してください。各サンプルは、まれにしかゼロにならない正規分布から取得されます。
だから私はなぜ重みがそのように下がるのか、そしてこれがこの方法が実際に正しくない結果であるのかどうかを理解しようとしています。
次に、より正確なアルゴリズムの定義を示します。これは、変数ガウスランダムウォークに適用されます。コードは以下のとおりです。
モデルは単にで、は固定されてい。
現在のサンプルの重みは。ここで、はガウス密度、は現在の値のサンプリング元の分布です。最初は、値を順方向にサンプリングするだけなので、で、初期の重みはです。
次に、各ステップで、変更するを選択します。私は新しい値サンプルするためのから、この密度はのための新たな使用提案分布となるように。
重みを更新するには、とに従って、古い値の密度とで除算します及び多重密度のによりと新しい値のに従っておよび。これにより、重みの分子が更新されます。
分母を更新するには、重みを古い提案乗算し(したがって、分母から削除)、それを除算します。
(私はを中心とする法線からをサンプリングするため、は常に等しいので、キャンセルして実装が行います実際には使用しません)。
前に述べたように、コードでは、念のため、この増分重み計算を実際の明示的な計算と比較しています。
参照用のコードを以下に示します。
println("Original sample: " + currentSample);
int flippedVariablesIndex = 1 + getRandom().nextInt(getVariables().size() - 1);
println("Flipping: " + flippedVariablesIndex);
double oldValue = getValue(currentSample, flippedVariablesIndex);
NormalDistribution normalFromBack = getNormalDistribution(getValue(currentSample, flippedVariablesIndex - 1));
double previousP = normalFromBack.density(oldValue);
double newValue = normalFromBack.sample();
currentSample.set(getVariable(flippedVariablesIndex), newValue);
double previousQ = fromVariableToQ.get(getVariable(flippedVariablesIndex));
fromVariableToQ.put(getVariable(flippedVariablesIndex), normalFromBack.density(newValue));
if (flippedVariablesIndex < length - 1) {
NormalDistribution normal = getNormalDistribution(getValue(currentSample, flippedVariablesIndex + 1));
double oldForwardPotential = normal.density(oldValue);
double newForwardPotential = normal.density(newValue);
// println("Removing old forward potential " + oldForwardPotential);
currentSample.removePotential(new DoublePotential(oldForwardPotential));
// println("Multiplying new forward potential " + newForwardPotential);
currentSample.updatePotential(new DoublePotential(newForwardPotential));
}
// println("Removing old backward potential " + previousP);
currentSample.removePotential(new DoublePotential(previousP));
// println("Multiplying (removing from divisor) old q " + previousQ);
currentSample.updatePotential(new DoublePotential(previousQ));
println("Final sample: " + currentSample);
println();
// check by comparison to brute force calculation of weight:
double productOfPs = 1.0;
for (int i = 1; i != length; i++) {
productOfPs *= getNormalDistribution(getValue(currentSample, i - 1)).density(getValue(currentSample, i));
}
double productOfQs = Util.fold(fromVariableToQ.values(), (p1, p2) -> p1*p2, 1.0);
double weight = productOfPs/productOfQs;
if (Math.abs(weight - currentSample.getPotential().doubleValue()) > 0.0000001) {
println("Error in weight calculation");
System.exit(0);
}