Kesilmiş bir multinom dağılımını nasıl örnekleyebilirim?


9

Kesilmiş bir multinom dağılım örneklemek için bir algoritma gerekir. Yani,

x1Zp1x1pkxkx1!xk!

nerede Z normalleşme sabiti, x vardır k pozitif bileşenler ve xi=n. Ben sadecex aralıkta axb.

Bu kesilmiş multinom dağılımını nasıl örnekleyebilirim?

Not: Kesilmemiş bir multinom dağılımını örneklemek için bir algoritma için Wikipedia'ya bakın . Bu algoritmayı kesilmiş bir dağılıma uyarlamanın bir yolu var mı?

Düzgün sürüm: Sorunun daha basit bir sürümü tümpi eşit, pi=1/k. En azından bu durumda kesik dağılımı örneklemek için bir algoritma tasarlayabiliyorsanız, lütfen gönderin. Genel cevap olmasa da, şu anda diğer pratik sorunları çözmeme yardımcı olacaktı.

Yanıtlar:


9

Seni doğru anlarsam, örneklemek istersin x1,,xk olasılıklı çok terimli dağılım değerleri p1,,pk öyle ki ixi=n, ancak dağıtımın kesilmesini istersiniz aixibi hepsi için xi.

Üç çözüm görüyorum (kesilmemiş durumda olduğu kadar zarif değil):

  1. Accept-reddeder. Kesilmemiş multinomial numunesi, kesilme sınırlarına uyuyorsa numuneyi kabul edin, aksi takdirde işlemi reddedin ve tekrarlayın. Hızlıdır, ancak çok verimsiz olabilir.
rtrmnomReject <- function(R, n, p, a, b) {
  x <- t(rmultinom(R, n, p))
  x[apply(a <= x & x <= b, 1, all) & rowSums(x) == n, ]
}
  1. Doğrudan simülasyon. Veri oluşturma sürecine benzeyen bir şekilde örnek verin, örneğin tek bir mermeri rastgele bir urndan örnekleyin ve siz örnekleyene kadar bu işlemi tekrarlayın.n Toplamda mermerler, ancak belirli bir urndan toplam mermeri yerleştirdiğinizde (xi zaten eşit bi) daha sonra böyle bir urndan çizmeyi bırakın. Bunu aşağıdaki komut dosyasında uyguladım.
# single draw from truncated multinomial with a,b truncation points
rtrmnomDirect <- function(n, p, a, b) {
  k <- length(p)

  repeat {
    pp <- p         # reset pp
    x <- numeric(k) # reset x
    repeat {
      if (sum(x<b) == 1) { # if only a single category is left
        x[x<b] <- x[x<b] + n-sum(x) # fill this category with reminder
        break
      }
      i <- sample.int(k, 1, prob = pp) # sample x[i]
      x[i] <- x[i] + 1  
      if (x[i] == b[i]) pp[i] <- 0 # if x[i] is filled do
      # not sample from it
      if (sum(x) == n) break    # if we picked n, stop
    }
    if (all(x >= a)) break # if all x>=a sample is valid
    # otherwise reject
  }

  return(x)
}
  1. Metropolis algoritması. Son olarak, üçüncü ve en etkili yaklaşım Metropolis algoritmasını kullanmak olacaktır . Algoritma, ilk örneği çizmek için doğrudan simülasyon kullanılarak başlatılır (ancak farklı şekilde başlatılabilir)X1. Aşağıdaki adımları yinelemeli olarak: teklif değeriy=q(Xi1) olarak kabul edildi Xi olasılıkla f(y)/f(Xi1), aksi takdirde Xi1 değer olduğu yerde alınır, burada f(x)ipixi/xi!. Bir teklif olarak işlevi kullandımq bu alır Xi1değerini alır ve rasgele olarak 0'dan stepvaka sayısına döner ve başka bir kategoriye taşır.
# draw R values
# 'step' parameter defines magnitude of jumps
# for Meteropolis algorithm
# 'init' is a vector of values to start with
rtrmnomMetrop <- function(R, n, p, a, b,
                          step = 1,
                          init = rtrmnomDirect(n, p, a, b)) {

  k <- length(p)
  if (length(a)==1) a <- rep(a, k)
  if (length(b)==1) b <- rep(b, k)

  # approximate target log-density
  lp <- log(p)
  lf <- function(x) {
    if(any(x < a) || any(x > b) || sum(x) != n)
      return(-Inf)
    sum(lp*x - lfactorial(x))
  }

  step <- max(2, step+1)

  # proposal function
  q <- function(x) {
    idx <- sample.int(k, 2)
    u <- sample.int(step, 1)-1
    x[idx] <- x[idx] + c(-u, u)
    x
  }

  tmp <- init
  x <- matrix(nrow = R, ncol = k)
  ar <- 0

  for (i in 1:R) {
    proposal <- q(tmp)
    prob <- exp(lf(proposal) - lf(tmp))
    if (runif(1) < prob) {
      tmp <- proposal
      ar <- ar + 1
    }
    x[i,] <- tmp
  }

  structure(x, acceptance.rate = ar/R, step = step-1)
}

Algoritma başlar X1ve daha sonra farklı dağıtım bölgelerinde dolaşır. Açıkçası öncekilerden daha hızlıdır, ancak az sayıda vakayı örneklemek için kullanırsanız, birbirine yakın çekilişlerle sonuçlanabileceğinizi hatırlamanız gerekir. Başka bir sorun, stepboyut hakkında karar vermeniz gerektiğidir , yani algoritmanın ne kadar büyük sıçramalar yapması gerektiği - çok küçük, yavaş hareket etmeye neden olabilir, çok büyük, çok fazla geçersiz teklif yapmaya ve reddetmeye neden olabilir. Kullanım örneği aşağıdadır. Grafiklerde şunları görebilirsiniz: ilk sıradaki marjinal yoğunluklar, ikinci sıradaki traceplots ve değişken çiftleri için sonraki sıçramaları gösteren grafikler.

n <- 500
a <- 50
b <- 125
p <- c(1,5,2,4,3)/15
k <- length(p)
x <- rtrmnomMetrop(1e4, n, p, a, b, step = 15)

cmb <- combn(1:k, 2)

par.def <- par(mfrow=c(4,5), mar = c(2,2,2,2))
for (i in 1:k)
  hist(x[,i], main = paste0("X",i))
for (i in 1:k)
  plot(x[,i], main = paste0("X",i), type = "l", col = "lightblue")
for (i in 1:ncol(cmb))
  plot(jitter(x[,cmb[1,i]]), jitter(x[,cmb[2,i]]),
       type = "l", main = paste(paste0("X", cmb[,i]), collapse = ":"),
       col = "gray")
par(par.def)

resim açıklamasını buraya girin

Bu dağılımdan örneklemeyle ilgili problem , genel olarak çok verimsiz bir örnekleme stratejisinin tanımlanmasıdır . Hayal etp1pk ve a1==ak, b1=bk ve aiyakın biBu durumda, farklı olasılıklara sahip kategorilere örnekleme yapmak istiyorsunuz, ancak sonunda benzer frekanslar bekliyoruz. Aşırı durumlarda, iki kategorik dağılımınp1p2, ve a1a2, b1b2, bu durumda çok nadir bir olay olmasını beklersiniz (böyle bir dağıtımın gerçek hayat örneği, hipoteziyle tutarlı olan örneği bulana kadar örneklemeyi tekrarlayan araştırmacı olacaktır, bu yüzden rastgele örneklemeden daha fazla hile ile ilgilidir) .

Örnekleme yaptığınız yerde Rukhin (2007, 2008) olarak tanımlarsanız dağıtım çok daha az problemlidir. npi her kategorideki durumlar, yani pi'S.


Rukhin, AL (2007). Tedavi sıralaması problemlerinde normal sıra istatistikleri ve geometrik rastgele değişkenlerin toplamları. İstatistik ve olasılık mektupları, 77 (12), 1312-1321.

Rukhin, AL (2008). Dengeli Tahsis Problemlerinde Durdurma Kuralları: Kesin ve Asimptotik Dağılımlar. Sıralı Analiz, 27 (3), 277-292.


Geçersiz örnekleri reddetmek çok yavaş olabilir. Bir çeviri yapmak muhtemelen daha basittir,yi=xiai, m=niai. Bu şekilde sadece üst sınırınız olur,yibiaiHakkında endişelenmek. Ardından, numuneyi reddettiğiniz yerdexa ihlal edildiğinde ( abu
retin

@becko bu yaklaşımı benim tarafımdan açıklanan yaklaşımla karşılaştırırsanız farklı çözümler sunduklarını göreceksiniz .
Tim

Nasıl farklı olabileceklerini anlamıyorum? Tek yaptığım değişkenlerin değişmesiydi.
becko

@ becko başlangıç ​​noktanız bu x[i] >= a. Kafa olasılığı = 0.9 olan önyargılı bir bozuk para attığınızı düşünün. En az 10 kafa ve 10 kuyruk elde edene kadar bozuk para atarsınız. Durma noktasında ortalama olarak kuyruklardan çok daha fazla kafaya sahip olacaksınız. Başlamak, x[1] = ... = x[k] = aher birinin başlangıç ​​noktalarının x[i]farklı olduğu için farklı olduğu gerçeğini göz ardı ettiğiniz anlamına gelir p[i].
Tim

Senin değinmek istediğin noktayı anlıyorum. Çözümünüzle ilgili sevmediğim tek şey, parametrelerin belirli seçimleri için çok verimsiz olabileceğini düşünüyorum.
becko

1

İşte Tim'in R kodunu Python'a çevirmeye çalışıyorum. Bu sorunu anlamak için biraz zaman harcadığım ve Python'daki algoritmaları kodladığım için, insanların ilgilenmesi durumunda bunları paylaşmayı düşündüm.

  1. Kabul-Red algoritması :
def sample_truncated_multinomial_accept_reject(k, pVec, a, b):
    x = list(np.random.multinomial(k, pVec, size=1)[0])
    h = [x[i] >= a[i] and x[i] <= b[i] for i in range(len(x))]
    while sum(h) < len(h):
        x = list(np.random.multinomial(k, pVec, size=1)[0])
        h = [x[i] >= a[i] and x[i] <= b[i] for i in range(len(x))]
    return x
  1. Doğrudan simülasyon
def truncated_multinomial_direct_sampling_from_urn(k, pVec, a, b):
    n = len(pVec)
    while True:
        pp = pVec 
        x = [0 for _ in range(n)] 
        while True:
            if sum([x[h] < b[h] for h in range(n)])==1:
                indx = [h for h in range(n) if x[h] < b[h]][0]
                x[indx] = k - sum(x)
                break
            i = np.random.choice(n, 1, p=pp)[0]
            x[i] += 1
            if x[i] == b[i]:
                pp = [pp[j]/(1-pp[i]) for j in range(n)]
                pp[i] = 0 
            if sum(x) == k:
                break  
        if sum([x[h] < a[h] for h in range(n)]) == 0:
            break 
    return x 
  1. Metropolis algoritması
def compute_log_function(x, pVec, a, b):
    x_less_a = sum([x[i] < a[i] for i in range(len(pVec))])
    x_more_a = sum([x[i] > b[i] for i in range(len(pVec))])
    if x_less_a or x_more_a or sum(x) != k:
        return float("-inf")
    return np.sum(np.log(pVec)*x - np.array([math.lgamma(h+1) for h in x]))
def sampling_distribution(original, pVec, a, b, step):
    x = copy.deepcopy(original) 
    idx = np.random.choice(len(x), 2, replace=False)
    u = np.random.choice(step, 1)[0]
    x[idx[0]] -= u
    x[idx[1]] += u
    x_less_a = sum([x[i] < a[i] for i in range(len(pVec))])
    x_more_a = sum([x[i] > b[i] for i in range(len(pVec))])
    while x_less_a or x_more_a or sum(x) != k:
        x = copy.deepcopy(original)  
        idx = np.random.choice(len(x), 2, replace=False)
        u = np.random.choice(step, 1)[0]
        x[idx[0]] -= u
        x[idx[1]] += u
        x_less_a = sum([x[i] < a[i] for i in range(len(pVec))])
        x_more_a = sum([x[i] > b[i] for i in range(len(pVec))])
    return x 
def sample_truncated_multinomial_metropolis_hasting(k, pVec, a, b, iters, step=1):
    tmp=sample_truncated_multinomial_accept_reject(k, pVec, a, b)[0]
    step = max(2, step)
    for i in range(iters):
        proposal = sampling_distribution(tmp, pVec, a, b, step)
        if compute_log_function(proposal, pVec, a, b) == float("-inf"):
            continue             
        prob = np.exp(np.array(compute_log_function(proposal, pVec, a, b)) -\
                      np.array(compute_log_function(tmp, pVec, a, b)))
        if np.random.uniform() < prob:
            tmp = proposal 
        step -= 1 
    return tmp

Bu kodun eksiksiz bir uygulaması için lütfen şu adresteki Github veri havuzuma bakın:

https://github.com/mohsenkarimzadeh/sampling

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.