制約の影響を受ける複数の離散変数からランダムに均一にサンプルを生成する方法は?


8

壷をI色のN個のボールC [i]で満たすモンテカルロプロセスを生成したいと思います。各色C [i]には、骨壷に配置する必要のあるボールの最小数と最大数があります。

たとえば、私はつぼに100個のボールを入れようとしていて、4つの色で満たすことができます。

  • 赤-最小0、最大100#NB、実際の最大は実現できません。
  • 青-最小50、最大100
  • 黄色-最小0、最大50
  • 緑-最小25、最大75

可能な結果全体に均一に分散されることが保証されているNサンプルをどのように生成できますか?

ボールに最小値も最大値もない、または同じ暗黙の最小値と最大値があるというこの問題の解決策を見てきました。たとえば、少し異なる主題に関するこの議論を参照してください。

合計が1になる均一に分散された重みを生成しますか?

しかし、私はこの解決策を一般化することに問題を抱えています。


1
「ランダムに分散」とは、均一にランダムに分散するという意味ですか?
whuber

1
あなたの説明はかなり明確ではありません。あなたは多変量超幾何に対応する種類のランダムサンプリング、または何か他のものを求めていますか?
Glen_b-2015

@whuber-はい、均一にランダムに分散されます。上記で明確化。
GPB 2015

ギブスのようなサンプラーは、この問題のはるかに大きなバージョンでもうまく機能します。
whuber

回答:


3

ましょう色のボールの数表すC Iを。また、m iM iはそれぞれ、色C iのボールの最小数と最大数を表すものとします。n 1n Iを無作為にランダムにサンプリングしたい場合、次の制約があります。niCimiMiCi(n1,,nI

  1. miniMi
  2. i=1Ini=N

まず第一に、あなたは下限制約を削除することができます(つまり、選ぶことによって)のm i個のカラーボールのC I初めに。これにより、2つの制約が次のように変更されます。minimiCi

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

レッツ示す均一な我々が興味を持っていること分布を我々からサンプルにチェーンルールと動的なプログラミングを使用することができます。 P効率的に。まず、チェーンルールを使用して Pを次のように記述します 。P n 1n IB b 1 IP1|Bb1PP ここでPnI|Bb1I= n 1

P1|Bb1=P|Bb1P11|Bb1=P|Bb1P11|Bb111
nの周辺分布わたし。なお、PNI|BB 1P|Bb1=Σ11P1|Bb1は離散分布であり、動的計画法を使用して効率的に計算できます。また、(1)の2番目の項は再帰的に計算できることに注意してください。再帰の最初のラウンドで n Iをサンプリングし、ボールの総数をB n Iに更新し、再帰して次のラウンドで n I 1をサンプリングします。P|Bb1B1

以下は、アイデアのMatlab実装です。アルゴリズムの複雑さはで、K = 最大I i = 1 b iです。コードは、実行ごとにランダムに生成されたm iを使用します。その結果、生成されたテストケースの一部に有効なソリューションがない可能性があります。その場合、コードは警告メッセージを出力します。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

ここで、関数print_constraints

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

関数dpfuncは、動的プログラミング計算を次のように実行します。

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

そして最後に、関数Discretesample(p、1)は、離散分布からランダムサンプルを描画します。この関数の1つの実装はここにありますp


1
周辺分布が多項分布であると考える理由を説明できますか?
whuber

カテゴリ型/離散型の分布を意味していたので、見つけてくれてありがとう。私は私の答えでそれを修正しました!
ソビ

1
@sobi-コード行の意味:q_ni(ni + 1)= dpfunc(i-1、running_B strong text -ni)?書式の問題はありますか?
GPB

@GPB:どれだけ強力なテキストがそこにあるのかわからない!削除する必要があります。これを見つけてくれてありがとう。修繕!多くのループ、ifステートメント、および再帰関数呼び出しがすべてMatlabで特に遅いため、コードの実行にはしばらく時間がかかります(数秒)。したがって、C ++実装ははるかに速く実行されます。
ソビ

@ソビ-私はPythonでコーディングしています。終了したら共有します...
GPB

2

この問題の一般化を考えてみましょう。 あるの塗料の缶M = 4つの異なる色及びN 0 = 100ボール。することができます私は、最大保持することができます0 m=4m=4n(0)=100iボール。あなたは、少なくとも持っ缶でボールの構成を生成したいbはI=050025をai(0)=(100,100,50,75) iの i内のボール、各構成は等しい確率で。bi=(0,50,0,25)ii

このような構成は、缶iからボールを取り除いた後に得られる構成と1対1で対応し、n = n 0 i b i = 100 0 + 50 + 0 + 25 = 25を制限しますせいぜい残りボールiは = 0 、I - 、B iは = 100 50 biin=n(0)ibi=100(0+50+0+25)=25缶当り。したがって、これらを生成し、後で調整できるようにします( b iボールをすべての iの can iに戻すことによって)。ai=ai(0)bi=(100,50,50,50)biii

ijskkkijsi+sjn(si+sj)ij1+min(ai+ajsisj,si+sj)ij

m2{i,j}状態、制限分布に達するまでチェーンを実行し、この手順でアクセスされた状態を追跡します。通常のように、シリアル相関を回避するには、この状態シーケンスをスキップして(またはランダムに再検討して)「間引き」する必要があります。缶の数の約半分の係数で薄くすることは、平均して多くのステップの後、それぞれの缶が影響を受け、真に新しい構成を生み出すため、うまく機能する傾向があります。

O(m)O(m)


a=(4,3,2,1)n=30201s1+s2=3

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

**00s1+s2=2

20**, 11**, 02**

**10013×2=6s1+s2=1

10**, 01**

**2011 022×2=4s1+s2=0214+6+4+1=15

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

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 

χ2χ211.2p=0.6714


このRコードは、問題の状況を処理するように設定されています。変更しan他の状況で動作します。間引き後にN必要な実現の数を生成するのに十分な大きさに設定します。

このコードは、すべてを体系的に循環させることにより、少しチートします (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)

どうもありがとう...私は今夜、これと他の応答を処理しています。明日に戻ることを望んでいます。
GPB 2015

1
缶iとjにsi + sjボールを分配する可能な方法の数が1 + ai + aj−si−sjである理由を説明できますか?たとえば、ai = 0の場合、可能な方法は1つだけです(つまり、すべてのsi + sjボールを缶jに入れる)。しかし、あなたの公式によれば、1 + 0 + aj + 0-sj = 1 + aj-sjの可能な方法があり、その数が1よりも大きくなるようにaj-sjを選択できます。また、説明してください。なぜアルゴリズムの実行時間はO(m)ですか?
ソビ

1
ai+ajsi+sjai+ajsi+sjsi+sj<ai+ajsi+sj+1min(ai+ajsisj,si+sj)+1gO(m)

1
ai=1,aj=3,si+sj=2min(1+32,2)+1=3min(ai,si+sj)max(0,si+sjaj)+1i

1
O(m)O(f(m))NO(f(m)/N)gO(m)O(mNO(N)
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.