비모수 적 군집화를위한 PyMC : 가우스 혼합의 매개 변수를 추정하기위한 Dirichlet 프로세스가 군집하지 못함


10

문제 설정

PyMC를 적용하려는 첫 번째 장난감 문제 중 하나는 비모수 적 군집입니다. 일부 데이터를 제공하고이를 가우스 혼합으로 모델링하고 군집 수와 각 군집의 평균 및 공분산을 배웁니다. 내가이 방법에 대해 알고있는 대부분의 내용은 2007 년경 Michael Jordan과 Yee Whye Teh의 비디오 강의 (스팀이 격렬 해지기 전에)와 Fonnesbeck 박사와 E. Chen의 자습서 [fn1], fn2]. 그러나 문제는 잘 연구되고 신뢰할만한 구현이있다 [fn3].

이 장난감 문제에서는 1 차원 가우스 에서 10 개의 드로우를 생성 하고 N ( μ = 4 , σ = 2 ) 에서 40 개의 드로우를 생성 합니다. 아래에서 볼 수 있듯이, 어떤 혼합 구성 요소에서 어떤 샘플이 나왔는지 쉽게 알 수 있도록 그림을 섞지 않았습니다.N(μ=0,σ=1)N(μ=4,σ=2)

가우스 혼합 모델 데이터

I는 각각의 데이터 샘플을 모델링 에 대한 = 1 , . . . , 50 및 여기서 z i 는이 i 의 클러스터를 나타냅니다.y나는(μ나는,σ나는)나는=1,...,50나는나는 번째 데이터 포인트 : . N D P는 여기 디리클레 절단 공정의 길이가 사용된다 나를 위해 N나는[1,...,].=50

Dirichlet 프로세스 인프라를 확장하여 각 군집 ID는 범주 형 랜덤 변수에서 추출한 것이며, 그 확률 질량 함수는 스틱 파괴 구성에 의해 제공됩니다. z iC a t e g o r i c a l ( p ) 먼저 N D P를 얻어서 1로 합산해야합니다.나는나는이자형영형아르 자형나는() 농도에 대한 파라미터 α . 스틱 브레이킹은 N D P- 긴 벡터 p를 구성한다에스나는케이(α)α 그에 의존 무 베타 분산 IID [을 Fn1] 참조. 그리고 데이터에 무지에 대해 α를 알기 원 하므로 [fn1]을 따르고 α U n i f o r m ( 0.3 , 100 )으로 가정 합니다.ααα나는에프영형아르 자형미디엄(0.3,100)

각 데이터 샘플의 클러스터 ID 생성 방법을 지정합니다. 각각의 클러스터는 연관된 평균 및 표준 편차, μ z iσ z i를 갖는다 . 그런 다음 μ z i ~ N ( μ = 0 , σ = 50 )σ z i ~ U n i f o r m ( 0 , 100 ) 입니다.μ나는σ나는μ나는(μ=0,σ=50)σ나는나는에프영형아르 자형미디엄(0,100)

(I 이전 [을 Fn1] 생각없이 다음과 hyperprior에 배치 된 이고, μ Z의 μ나는 μ 0 자체가 고정 된 매개 변수 정규 분포 연신 및 σ 0 균일 한에서. 그러나 당https://stats.stackexchange.com/a/71932/31187, 내 데이터는 계층 hyperprior의이 종류를 지원하지 않습니다.)μ나는(μ0,σ0)μ0σ0

요약하면 내 모델은 다음과 같습니다.

여기서 i 는 1에서 50까지 (데이터 샘플 수)입니다.와이나는(μ나는,σ나는)나는

는 0과 사이의 값을 취할 수 N D P - 1 = 49 ; p ~ S t i c k ( α ) , N D P- 길이 벡터; 및 α U n i f o r m ( 0.3 , 100 )나는이자형영형아르 자형나는()1=49에스나는케이(α)α나는에프영형아르 자형미디엄(0.3,100)스칼라 (이제 데이터 샘플 수가 Dirichlet의 잘린 길이와 같게 만드는 것을 약간 후회하지만 명확하기를 바랍니다.)

σ z i ~Uniform(0,100). 거기N D P는 이들 수단과 표준 편차 (의 각각에 대한 하나의N D P 가능한 클러스터).μ나는(μ=0,σ=50)σ나는나는에프영형아르 자형미디엄(0,100)

그래픽 모델은 다음과 같습니다. 이름은 변수 이름입니다 (아래 코드 섹션 참조).

그래프

문제 설명

몇 가지 조정 및 수정 실패에도 불구하고 학습 된 매개 변수는 데이터를 생성 한 실제 값과 전혀 유사하지 않습니다.

나는α=5

μ나는나는μ나는나는=1,...,20

초기화되지 않은 클러스터 ID를 가진 수단

처음 10 개의 데이터 샘플은 하나의 모드에서 왔고 나머지는 다른 모드에서 온 것임을 상기 한 결과는 분명히 그것을 포착하지 못했습니다.

클러스터 ID의 무작위 초기화를 허용하면 둘 이상의 클러스터를 얻지 만 클러스터는 모두 동일한 3.5 수준을 방황합니다.

무작위로 초기화 된 클러스터 ID를 가진 수단

나는

α

부록 : 코드

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

해커를위한 확률 적 프로그래밍 및 베이지안 통계 책 의이 장을 읽었습니까? 도움이 될만한 예가 있습니다!
Tim

이것은 약간의 대답으로 보입니다. 더 많은 의견 인 것 같습니다. OP를 통해 얻을 수있는 정보를 최소한 간략히 설명해 주시겠습니까?
Glen_b-복지 모니카

@TimRich 예 나는 그것을 읽고, 대학원에서 수업을 받았고, 응용 통계를 수행하는 업계에서 일했습니다.) 이것은 PyMC 관련 질문입니다.
Ahmed Fasih

1
나는 계층 적 사전을 무시하지 않을 것입니다. 혼합물의 구성 요소에 평평한 우선 순위를두면 특히 클러스터의 수를 동시에 배우려고 할 때 자신이 나쁜 위치에 있다는 것이 잘 알려져 있습니다 . 이것이 내가 생각하는 흔적 플롯에서 이상한 스파이크를 일으키는 원인입니다. NP-Bayes의 큰 이름은 모두 μ Z i 를 설정하는 것으로 보입니다.μ나는(μ0,σ0)μ0,σ0

답변:


4

누군가 가이 질문을 더 이상보고 있는지 확신 할 수 없지만 Tom의 Gibbs 샘플링 제안을 테스트하기 위해 rjags에 질문을 넣는 동안 표준 편차에 대한 평면에 대한 Guy의 통찰력을 통합했습니다.

이 장난감 문제는 10 개 및 40 개 데이터 포인트가 사전 정보없이 분산을 추정하기에 충분하지 않으므로 어려울 수 있습니다. 현재의 이전 σzi∼Uniform (0,100)은 유익하지 않습니다. 이것은 왜 거의 모든 μzi의 드로우가 두 분포의 예상 평균인지 설명 할 수 있습니다. 귀하의 질문을 너무 많이 변경하지 않으면 각각 100 및 400 데이터 포인트를 사용합니다.

또한 코드에서 직접 스틱 브레이킹 프로세스를 사용하지 않았습니다. dirichlet 프로세스 의 wikipedia 페이지에서 p ~ Dir (a / k)가 정상이라고 생각했습니다.

마지막으로 여전히 많은 클러스터 k를 취하기 때문에 반 매개 변수 구현입니다. rjags에서 무한 혼합 모델을 만드는 방법을 모르겠습니다.

마르코프 체인 뮤 클러스터 1

마르코프 체인 뮤 클러스터 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
케이케이α나는=/케이500케이=25JAGSJAGS

1

PyMC가 샘플을 추출하는 방식으로 인해 혼합 상태가 좋지 않을 수 있습니다. PyMC 설명서의 5.8.1 섹션에 설명 된대로 배열 변수의 모든 요소가 함께 업데이트됩니다. 귀하의 경우, 그것은 전체 clustermean배열을 한 단계 로 업데이트하려고 시도한다는 것을 의미합니다 clusterid. PyMC는 Gibbs 샘플링을 수행하지 않습니다. 제안은 간단한 휴리스틱에 의해 선택되는 Metropolis를 수행합니다. 이로 인해 전체 배열에 대해 좋은 값을 제안 할 가능성이 없습니다.


"한 번에 전체 어레이를 업데이트하려고합니다"라고 말하자마자 Metropolis (이 경우)와 Gibbs의 단점을 이해했습니다. STAN 또는 JAGS에 대해 더 잘 할 수있는 특별한 것이 있습니까? 두 경우 모두 PyMC에서 Gibbs를 구현하는 데 시간을 할애합니다. 감사합니다! (저는 광속부터 작업에 대한 팬이었습니다. 감사합니다.)
Ahmed Fasih

1
STAN은 이산 변수를 처리하지 않지만 JAGS는 시도해 볼 가치가 있습니다.
Tom Minka
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.