Wie werden Stichproben gleichmäßig zufällig aus mehreren diskreten Variablen generiert, die Einschränkungen unterliegen?

8

Ich möchte einen Monte-Carlo-Prozess generieren, um eine Urne mit N Kugeln der Farbe I, C [i], zu füllen. Jede Farbe C [i] hat eine minimale und maximale Anzahl von Kugeln, die in die Urne gelegt werden sollten.

Zum Beispiel versuche ich, 100 Kugeln in die Urne zu legen und kann sie mit vier Farben füllen:

  • Rot - Minimum 0, Maximum 100 # NB, das tatsächliche Maximum kann nicht realisiert werden.
  • Blau - Minimum 50, Maximum 100
  • Gelb - Minimum 0, Maximum 50
  • Grün - Minimum 25, Maximum 75

Wie kann ich N Stichproben generieren, die eine gleichmäßige Verteilung auf mögliche Ergebnisse gewährleisten?

Ich habe Lösungen für dieses Problem gesehen, bei denen die Kugeln kein Minimum oder Maximum haben oder alternativ die gleichen impliziten Minima und Maxima haben. Siehe zum Beispiel diese Diskussion zu einem etwas anderen Thema:

Gleichmäßig verteilte Gewichte erzeugen, die sich zu einer Einheit summieren?

Aber ich habe Probleme, diese Lösung zu verallgemeinern.

GPB
quelle
1
Mit "zufällig verteilt" meinen Sie gleichmäßig zufällig verteilt?
whuber
1
Ihre Beschreibung ist nicht ganz klar. Suchen Sie nach einer Zufallsstichprobe, die einer multivariaten Hypergeometrie entspricht, oder nach etwas anderem?
Glen_b -State Monica
@whuber - ja, gleichmäßig zufällig verteilt. Oben geklärt.
GPB
Ein Gibbs-ähnlicher Sampler erledigt die Aufgabe auch bei viel größeren Versionen dieses Problems.
whuber

Antworten:

3

Lassen die Anzahl der Kugeln der Farbe bezeichnen . Außerdem bezeichnen und die minimale bzw. maximale Anzahl von Kugeln der Farbe . Wir wollen gleichmäßig zufällig folgende Einschränkungen gelten:C i m i M i C i ( n 1 , , n I )niCimiMiCi(n1,,nI)

  1. miniMi
  2. i=1Ini=N

Zunächst können Sie die Einschränkungen der unteren Grenze (dh ) entfernen, indem Sie zunächst Kugeln der Farbe . Dadurch werden die beiden Einschränkungen wie folgt geändert:m i C iminimiCi

  1. 0nibi=Mimi
  2. i=1Ini=B=Ni=1Imi

Lassen bezeichnen die einheitliche Verteilung , dass wir interessiert sind , können wir Kettenregel und dynamische Programmierung Probe verwenden. effizient. Zuerst verwenden wir die Kettenregel , um wie folgt zu schreiben : wobei ist die Randverteilung von . Man beachte, dassP P P ( n 1 , , n IB , b 1 : I )P(n1,,nIB,b1:I)PP P(nI|B,b1:I)= n 1 ,, n I - 1 P(n1,,nI|B,b1:I)nIP(nI|B,b1:I)nIB-

P(n1,,nIB,b1:I)=P(nIB,b1:I)P(n1,,nI1nI,B,b1:I)=P(nIB,b1:I)P(n1,,nI1BnI,b1:I1)(1)
P(nI|B,b1:I)=n1,,nI1P(n1,,nI|B,b1:I)nIP(nI|B,b1:I)ist eine diskrete Verteilung und kann mithilfe dynamischer Programmierung effizient berechnet werden. Beachten Sie auch, dass der zweite Term in (1) rekursiv berechnet werden kann. Wir probieren in der ersten Runde der Rekursion, aktualisieren die Gesamtzahl der Bälle auf und kehren in der nächsten Runde zu Probe zurück.nIn I - 1BnInI1

Das Folgende ist eine Matlab-Implementierung der Idee. Die Komplexität des Algorithmus ist wobei . Der Code verwendet zufällig generierte s in jedem Lauf. Infolgedessen haben einige der generierten Testfälle möglicherweise keine gültige Lösung. In diesem Fall druckt der Code eine Warnmeldung aus.O(I×B×K)K=maxi=1Ibimi

global dpm b

I = 5; % number of colors
N = 300; % total number of balls

m = randi(50, 1, I)-1; % minimum number of balls from each from each color
M = 99*ones(1, I); % maximum number of balls from each color

% print original constraints
print_constraints(I, N, m, M, 'original constraints');

% remove the lower bound constraints
b = M - m;
B = N - sum(m);
m = zeros(size(m));

% print transformed constraints
print_constraints(I, B, zeros(1, I), b, 'transformed constraints');

% initialize the dynamic programming matrix (dpm)
% if dpm(i, n) <> -1, it denotes the value of the following marginal probability
% \sum_{k=1}^{i-1} P(n_1, ..., n_i |
dpm = -ones(I, B);

% sample the number of balls of each color, one at a time, using chain rule
running_B = B;  % we change the value of "running_B" on the fly, as we sample balls of different colors
for i = I : -1 : 1
    % compute marginal distribution P(n_i)

    % instead of P(n_i) we compute q(n_i) which is un-normalized.
    q_ni = zeros(1, b(i) + 1); % possibilities for ni are 0, 1, ..., b(i)
    for ni = 0 : b(i)
        q_ni(ni+1) = dpfunc(i-1, running_B-ni);
    end
    if(sum(q_ni) == 0)
        fprintf('Impossible!!! constraints can not be satisfied!\n');
        return;
    end
    P_ni = q_ni / sum(q_ni);
    ni = discretesample(P_ni, 1) - 1;
    fprintf('n_%d=%d\n', i, ni);
    running_B = running_B - ni;
end

wo die Funktion print_constraints ist

function [] = print_constraints(I, N, m, M, note)
    fprintf('\n------ %s ------ \n', note);
    fprintf('%d <= n_%d <= %d\n', [m; [1:I]; M]);
    fprintf('========================\n');
    fprintf('sum_{i=1}^%d n_i = %d\n', I, N);
end

und die Funktion dpfunc führt die dynamische Programmierberechnung wie folgt durch:

function res = dpfunc(i, n)
    global dpm b

    % check boundary cases
    if(n == 0)
        res = 1;
        return;
    end
    if(i == 0) % gets here only if n <> 0
        res = 0;
        return;
    end

    if(n < 0)
        res = 0;
        return;
    end

    if(dpm(i, n) == -1) % if <> -1, it has been compute before, so, just use it!
        % compute the value of dpm(i, n) = \sum_{n_1, ..., n_i} valid(n, n_1, ..., n_i)
        % where "valid" return 1 if \sum_{j=1}^i n_i = n and 0 <= n_i <= b_i, for all i
        % and 0 otherwise.
        dpm(i, n) = 0;
        for ni = 0 : b(i)
            dpm(i, n) = dpm(i, n) + dpfunc(i-1, n-ni);
        end
    end
    res = dpm(i, n);
end

und schließlich zieht die Funktion diskrete Stichprobe (p, 1) eine Zufallsstichprobe aus der diskreten Verteilung . Eine Implementierung dieser Funktion finden Sie hier .p

Sobi
quelle
1
Können Sie erklären, warum Sie die marginale Verteilung für multinomial halten?
whuber
Ich meinte kategoriale / diskrete Verteilung, danke, dass Sie sie entdeckt haben. Ich habe es gerade in meiner Antwort korrigiert!
Sobi
1
@sobi - Was ist mit der Codezeile gemeint: q_ni (ni + 1) = dpfunc (i-1, running_B starker Text -ni)? Gibt es ein Formatierungsproblem?
GPB
@ GPB: Ich bin mir nicht sicher, wie stark der Text dort angekommen ist ! Es muss entfernt werden. Danke, dass du das entdeckt hast. Fest! Die Ausführung des Codes dauert eine Weile (einige Sekunden), da er viele Schleifen, if-Anweisungen und rekursive Funktionsaufrufe enthält, die in Matlab besonders langsam sind. Daher würde eine C ++ - Implementierung viel schneller ausgeführt!
Sobi
@Sobi - Ich codiere in Python, werde mit Ihnen teilen, wenn Sie fertig sind ....
GPB
2

Betrachten wir eine Verallgemeinerung dieses Problems. Es gibt Farbdosen mit verschiedenen Farben und Kugeln. Kann bis zu Bälle halten? Sie möchten Konfigurationen von Kugeln in den Dosen mit mindestens Kugeln in der Dose für jedes erzeugen , wobei jede Konfiguration mit gleicher Wahrscheinlichkeit erfolgt.m=4m=4n(0)=100iai(0)=(100,100,50,75)bi=(0,50,0,25)ii

Solche Konfigurationen stimmen eins zu eins mit den Konfigurationen die nach dem Entfernen von Kugeln aus der Dose , wodurch verbleibende Bälle zu höchstens pro Dose. Ich werde diese daher einfach generieren und Sie sie anschließend anpassen lassen (indem Sie Bälle für jedes wieder in can legen ). i n = n ( 0 ) - i b i = 100 - ( 0 + 50 + 0 + 25 ) = 25 a i = a ( 0 ) i - b i = ( 100 , 50 , 50 , 50 ) b i i ibiin=n(0)ibi=100(0+50+0+25)=25ai=ai(0)bi=(100,50,50,50)biii

Um diese Konfigurationen hochzuzählen, korrigieren Sie alle bis auf zwei Indizes, z. B. und . Angenommen, es gibt bereits Bälle in Dose für jedes sich von und . Das lässt Bälle. Abhängig davon, wo sich die anderen Kugeln befinden, sind diese gleichmäßig in den Dosen und . Die möglichen Konfigurationen sind in der Anzahl (siehe die Kommentare) und reichen von der Platzierung so vieler Bälle in Doseijskkkijsi+sjn(si+sj)ij1+min(ai+ajsisj,si+sj)iwie möglich den ganzen Weg so viele Bälle in Dose durch Platzieren wie möglich.j

Wenn Sie möchten, können Sie die Gesamtzahl der Konfigurationen zählen, indem Sie dieses Argument rekursiv auf die verbleibenden Dosen anwenden . Um Proben zu erhalten, müssen wir diese Anzahl jedoch nicht einmal kennen. Alles, was wir tun müssen, ist, wiederholt alle möglichen ungeordneten Paare von Dosen zu besuchen und die Verteilung der Kugeln innerhalb dieser beiden Dosen zufällig (und gleichmäßig) zu ändern. Dies ist eine Markov-Kette mit einer begrenzten Wahrscheinlichkeitsverteilung, die über alle möglichen Zustände gleichmäßig ist (wie mit Standardmethoden leicht gezeigt werden kann). Daher reicht es aus, in einem zu beginnenm2{i,j}Führen Sie die Kette so lange aus, bis die Grenzverteilung erreicht ist, und verfolgen Sie dann die von diesem Verfahren besuchten Zustände. Wie üblich sollte diese Folge von Zuständen "verdünnt" werden, um eine serielle Korrelation zu vermeiden, indem sie übersprungen (oder zufällig wiederholt werden). Das Ausdünnen um den Faktor etwa der Hälfte der Anzahl der Dosen funktioniert in der Regel gut, da nach durchschnittlich vielen Schritten jede Dose betroffen ist und eine wirklich neue Konfiguration entsteht.

Dieser Algorithmus kostet Aufwand, um durchschnittlich jede zufällige Konfiguration zu generieren. Obwohl andere -Algorithmen existieren, hat dieser den Vorteil, dass die kombinatorischen Berechnungen nicht vorher durchgeführt werden müssen.O(m)O(m)


Lassen Sie uns als Beispiel eine kleinere Situation manuell herausarbeiten. Sei zum Beispiel und . Es gibt 15 gültige Konfigurationen, die als Zeichenfolgen von Belegungsnummern geschrieben werden können. Zum Beispiel werden zwei Kugeln in die zweite Dose und eine Kugel in der vierten Dose. Betrachten wir das Argument und betrachten wir die Gesamtbelegung der ersten beiden Dosen. Wenn das Bälle ist, bleiben für die letzten beiden Dosen keine Bälle übrig. Das gibt die Staatena=(4,3,2,1)n=30201s1+s2=3

30**, 21**, 12**, 03**

wobei **alle möglichen Belegungsnummern für die letzten beiden Dosen darstellt: nämlich 00. Wenn , sind die Zuständes1+s2=2

20**, 11**, 02**

wo **kann jetzt entweder 10oder sein 01. Das ergibt weitere Zustände. Wenn , sind die Zustände3×2=6s1+s2=1

10**, 01**

wo jetzt **sein kann 20, 11aber nicht 02 (wegen der Grenze von einer Kugel in der letzten Dose). Das ergibt weitere Zustände. Wenn schließlich , befinden sich alle Kugeln in den letzten beiden Dosen, die bis zu ihren Grenzen von und voll sein müssen . Die gleich wahrscheinlichen Zustände sind daher2×2=4s1+s2=0214+6+4+1=15

3000, 2100, 1200, 0300; 2010, 2001, 1110, 1101, 0210, 0201; 1020, 1011, 0120, 0111; 0021.

Unter Verwendung des folgenden Codes wurde eine Folge von solcher Konfigurationen erzeugt und auf jede dritte verdünnt, wodurch Konfigurationen der Zustände erzeugt wurden. Ihre Frequenzen waren die folgenden:10,009333715

State: 3000 2100 1200 0300 2010 1110 0210 1020 0120 2001 1101 0201 1011 0111 0021 
Count:  202  227  232  218  216  208  238  227  237  209  239  222  243  211  208 

Ein Test der Gleichmäßigkeit ergibt einen Wert von , ( Freiheitsgrade): Das ist eine schöne Übereinstimmung mit der Hypothese, dass dieses Verfahren gleich wahrscheinliche Zustände erzeugt.χ2χ211.2p=0.6714


Dieser RCode ist so eingerichtet, dass er die jeweilige Situation behandelt. Ändern Sie sich aund narbeiten Sie mit anderen Situationen. Stellen NSie den Wert so ein, dass die Anzahl der nach dem Ausdünnen erforderlichen Realisierungen generiert wird .

Dieser Code betrügt ein wenig, indem er systematisch alle Paare durchläuft . Wenn Sie über das Ausführen der Markow - Kette zu streng sein wollen, erzeugen , und zufällig, in dem kommentierten Code als gegeben. (i,j)ijij

#
# Gibbs-like sampler.
#
# `a` is an array of maximum numbers of balls of each type.  Its values should
#     all be integers greater than zero.
# `n` is the total number of balls.
#------------------------------------------------------------------------------#
g <- function(j, state, a) {
  #
  # `state` contains the occupancy numbers.
  # `a`     is the array of maximum occupancy numbers.
  # `j`     is a pair of indexes into `a` to "rotate".
  #
  k <- sum(state[j]) # Total occupancy.
  x <- floor(runif(1, max(0, k - a[j[2]]), min(k, a[j[1]]) + 1))
  state[j] <- c(x, k-x)
  return(state)
}
#
# Set up the problem.
#
a <- c(100, 50, 50, 50)
n <- 25

# a <- 4:1
# n <- 3
#
# Initialize the state.
#
state <- round(n * a / sum(a))
i <- 1
while (sum(state) < n) {
  if (state[i] < a[i]) state[i] <- state[i] + 1
  i <- i+1
}
while (sum(state) > n) {
  i <- i-1
  if (state[i] > 0) state[i] <- state[i] - 1
}
#
# Conduct a sequence of random changes.
#
set.seed(17)
N <- 1e5
sim <- matrix(state, ncol=1)
u <- ceiling(N / choose(length(state), 2) / 2)
i <- rep(rep(1:length(state), each=length(state)-1), u)
j <- rep(rep(length(state):1, length(state)-1), u)
ij <- rbind(i, j)
#
# Alternatively, generate `ij` randomly:
#   i <- sample.int(length(state), N, replace=TRUE)
#   j <- sample.int(length(state)-1, N, replace=TRUE)
#   ij <- rbind(i, ((i+j-1) %% length(state))+1)
#
sim <- cbind(sim, apply(ij, 2, function(j) {state <<- g(j, state, a); state}))
rownames(sim) <- paste("Can", 1:nrow(sim))
#
# Thin them for use.  Each column is a state.
#
thin <- function(x, stride=1, start=1) {
  i <- round(seq(start, ncol(x), by=stride))
  x[, i]
}
#
# Make a scatterplot of the results, to illustrate.
#
par(mfrow=c(1,1))
s <- thin(sim, stride=max(1, N/1e4))
pairs(t(s) + runif(length(s), -1/2, 1/2), cex=1/2, col="#00000005", pch=16)
whuber
quelle
Vielen Dank ... Ich verarbeite diese und die andere Antwort heute Abend und hoffe, morgen wieder zurück zu kommen.
GPB
1
Können Sie bitte erklären, warum die Anzahl der Möglichkeiten, si + sj-Bälle in den Dosen i und j zu verteilen, 1 + ai + aj - si - sj ist? Wenn zum Beispiel ai = 0 ist, gibt es nur einen möglichen Weg (nämlich alle si + sj-Bälle in die Dose j zu legen). Aber gemäß Ihrer Formel sollte es 1 + 0 + aj + 0-sj = 1 + aj-sj mögliche Wege geben, und aj-sj kann so gewählt werden, dass die Zahl willkürlich größer als 1 ist. Können Sie das bitte auch erklären? Warum ist die Laufzeit des Algorithmus O (m)?
Sobi
1
@Sobi Es sind freie Felder und Bälle zum Einfügen vorhanden . Die Konfigurationen entsprechen dem Anordnen von Schlitzen in einer Reihe mit einem Teiler zwischen ihnen (um die beiden Dosen zu trennen) und dem Füllen einer zusammenhängenden Folge von dieser Schlitze, die den Teiler enthalten oder diesem benachbart sind. Das heißt, wenn , ist der Wert nur , also ist die richtige Menge . Ich habe diese Änderung in diese Antwort aufgenommen. Vielen Dank für den Hinweis! Der in der Funktion eingekapselte Algorithmus ist offensichtlich . ai+ajsi+sjai+ajsi+sjsi+sj<ai+ajsi+sj+1min(ai+ajsisj,si+sj)+1gO(m)
whuber
1
Betrachten Sie . Die neue Formel ergibt aber es gibt nur zwei Möglichkeiten. Ich denke, die folgende Formel sollte funktionieren: . Die erste / zweite Menge ist die maximale / minimale Anzahl von Bällen, die kann. ai=1,aj=3,si+sj=2min(1+32,2)+1=3min(ai,si+sj)max(0,si+sjaj)+1i
Sobi
1
Ja, ich glaube, die Mischzeit ist aber es spielt keine Rolle, ob es . Bei genügend Iterationen (die wir haben, wenn wir asymptotische Ergebnisse betrachten) ist der Einheitsbeitrag des Mischens , was vernachlässigbar ist. Ist jedoch da bei jeder Ausführung ein neuer Status erstellt wird und die einfache Ausgabe eines Status eine -Operation ist. Ausdünnen schadet dem Ergebnis auch nicht. Eine Möglichkeit zum Dünnen besteht darin, eine große Anzahl von Realisierungen zu erstellen und neu zu ordnen (möglicherweise durch zyklisches Durchlaufen mit einem großen Schritt), was nur Aufwand erfordert. O ( f ( m ) ) N O ( f ( m ) / N ) O ( m ) O ( m ) N O ( N )O(m)O(f(m))NO(f(m)/N)gO(m)O(m)NO(N)
whuber