PyMC สำหรับการจัดกลุ่มแบบไม่ใช้พารามิเตอร์: กระบวนการ Dirichlet เพื่อประเมินพารามิเตอร์ของส่วนผสมแบบเกาส์ไม่สามารถทำคลัสเตอร์ได้


10

การตั้งค่าปัญหา

หนึ่งในปัญหาของเล่นครั้งแรกที่ฉันต้องการใช้ PyMC กับการจัดกลุ่มแบบไม่ใช้พารามิเตอร์: ให้ข้อมูลบางส่วนสร้างแบบจำลองเป็นแบบเกาส์และเรียนรู้จำนวนของกลุ่มและค่าเฉลี่ยและความแปรปรวนร่วมของแต่ละกลุ่ม สิ่งที่ฉันรู้เกี่ยวกับวิธีนี้ส่วนใหญ่มาจากการบรรยายทางวิดีโอโดย Michael Jordan และ Yee Whye Teh ประมาณปี 2007 (ก่อนที่จะกลายเป็นความโกรธแค้น) และสองสามวันสุดท้ายของการอ่านบทเรียนของดร. Fonnesbeck และ E. Chen [fn1], [ Fn2] แต่ปัญหาคือการศึกษาที่ดีและมีการใช้งานที่น่าเชื่อถือ [fn3]

ในปัญหาของเล่นนี้ฉันสร้างสิบดึงจากหนึ่งมิติเกาส์และสี่สิบวาดจาก . อย่างที่คุณเห็นด้านล่างฉันไม่ได้สลับการสุ่มเพื่อให้ง่ายต่อการบอกว่าตัวอย่างใดมาจากส่วนประกอบผสมN ( μ = 4 , σ = 2 )N(μ=0,σ=1)N(μ=4,σ=2)

ข้อมูลแบบจำลองการผสมแบบเกาส์

ฉันจำลองแต่ละตัวอย่างข้อมูลสำหรับและที่บ่งชี้ถึงคลัสเตอร์สำหรับจุดข้อมูลนี้:{DP}] นี่คือความยาวของกระบวนการ Dirichlet ตัดทอนที่ใช้: สำหรับผมn_ฉัน= 1 , . . , 50 Z ฉันฉันZ ฉัน[ 1 , . . , N D P ] N D P N D P = 50yiN(μzi,σzi)i=1,...,50ziizi[1,...,NDP]NDPNDP=50

การขยายโครงสร้างพื้นฐานของกระบวนการ Dirichlet แต่ละID กลุ่มของคือการดึงจากตัวแปรสุ่มแบบเด็ดขาดซึ่งฟังก์ชันความน่าจะเป็นจำนวนมากจะได้รับจากการสร้างแบบ :ด้วยสำหรับ a พารามิเตอร์เข้มข้น\โครงสร้างที่สร้างการแยกที่ไม่ต่อเนื่องสร้าง - เวกเตอร์ยาวซึ่งต้องรวมเป็น 1 โดยการได้รับ iid การแจกแจงแบบเบต้าแบบกระจายที่ขึ้นอยู่กับดู [fn1] และตั้งแต่ฉันต้องการข้อมูลที่จะแจ้งความโง่เขลาของฉันผมทำตาม [Fn1] และถือว่า100)Z ฉัน ~ C ทีอีกรัมo R ฉันลิตร( P ) P ~ S T ฉันc k ( α ) α N D P P N D P α α α ~ U n ฉันo R ม. ( 0.3 , 100 )ziziCategorical(p)pStick(α)αNDPpNDPαααUniform(0.3,100)

สิ่งนี้ระบุวิธีสร้าง ID คลัสเตอร์ของตัวอย่างข้อมูลแต่ละตัว แต่ละกลุ่มมีความเกี่ยวข้องค่าเฉลี่ยและค่าเบี่ยงเบนมาตรฐาน,และ{} จากนั้นและ100) μ z ฉัน σ z ฉัน μ z ฉันN ( μ = 0 , σ = 50 ) σ z ฉันU n ฉันf o r m ( 0 , 100 )NDPμziσziμziN(μ=0,σ=50)σziUniform(0,100)

(ผมได้รับก่อนหน้านี้ [Fn1] ไม่คิดและวาง hyperprior บน , ที่อยู่,กับตัวเองวาดจาก การแจกแจงแบบคงที่พารามิเตอร์คงที่และจากชุดรูปแบบ แต่ต่อhttps://stats.stackexchange.com/a/71932/31187ข้อมูลของฉันไม่สนับสนุน hyperprior ลำดับชั้นแบบนี้) μ z ฉันN ( μ 0 , σ 0 ) μ 0 σ 0μziμziN(μ0,σ0)μ0σ0

โดยสรุปแบบจำลองของฉันคือ:

iyiN(μzi,σzi)โดยที่วิ่งจาก 1 ถึง 50 (จำนวนตัวอย่างข้อมูล)i

ziCategorical(p)และสามารถรับค่าระหว่าง 0 ถึง ; , - เวกเตอร์ยาว และสเกลาร์ (ตอนนี้ฉันเสียใจเล็กน้อยที่ทำให้จำนวนตัวอย่างข้อมูลเท่ากับความยาวที่ถูกตัดของ Dirichlet มาก่อน แต่ฉันหวังว่ามันจะชัดเจน)NDP1=49pStick(α)NDPαUniform(0.3,100)

μziN(μ=0,σ=50)และ100) มีของวิธีการเหล่านี้และค่าเบี่ยงเบนมาตรฐาน (หนึ่งค่าสำหรับแต่ละกลุ่มที่เป็นไปได้ของ )σziUniform(0,100)NDPNDP

นี่คือรูปแบบกราฟิก: ชื่อเป็นชื่อตัวแปรดูส่วนรหัสด้านล่าง

กราฟ

คำชี้แจงปัญหา

แม้จะมีการปรับแต่งมากมายและการแก้ไขที่ล้มเหลว แต่พารามิเตอร์ที่เรียนรู้นั้นไม่ได้คล้ายกับค่าจริงที่สร้างข้อมูล

ขณะนี้ฉันกำลังเริ่มต้นตัวแปรสุ่มส่วนใหญ่เป็นค่าคงที่ ตัวแปรค่าเฉลี่ยและส่วนเบี่ยงเบนมาตรฐานจะเริ่มต้นไปยังค่าที่คาดหวังของพวกเขา (เช่น 0 สำหรับคนปกติกลางของการสนับสนุนของพวกเขาสำหรับคนที่เหมือนกัน) ผมเริ่มต้นทุกรหัสคลัสเตอร์เป็น 0 และฉันเริ่มต้นความเข้มข้นพารามิเตอร์ 5ziα=5

ด้วยการกำหนดค่าเริ่มต้นการทำซ้ำ 100'000 MCMC จะไม่สามารถค้นหาคลัสเตอร์ที่สองได้ อิลิเมนต์แรกของใกล้เคียงกับ 1 และการดึงข้อมูลเกือบทั้งหมดของสำหรับตัวอย่างข้อมูลทั้งหมดที่เหมือนกันคือประมาณ 3.5 ฉันแสดงทุก ๆ 100 ปีที่นี่สำหรับตัวอย่างยี่สิบข้อมูลแรกนั่นคือสำหรับ :pμziiμzii=1,...,20

หมายถึงด้วย ID คลัสเตอร์ที่เริ่มต้นได้ที่ศูนย์

จำได้ว่าตัวอย่างข้อมูลสิบตัวอย่างแรกนั้นมาจากโหมดเดียวและส่วนที่เหลือมาจากอีกโหมดหนึ่งผลลัพธ์ข้างต้นไม่สามารถจับภาพได้อย่างชัดเจน

ถ้าฉันอนุญาตให้เริ่มต้นแบบสุ่มของ ID คลัสเตอร์จากนั้นฉันจะได้รับมากกว่าหนึ่งคลัสเตอร์ แต่คลัสเตอร์หมายถึงทั้งหมดเดินไปรอบ ๆ ระดับ 3.5 เดียวกัน:

หมายถึงด้วย ID คลัสเตอร์ที่เริ่มต้นได้แบบสุ่ม

สิ่งนี้ชี้ให้ฉันเห็นว่าเป็นปัญหาปกติของ MCMC ที่ไม่สามารถเข้าถึงโหมดหลังของโหมดอื่นที่อยู่ที่: จำได้ว่าผลลัพธ์ที่แตกต่างเหล่านี้เกิดขึ้นหลังจากเพียงเปลี่ยนการเริ่มต้นของ ID คลัสเตอร์ไม่ใช่นักบวชหรือ สิ่งอื่นใดzi

ฉันทำผิดแบบจำลองใด ๆ หรือไม่? คำถามที่คล้ายกัน: https://stackoverflow.com/q/19114790/500207ต้องการใช้การแจกแจง Dirichlet และใส่ส่วนผสมแบบเกาส์ 3 องค์ประกอบและพบปัญหาที่คล้ายกัน ฉันควรพิจารณาตั้งค่ารูปแบบคอนจูเกตแบบสมบูรณ์และใช้การสุ่มตัวอย่างแบบกิ๊บส์สำหรับการจัดกลุ่มแบบนี้หรือไม่ (ฉันใช้เครื่องมือเก็บตัวอย่างกิ๊บส์สำหรับคดีการแจกแจงพารามิเตอร์ Dirichlet ยกเว้นการใช้ความเข้มข้นคงที่ย้อนกลับไปในวันนี้และใช้งานได้ดีดังนั้นคาดว่า PyMC จะสามารถแก้ปัญหานั้นได้อย่างง่ายดาย)α

ภาคผนวก: รหัส

import pymc
import numpy as np

### Data generation

# Means and standard deviations of the Gaussian mixture model. The inference
# engine doesn't know these.
means = [0, 4.0]
stdevs = [1, 2.0]

# Rather than randomizing between the mixands, just specify how many
# to draw from each. This makes it really easy to know which draws
# came from which mixands (the first N1 from the first, the rest from
# the secon). The inference engine doesn't know about N1 and N2, only Ndata
N1 = 10
N2 = 40
Ndata = N1+N2

# Seed both the data generator RNG  as well as the global seed (for PyMC)
RNGseed = 123
np.random.seed(RNGseed)

def generate_data(draws_per_mixand):
    """Draw samples from a two-element Gaussian mixture reproducibly.

    Input sequence indicates the number of draws from each mixand. Resulting
    draws are concantenated together.

    """
    RNG = np.random.RandomState(RNGseed)
    values = np.hstack([RNG.normal(means[i], stdevs[i], ndraws)
                        for (i,ndraws) in enumerate(draws_per_mixand)])
    return values

observed_data = generate_data([N1, N2])


### PyMC model setup, step 1: the Dirichlet process and stick-breaking

# Truncation level of the Dirichlet process
Ndp = 50

# "alpha", or the concentration of the stick-breaking construction. There exists
# some interplay between choice of Ndp and concentration: a high concentration
# value implies many clusters, in turn implying low values for the leading
# elements of the probability mass function built by stick-breaking. Since we
# enforce the resulting PMF to sum to one, the probability of the last cluster
# might be then be set artificially high. This may interfere with the Dirichlet
# process' clustering ability.
#
# An example: if Ndp===4, and concentration high enough, stick-breaking might
# yield p===[.1, .1, .1, .7], which isn't desireable. You want to initialize
# concentration so that the last element of the PMF is less than or not much
# more than the a few of the previous ones. So you'd want to initialize at a
# smaller concentration to get something more like, say, p===[.35, .3, .25, .1].
#
# A thought: maybe we can avoid this interdependency by, rather than setting the
# final value of the PMF vector, scale the entire PMF vector to sum to 1? FIXME,
# TODO.
concinit = 5.0
conclo = 0.3
conchi = 100.0
concentration = pymc.Uniform('concentration', lower=conclo, upper=conchi,
                             value=concinit)

# The stick-breaking construction: requires Ndp beta draws dependent on the
# concentration, before the probability mass function is actually constructed.
betas = pymc.Beta('betas', alpha=1, beta=concentration, size=Ndp)

@pymc.deterministic
def pmf(betas=betas):
    "Construct a probability mass function for the truncated Dirichlet process"
    # prod = lambda x: np.exp(np.sum(np.log(x))) # Slow but more accurate(?)
    prod = np.prod
    value = map(lambda (i,u): u * prod(1.0 - betas[:i]), enumerate(betas))
    value[-1] = 1.0 - sum(value[:-1]) # force value to sum to 1
    return value

# The cluster assignments: each data point's estimated cluster ID.
# Remove idinit to allow clusterid to be randomly initialized:
idinit = np.zeros(Ndata, dtype=np.int64)
clusterid = pymc.Categorical('clusterid', p=pmf, size=Ndata, value=idinit)

### PyMC model setup, step 2: clusters' means and stdevs

# An individual data sample is drawn from a Gaussian, whose mean and stdev is
# what we're seeking.

# Hyperprior on clusters' means
mu0_mean = 0.0
mu0_std = 50.0
mu0_prec = 1.0/mu0_std**2
mu0_init = np.zeros(Ndp)
clustermean = pymc.Normal('clustermean', mu=mu0_mean, tau=mu0_prec,
                          size=Ndp, value=mu0_init)

# The cluster's stdev
clustersig_lo = 0.0
clustersig_hi = 100.0
clustersig_init = 50*np.ones(Ndp) # Again, don't really care?
clustersig = pymc.Uniform('clustersig', lower=clustersig_lo,
                          upper=clustersig_hi, size=Ndp, value=clustersig_init)
clusterprec = clustersig ** -2

### PyMC model setup, step 3: data

# So now we have means and stdevs for each of the Ndp clusters. We also have a
# probability mass function over all clusters, and a cluster ID indicating which
# cluster a particular data sample belongs to.

@pymc.deterministic
def data_cluster_mean(clusterid=clusterid, clustermean=clustermean):
    "Converts Ndata cluster IDs and Ndp cluster means to Ndata means."
    return clustermean[clusterid]

@pymc.deterministic
def data_cluster_prec(clusterid=clusterid, clusterprec=clusterprec):
    "Converts Ndata cluster IDs and Ndp cluster precs to Ndata precs."
    return clusterprec[clusterid]

data = pymc.Normal('data', mu=data_cluster_mean, tau=data_cluster_prec,
                   observed=True, value=observed_data)

อ้างอิง

  1. fn1: http://nbviewer.ipython.org/urls/raw.github.com/fonnesbeck/Bios366/master/notebooks/Section5_2-Dirichlet-Processes.ipynb
  2. fn2: http://blog.echen.me/2012/03/20/infinite-mixture-models-with-nonparametric-bayes-and-the-dirichlet-process/
  3. fn3: http://scikit-learn.org/stable/auto_examples/mixture/plot_gmm.html#example-mixture-plot-gmm-py

ความแปรปรวนขององค์ประกอบก่อนหน้าของคุณคือ Uniform (0,100) ซึ่งอาจทำให้คุณเกิดปัญหาใหญ่ มีเพียง 2% ของมวลก่อนหน้านี้ซึ่งครอบคลุมความแปรปรวนที่แท้จริงของ 1 และ 2 ความแปรปรวนที่คาดหวังของส่วนประกอบของคุณภายใต้ก่อนหน้านี้คือ 50 ซึ่งเป็นแบบเกาส์ทั่วไปที่สามารถอธิบายข้อมูลของคุณได้อย่างง่ายดายด้วยองค์ประกอบเดียว
jerad

คุณได้อ่านหนังสือProbabilistic Programming และ Bayesian Statistics for Hackers แล้วหรือยัง? มันมีตัวอย่างที่อาจช่วยคุณได้!
ทิม

ดูเหมือนว่าจะเป็นคำตอบสั้น ๆ ดูเหมือนจะเป็นความคิดเห็นเพิ่มเติม อย่างน้อยคุณสามารถร่างข้อมูล OP ที่จะได้รับโดยการอ่านมันได้หรือไม่
Glen_b -Reinstate Monica

@ TimRich ใช่ฉันได้อ่านและเข้าเรียนในบัณฑิตวิทยาลัยและทำงานในอุตสาหกรรมที่ใช้สถิติประยุกต์) เป็นคำถามเฉพาะของ PyMC
Ahmed Fasih

1
ฉันจะไม่ยกเลิกลำดับชั้นมาก่อน เป็นที่ทราบกันดีว่าคุณทำให้ตัวเองอยู่ในตำแหน่งที่ไม่ดีถ้าคุณใส่นักบวชแบน ๆ บนส่วนประกอบของส่วนผสม - โดยเฉพาะอย่างยิ่งเมื่อคุณพยายามที่จะเรียนรู้จำนวนของกลุ่ม นี่คือสิ่งที่ทำให้เกิดแหลมแปลกในแปลงติดตามของคุณฉันคิดว่า ชื่อขนาดใหญ่ใน NP-Bayes ดูเหมือนจะตั้งค่าและใช้การประมาณปลั๊กอินของหรือวางข้อมูลไว้ก่อนหน้านี้ วางไว้บนตาชั่งที่เหมาะสม μ 0 , σ 0μZiN(μ0,σ0)μ0,σ0
ผู้ชาย

คำตอบ:


4

ฉันไม่แน่ใจว่าใครจะดูคำถามนี้อีก แต่ฉันใส่คำถามของคุณใน rjags เพื่อทดสอบข้อเสนอแนะการสุ่มตัวอย่างของทอมกิ๊บส์ในขณะที่รวมข้อมูลเชิงลึกจาก Guy เกี่ยวกับแฟลตก่อนส่วนเบี่ยงเบนมาตรฐาน

ปัญหาของเล่นนี้อาจเป็นเรื่องยากเพราะ 10 และ 40 จุดข้อมูลไม่เพียงพอที่จะประเมินความแปรปรวนโดยไม่มีข้อมูลมาก่อน σzi∼ ก่อนหน้าปัจจุบันปัจจุบัน (0,100) ไม่ใช่ข้อมูล นี่อาจอธิบายได้ว่าทำไมการดึงμziเกือบทั้งหมดจึงเป็นค่าเฉลี่ยที่คาดหวังของการแจกแจงสองแบบ หากไม่เปลี่ยนคำถามของคุณมากเกินไปฉันจะใช้จุดข้อมูล 100 และ 400 ตามลำดับ

ฉันยังไม่ได้ใช้กระบวนการแยกติดโดยตรงในรหัสของฉัน วิกิพีเดียหน้าสำหรับกระบวนการ Dirichlet ทำให้ฉันคิดว่า P ~ Dir (A / k) จะ ok

ในที่สุดมันก็เป็นเพียงการดำเนินการแบบกึ่งพารามิเตอร์เพราะมันยังคงใช้จำนวน k กลุ่ม ฉันไม่รู้ว่าจะสร้างแบบจำลองที่ไม่มีที่สิ้นสุดใน rjags ได้อย่างไร

มาร์คอฟเชน mu คลัสเตอร์ 1

มาร์คอฟเชน mu คลัสเตอร์ 2

library("rjags")

set1 <- rnorm(100, 0, 1)
set2 <- rnorm(400, 4, 1)
data <- c(set1, set2)

plot(data, type='l', col='blue', lwd=3,
     main='gaussian mixture model data',
     xlab='data sample #', ylab='data value')
points(data, col='blue')

cpd.model.str <- 'model {
  a ~ dunif(0.3, 100)
  for (i in 1:k){
    alpha[i] <- a/k
    mu[i] ~ dnorm(0.0, 0.001)
    sigma[i] ~ dunif(0, 100)
  }
  p[1:k] ~ ddirich(alpha[1:k])
  for (i in 1:n){
    z[i] ~ dcat(p)
    y[i] ~ dnorm(mu[z[i]], pow(sigma[z[i]], -2))
  }
}' 


cpd.model <- jags.model(textConnection(cpd.model.str),
                        data=list(y=data,
                                  n=length(data),
                                  k=5))
update(cpd.model, 1000)
chain <- coda.samples(model = cpd.model, n.iter = 1000,
                      variable.names = c('p', 'mu', 'sigma'))
rchain <- as.matrix(chain)
apply(rchain, 2, mean)

1
สำหรับการใช้กลุ่มจำนวน จำกัดคุณสามารถใช้ใหญ่ (และตั้งค่าตามที่คุณมี) และรับแบบจำลองที่เหมือนกับกระบวนการ Dirichlet อย่างมีประสิทธิภาพ การบรรจบกันของกระบวนการนี้ก่อนกระบวนการ Dirichlet นั้นรวดเร็วมาก สำหรับการสังเกตครั้งสิ่งที่คล้ายน่าจะเกินพอ นอกจากนี้ยังฉลาดเมื่อใช้เพื่อไม่ใช้โครงสร้างแบบทำลายเพราะจะไม่ตรวจพบการอัปเดตบล็อกใน ; สิ่งที่คุณทำที่นี่ดีกว่า K α i = a / K 500 K = 25 pKKαi=a/K500K=25JAGSJAGSp
ผู้ชายที่

1

การผสมที่ไม่ดีที่คุณเห็นเป็นไปได้มากที่สุดเนื่องจากวิธีการที่ PyMC ดึงตัวอย่าง ดังที่อธิบายไว้ในหัวข้อ 5.8.1ของเอกสารประกอบ PyMC องค์ประกอบทั้งหมดของตัวแปรอาร์เรย์จะได้รับการอัพเดตพร้อมกัน ในกรณีของคุณนั่นหมายความว่ามันจะพยายามที่จะปรับปรุงทั้งอาร์เรย์ในขั้นตอนเดียวและในทำนองเดียวกันสำหรับclustermean clusteridPyMC ไม่ทำการสุ่มตัวอย่างจากกิ๊บส์ มันเป็นเมืองหลวงที่มีการเลือกข้อเสนอโดยการวิเคราะห์พฤติกรรมแบบง่าย ๆ สิ่งนี้ทำให้ไม่น่าที่จะเสนอค่าที่ดีสำหรับทั้งอาร์เรย์


ทันทีที่คุณพูดว่า "จะพยายามอัปเดตอาร์เรย์ทั้งหมดในขั้นตอนเดียว" ฉันเข้าใจข้อเสียของ Metropolis (ในตัวอย่างนี้) เมื่อเทียบกับ Gibbs มีอะไรพิเศษเกี่ยวกับ STAN หรือ JAGS ที่อาจทำให้พวกเขาทำได้ดีขึ้นในเรื่องนี้? ไม่ว่าในกรณีใดฉันจะใช้เวลาสักครู่ในการติดตั้ง Gibbs ใน PyMC ขอบคุณ! (ฉันเป็นแฟนตัวยงของการทำงานของคุณตั้งแต่ Lightspeed ขอบคุณมาก ๆ !)
Ahmed Fasih

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