확률 밀도 함수가 있는 일반 정규 분포 ( wikipedia entry )를 사용하여 식물 분산을 모델링 하고 있습니다.
여기서 는 이동 거리, 는 척도 모수, 는 모양 모수입니다. 이동 한 평균 거리는이 분포의 표준 편차로 제공됩니다.
이것은 일 때 지수 모양 , 일 때 가우시안 모양 , 때 렙 토쿠 르틱 분포를 허용하기 때문에 편리합니다 . 이 분포는 일반적으로 매우 드물기 때문에 식물 분산 문헌에서 정기적으로 자라기 때문에 정보를 찾기가 어렵습니다.
가장 흥미로운 매개 변수는 와 평균 분산 거리입니다.
MCMC를 사용하여 와 를 추정하려고 하지만 제안서 값을 샘플링하는 효율적인 방법을 마련하기 위해 고심하고 있습니다. 지금까지 나는 Metropolis-Hastings를 사용했으며 균일 분포 and 에서 도출했으며 약 200-400 미터의 후방 평균 분산 거리를 얻었습니다. 이는 생물학적 의미가 있습니다. 그러나 수렴은 실제로 느리고 전체 매개 변수 공간을 탐색하고 있다고 확신하지 않습니다.
와 대한 더 나은 제안서 배포를 제안하는 것은 까다 롭습니다 . 왜냐하면 그것들은 자체적으로 많은 의미를 갖지 않고 서로 의존하기 때문입니다. 평균 분산 거리는 명확한 생물학적 의미를 갖지만, 주어진 평균 분산 거리는 무한히 많은 와 조합으로 설명 될 수 있습니다 . 이와 같이 와 는 후부에서 상관된다.
지금까지 Metropolis Hastings를 사용했지만 여기에서 작동하는 다른 알고리즘을 사용할 수 있습니다.
질문 : 누구나 와 대한 제안 값을보다 효율적으로 그릴 수있는 방법을 제안 할 수 있습니까 ?
편집 : 시스템에 대한 추가 정보 : 계곡을 따라 식물 집단을 연구하고 있습니다. 목표는 공여자 식물과 그들이 수분하는 식물 사이에서 꽃가루가 이동 한 거리의 분포를 결정하는 것입니다. 내가 가진 데이터는 다음과 같습니다
- 가능한 모든 꽃가루 기증자의 위치와 DNA
- 성장하고 유전자형 화 된 60 개의 모체 식물 (예 : 꽃가루 수용기) 샘플에서 수집 한 씨앗.
- 각 모성 식물의 위치와 DNA.
기증자 식물의 정체성을 모르지만, 이것은 어떤 기증자가 각 묘종의 아버지인지를 결정함으로써 유전 데이터로부터 추론 할 수 있습니다. 이 정보는 각 자손에 대한 행과 각 후보 공여자에 대한 열이있는 확률 행렬 G에 포함되어 있으며 , 이는 각 후보자가 유전자 데이터를 기반으로 각 자손의 아버지가 될 확률을 제공합니다. G 는 계산하는 데 약 3 초가 걸리며 반복 할 때마다 다시 계산해야하므로 속도가 상당히 느려집니다.
우리는 일반적으로 더 가까운 후보 공여자가 아버지가 될 가능성이 높기 때문에, 친자 관계와 유추를 함께 추론하면 친자 관계 유추가 더 정확합니다. 행렬 D 는 G 와 차원이 같 으며 어머니와 후보자 사이의 거리와 일부 매개 변수 벡터만으로 친자 관계의 확률을 포함합니다. D 와 G의 요소를 곱하면 유전 적 및 공간적 데이터가 주어지면 친자 관계가 될 확률이 높아집니다. 곱한 값의 곱은 분산 모델의 가능성을 제공합니다.
위에서 설명한 것처럼 분산을 모델링하기 위해 GND를 사용했습니다. 사실 저는 GND와 균일 한 분포의 혼합을 사용하여 무시할 경우 GND의 명백한 꼬리를 부 풀릴 수있는 우연 (유전자가 지저분 함)으로 인해 친자 관계 가능성이 더 높은 먼 후보자들의 가능성을 허용했습니다. 따라서 분산 거리 의 확률 은 다음과 같습니다.
여기서 는 GND로부터의 분산 거리 확률이고, N은 후보의 수이며, ( )는 GND가 분산에 얼마나 많은 기여를하는지 결정합니다.
따라서 계산 부담을 증가시키는 두 가지 추가 고려 사항이 있습니다.
- 분산 거리는 알려져 있지 않지만 매번 반복 할 때마다 유추되어야합니다 .이를 위해 G 를 생성 하는 것은 비용이 많이 듭니다.
- 통합 할 세 번째 매개 변수 가 있습니다.
이러한 이유로 그리드 보간을 수행하기에는 너무 복잡해 보였지만 다른 방법으로 확신하게되어 기쁩니다.
예
다음은 내가 사용한 파이썬 코드의 간단한 예입니다. 유전자 데이터에서 친자 확인을 단순화했습니다. 많은 추가 코드가 필요하기 때문에 0과 1 사이의 값으로 대체되었습니다.
먼저 GND를 계산하는 함수를 정의하십시오.
import numpy as np
from scipy.special import gamma
def generalised_normal_PDF(x, a, b, gamma_b=None):
"""
Calculate the PDF of the generalised normal distribution.
Parameters
----------
x: vector
Vector of deviates from the mean.
a: float
Scale parameter.
b: float
Shape parameter
gamma_b: float, optional
To speed up calculations, values for Euler's gamma for 1/b
can be calculated ahead of time and included as a vector.
"""
xv = np.copy(x)
if gamma_b:
return (b/(2 * a * gamma_b )) * np.exp(-(xv/a)**b)
else:
return (b/(2 * a * gamma(1.0/b) )) * np.exp(-(xv/a)**b)
def dispersal_GND(x, a, b, c):
"""
Calculate a probability that each candidate is a sire
assuming assuming he is either drawn at random form the
population, or from a generalised normal function of his
distance from each mother. The relative contribution of the
two distributions is controlled by mixture parameter c.
Parameters
----------
x: vector
Vector of deviates from the mean.
a: float
Scale parameter.
b: float
Shape parameter
c: float between 0 and 1.
The proportion of probability mass assigned to the
generalised normal function.
"""
prob_GND = generalised_normal_PDF(x, a, b)
prob_GND = prob_GND / prob_GND.sum(axis=1)[:, np.newaxis]
prob_drawn = (prob_GND * c) + ((1-c) / x.shape[1])
prob_drawn = np.log(prob_drawn)
return prob_drawn
다음으로 2000 명의 후보자와 800 명의 자손을 시뮬레이션합니다. 또한 자손의 어머니와 후보 아버지 사이의 거리 목록과 더미 G 행렬을 시뮬레이션합니다 .
n_candidates = 2000 # Number of candidates in the population
n_offspring = 800 # Number of offspring sampled.
# Create (log) matrix G.
# These are just random values between 0 and 1 as an example, but must be inferred in reality.
g_matrix = np.random.uniform(0,1, size=n_candidates*n_offspring)
g_matrix = g_matrix.reshape([n_offspring, n_candidates])
g_matrix = np.log(g_matrix)
# simulate distances to ecah candidate father
distances = np.random.uniform(0,1000, 2000)[np.newaxis]
초기 매개 변수 값을 설정하십시오.
# number of iterations to run
niter= 100
# set intitial values for a, b, and c.
a_current = np.random.uniform(0.001,500, 1)
b_current = np.random.uniform(0.01, 3, 1)
c_current = np.random.uniform(0.001, 1, 1)
# set initial likelihood to a very small number
lik_current = -10e12
a, b 및 c를 차례로 업데이트하고 대도시 비율을 계산하십시오.
# number of iterations to run
niter= 100
# set intitial values for a, b, and c.
# When values are very small, this can cause the Gamma function to break, so the limit is set to >0.
a_current = np.random.uniform(0.001,500, 1)
b_current = np.random.uniform(0.01, 3, 1)
c_current = np.random.uniform(0.001, 1, 1)
# set initial likelihood to a very small number
lik_current = -10e12
# empty array to store parameters
store_params = np.zeros([niter, 3])
for i in range(niter):
a_proposed = np.random.uniform(0.001,500, 1)
b_proposed = np.random.uniform(0.01,3, 1)
c_proposed = np.random.uniform(0.001,1, 1)
# Update likelihood with new value for a
prob_dispersal = dispersal_GND(distances, a=a_proposed, b=b_current, c=c_current)
lik_proposed = (g_matrix + prob_dispersal).sum() # lg likelihood of the proposed value
# Metropolis acceptance ration for a
accept = bool(np.random.binomial(1, np.min([1, np.exp(lik_proposed - lik_current)])))
if accept:
a_current = a_proposed
lik_current = lik_proposed
store_params[i,0] = a_current
# Update likelihood with new value for b
prob_dispersal = dispersal_GND(distances, a=a_current, b=b_proposed, c=c_current)
lik_proposed = (g_matrix + prob_dispersal).sum() # log likelihood of the proposed value
# Metropolis acceptance ratio for b
accept = bool(np.random.binomial(1, np.min([1, np.exp(lik_proposed - lik_current)])))
if accept:
b_current = b_proposed
lik_current = lik_proposed
store_params[i,1] = b_current
# Update likelihood with new value for c
prob_dispersal = dispersal_GND(distances, a=a_current, b=b_current, c=c_proposed)
lik_proposed = (g_matrix + prob_dispersal).sum() # lg likelihood of the proposed value
# Metropolis acceptance ratio for c
accept = bool(np.random.binomial(1, np.min([1, np.exp(lik_proposed - lik_current)])))
if accept:
c_current = c_proposed
lik_current = lik_proposed
store_params[i,2] = c_current