วิธีตัวอย่างการแจกแจงแบบหลายส่วนที่ถูกตัดทอน?


9

ฉันต้องการอัลกอริทึมในการสุ่มตัวอย่างการกระจายหลายส่วนแบบตัดปลาย นั่นคือ,

x1Zp1x1pkxkx1!xk!

ที่เป็นค่าคงที่ฟื้นฟู\ vec xมีkส่วนประกอบบวกและ\ รวม x_i n ฉันเพียงพิจารณาค่าของ\ vec {x}ในช่วง\ vec เป็น \ le \ vec x \ le \ vec Zxkxi=nxax

ฉันจะลองตัวอย่างการกระจายหลายส่วนแบบตัดปลายนี้ได้อย่างไร

หมายเหตุ:ดูวิกิพีเดียสำหรับอัลกอริทึมในการสุ่มตัวอย่างการกระจายแบบหลายส่วนแบบไม่ตัดทอน มีวิธีใดที่จะปรับอัลกอริทึมนี้ให้กระจายแบบถูกตัดทอน?

รุ่น Uniform:รุ่นที่เรียบง่ายของปัญหาคือใช้เวลาทั้งหมดพีผมเท่ากับ, พีผม=1/k k หากคุณสามารถออกแบบอัลกอริทึมให้สุ่มตัวอย่างการแจกแจงที่ถูกตัดทอนในกรณีนี้เป็นอย่างน้อยโปรดโพสต์มัน แม้ว่าจะไม่ใช่คำตอบทั่วไปที่จะช่วยฉันแก้ปัญหาเชิงปฏิบัติอื่น ๆ ในขณะนี้

คำตอบ:


9

ถ้าฉันเข้าใจคุณอย่างถูกต้องคุณต้องการตัวอย่างค่าจากการแจกแจงพหุนามด้วยความน่าจะเป็นเช่นนั้นแต่คุณต้องการให้การแจกแจงถูกตัดทอนสำหรับทุกx_ix1,...,xkพี1,...,พีkΣผมxผม=naผมxผมผมxผม

ฉันเห็นวิธีแก้ปัญหาสามข้อ (ไม่หรูหราเหมือนในกรณีที่ไม่ถูกตัดทอน):

  1. ยอมรับปฏิเสธ ตัวอย่างจาก Multinomial ที่ไม่ถูกตัดทอนยอมรับตัวอย่างถ้ามันเหมาะกับขอบเขตของการตัดมิฉะนั้นปฏิเสธและทำซ้ำกระบวนการ มันรวดเร็ว แต่อาจไม่มีประสิทธิภาพมาก
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. การจำลองโดยตรง ตัวอย่างแฟชั่นที่มีลักษณะคล้ายกับกระบวนการสร้างข้อมูลคือตัวอย่างหินอ่อนเดี่ยวจากโกศแบบสุ่มและทำซ้ำกระบวนการนี้จนกว่าคุณจะสุ่มตัวอย่างหินอ่อนทั้งหมด แต่เมื่อคุณปรับใช้จำนวนหินอ่อนทั้งหมดจากโกศที่กำหนด (เท่ากับ ) จากนั้นหยุดการวาดจากโกศ ฉันใช้สิ่งนี้ในสคริปต์ด้านล่างnxผมผม
# 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. อัลกอริทึมมหานคร สุดท้ายวิธีที่สามและมีประสิทธิภาพมากที่สุดที่จะใช้ขั้นตอนวิธีการกรุงเทพมหานคร อัลกอริทึมจะเริ่มต้นโดยใช้การจำลองโดยตรง ( แต่สามารถเริ่มต้นที่แตกต่างกัน) การวาดตัวอย่างแรกX_1ในขั้นตอนต่อไปซ้ำ: ค่าข้อเสนอ ได้รับการยอมรับเป็นกับความน่ามิฉะนั้นค่าดำเนินการในการ มันคือที่ที่. ตามข้อเสนอฉันใช้ฟังก์ชันที่ใช้ค่าและสุ่มพลิกจาก 0 เป็นจำนวนเคสและย้ายไปยังหมวดหมู่อื่นX1Y=Q(Xผม-1)Xผม(Y)/(Xผม-1)Xผม-1(x)αΠผมพีผมxผม/xผม!QXผม-1step
# 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)
}

อัลกอริทึมเริ่มต้นที่จากนั้นจึงเดินไปตามภูมิภาคต่างๆของการแจกแจง เห็นได้ชัดว่าเร็วกว่าในกรณีก่อน ๆ แต่คุณต้องจำไว้ว่าถ้าคุณใช้มันเพื่อสุ่มตัวอย่างจำนวนคดีเล็ก ๆ น้อย ๆ คุณก็สามารถจบลงด้วยการจับที่อยู่ใกล้กัน ปัญหาอีกประการหนึ่งคือคุณต้องตัดสินใจเกี่ยวกับขนาดเช่นการกระโดดครั้งใหญ่ควรอัลกอริทึมอย่างไร - เล็กเกินไปอาจทำให้เคลื่อนที่ช้าลงใหญ่เกินไปอาจนำไปสู่การทำข้อเสนอที่ไม่ถูกต้องมากเกินไปและปฏิเสธพวกเขา คุณสามารถดูตัวอย่างการใช้งานด้านล่าง ในพล็อตที่คุณสามารถดู: ความหนาแน่นเล็กน้อยในแถวแรก traceplots ในแถวที่สองและพล็อตแสดงการกระโดดที่ตามมาสำหรับคู่ของตัวแปรX1step

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)

ป้อนคำอธิบายรูปภาพที่นี่

ปัญหาเกี่ยวกับการสุ่มตัวอย่างจากการกระจายนี้คือการอธิบายกลยุทธ์การสุ่มตัวอย่างที่ไม่มีประสิทธิภาพมากโดยทั่วไป ลองจินตนาการว่าและ ,และอยู่ใกล้กับของในกรณีเช่นนี้คุณต้องการตัวอย่างไปยังหมวดหมู่ที่มีความน่าจะเป็นต่างกัน ความถี่ในที่สุด ในกรณีที่รุนแรงให้จินตนาการการกระจายสองหมวดหมู่โดยที่และ ,พี1พีka1==ak1=...kaผมผมพี1»พี2a1«a21«2ในกรณีเช่นนี้คุณคาดว่าจะมีเหตุการณ์ที่เกิดขึ้นได้ยากน้อยมาก (ตัวอย่างในชีวิตจริงของการแจกแจงดังกล่าวจะเป็นนักวิจัยที่สุ่มตัวอย่างซ้ำ ๆ จนกระทั่งเขาพบตัวอย่างที่สอดคล้องกับสมมติฐานของเขาดังนั้นมันจึงเป็นการโกงมากกว่าการสุ่มแบบสุ่ม) .

การกระจายมากน้อยที่มีปัญหาถ้าคุณกำหนดเป็น Rukhin (2007, 2008) ที่คุณลิ้มลองกรณีในแต่ละหมวดหมู่คือตัวอย่างตามสัดส่วน 'snพีผมพีผม


Rukhin, AL (2007) สถิติการสั่งซื้อปกติและผลรวมของตัวแปรสุ่มเรขาคณิตในปัญหาการจัดสรรการรักษา สถิติและตัวอักษรน่าจะเป็น 77 (12), 1312-1321

Rukhin, AL (2008) การหยุดกฎในปัญหาการจัดสรรแบบสมดุล: การกระจายที่แน่นอนและแบบ Asymptotic การวิเคราะห์ตามลำดับ, 27 (3), 277-292


การปฏิเสธตัวอย่างที่ไม่ถูกต้องอาจช้าเกินไป มันอาจจะง่ายที่จะทำแปล ,Ä_i วิธีนี้คุณมีขอบเขตบนเท่านั้นที่ต้องกังวล จากนั้นคุณสามารถลบบรรทัดที่คุณปฏิเสธตัวอย่างถ้าเป็นละเมิด (หนึ่งสามารถตั้งครรภ์คุณค่าของที่ปฏิเสธนี้จะไม่มีประสิทธิภาพมาก)yi=xiaim=niaiYผมผม-aผมxaa
becko

@ Becko หากคุณเปรียบเทียบวิธีการดังกล่าวกับวิธีที่อธิบายโดยฉันคุณจะเห็นว่าพวกเขาให้วิธีแก้ปัญหาที่แตกต่างกัน
ทิม

ฉันไม่เข้าใจว่าพวกเขาจะแตกต่างกันอย่างไร ทั้งหมดที่ฉันทำคือการเปลี่ยนแปลงของตัวแปร
becko

@becko x[i] >= aจุดเริ่มต้นของคุณคือทั้งหมด ลองนึกภาพคุณโยนเหรียญเอนเอียงด้วยความน่าจะเป็นของหัว = 0.9 คุณโยนเหรียญจนกว่าคุณจะได้รับอย่างน้อย 10 หัวและ 10 ก้อย ที่จุดหยุดคุณจะมีหัวโดยเฉลี่ยมากกว่าก้อย การเริ่มต้นx[1] = ... = x[k] = aหมายความว่าคุณไม่สนใจความจริงที่ว่าจุดเริ่มต้นของแต่ละจุดx[i]นั้นแตกต่างกันเนื่องจากความแตกต่างp[i]ของ
ทิม

ฉันเห็นประเด็นของคุณ สิ่งเดียวที่ฉันไม่ชอบเกี่ยวกับวิธีแก้ปัญหาของคุณคือฉันคิดว่ามันไม่มีประสิทธิภาพมากสำหรับการเลือกพารามิเตอร์
becko

1

นี่คือความพยายามของฉันในการพยายามแปลรหัส R ของทิมเป็น Python เนื่องจากฉันใช้เวลาทำความเข้าใจปัญหานี้และเขียนรหัสอัลกอริทึมใน Python ฉันจึงคิดว่าจะแบ่งปันสิ่งนี้ในกรณีที่ผู้คนสนใจ

  1. อัลกอริธึมยอมรับ - ปฏิเสธ :
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. การจำลองโดยตรง
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. อัลกอริทึมมหานคร
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

สำหรับการติดตั้งโค้ดนี้โดยสมบูรณ์โปรดดูที่เก็บ Github ของฉันที่

https://github.com/mohsenkarimzadeh/sampling

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.