Je soupçonne que c'est une question assez inhabituelle et exploratoire, alors soyez indulgent avec moi.
Je me demande si l'on pourrait appliquer l'idée de l'échantillonnage d'importance à l'échantillonnage de Gibbs. Voici ce que je veux dire: dans l'échantillonnage de Gibbs, nous modifions la valeur d'une variable (ou d'un bloc de variables) à la fois, en échantillonnant à partir de la probabilité conditionnelle étant donné les variables restantes.
Cependant, il peut ne pas être possible ou facile d'échantillonner à partir de la probabilité conditionnelle exacte. Au lieu de cela, nous échantillonnons à partir d'une distribution de proposition et utilisons, par exemple, Metropolis-Hastings (MH).
Jusqu'ici tout va bien. Mais voici une voie divergente: que se passe-t-il si nous, au lieu d'utiliser MH, utilisons la même idée utilisée dans l'échantillonnage d'importance, à savoir que nous échantillonnons à partir de et gardons un poids d'importance de l'échantillon actuel?
Plus en détail: supposons que nous ayons des variables et une distribution factorisée sorte que . Nous conservons la probabilité de proposition utilisée pour échantillonner la valeur actuelle de chaque variable . À chaque étape, nous modifions un sous-ensemble des variables et mettons à jour (seuls les facteurs de et qui sont affectés). Nous prenons les échantillons et leur poids d'importance pour calculer les statistiques qui nous intéressent.
Cet algorithme serait-il correct? Si non, des raisons claires pourquoi? Intuitivement, cela a du sens pour moi car il semble faire la même chose que l'échantillonnage d'importance, mais avec des échantillons dépendants à la place.
J'ai mis en œuvre cela pour un modèle de marche aléatoire gaussien et j'ai observé que les poids deviennent de plus en plus petits (mais pas monotones), de sorte que les échantillons initiaux finissent par avoir trop d'importance et dominent la statistique. Je suis assez certain que l'implémentation n'est pas boguée, car à chaque étape, je compare le poids mis à jour à un calcul explicite en force brute de celui-ci. Notez que les poids ne descendent pas indéfiniment à zéro, car ils sont où et sont tous deux des produits d'un nombre fini de densités, et chaque échantillon est obtenu à partir d'une distribution normale qui ne sera que rarement nulle.
J'essaie donc de comprendre pourquoi les poids baissent comme ça, et si c'est une conséquence du fait que cette méthode n'est pas correcte.
Voici une définition plus précise de l'algorithme, appliqué à une marche aléatoire gaussienne sur les variables . Le code suit ci-dessous.
Le modèle est simplement , avec fixé à .
Le poids de l'échantillon actuel est , où sont les densités gaussiennes et sont les distributions à partir desquelles les valeurs actuelles ont été échantillonnées. Initialement, nous échantillonnons simplement les valeurs de manière directe, donc et le poids initial est .
Ensuite, à chaque étape, je choisis pour changer. une nouvelle valeur pour partir de , donc cette densité devient la nouvelle distribution de proposition utilisée pour .
Pour mettre à jour le poids, je le divise par les densités et de l'ancienne valeur selon et , et multipliez par les densités et de nouvelle valeur selon et . Cela met à jour le numérateur du poids.
Pour mettre à jour le dénominateur , je multiplie le poids par l'ancienne proposition (le supprimant ainsi du dénominateur) et je le divise par .
(Parce que partir de la normale centrée sur , est toujours égal à donc ils annulent et l'implémentation ne pas vraiment les utiliser).
Comme je l'ai mentionné précédemment, dans le code, je compare ce calcul de poids incrémentiel au calcul explicite réel juste pour être sûr.
Voici le code de référence.
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);
}