Olasılık yoğunluğu fonksiyonuna sahip genelleştirilmiş bir normal dağılım ( wikipedia girişi ) kullanarak bitki dağılımını modelleniyorum :
burada kat edilen mesafedir, bir ölçek parametresidir ve şekil parametresidir. Ortalama kat edilen mesafe bu dağılımın standart sapması ile verilir:
Bu uygundur, çünkü olduğunda üstel bir şekle, olduğunda bir Gauss şekline ve olduğunda leptokurtik bir dağılım sağlar . Bu dağılım, genel olarak oldukça nadir olmasına ve dolayısıyla hakkında bilgi bulmak zor olmasına rağmen, bitki dağılım literatüründe düzenli olarak ekilir.
En ilginç parametreler ve ortalama dağılım mesafesidir.
MCMC kullanarak ve tahmin etmeye çalışıyorum , ancak teklif değerlerini örneklemek için etkili bir yol bulmakta zorlanıyorum. Şimdiye kadar Metropolis-Hastings'i kullandım ve ve eşit dağılımlardan çekildim ve biyolojik anlamda mantıklı olan yaklaşık 200-400 metrelik posterior ortalama dağılım mesafeleri elde ediyorum. Ancak, yakınsama gerçekten yavaş ve tam parametre alanı keşfetmek ikna değilim.
ve için daha iyi bir teklif dağıtımı yapmak zor , çünkü kendi başlarına fazla bir anlamı olmadan birbirlerine bağımlılar. Ortalama dağılım mesafesi net bir biyolojik anlama sahiptir, ancak belirli bir ortalama dağılım mesafesi, ve sonsuz sayıda kombinasyonu ile açıklanabilir . Bu şekilde ve posteriorda korelasyon gösterir.
Şimdiye kadar Metropolis Hastings'i kullandım, ancak burada çalışacak başka herhangi bir algoritmaya açıkım.
Soru: Herkes ve için teklif değerleri çizmenin daha verimli bir yolunu önerebilir mi?
Edit: Sistem hakkında ek bilgi: Ben bir vadi boyunca bitki popülasyonu çalışıyorum. Amaç, verici bitkiler ile tozlaştıkları bitkiler arasındaki polen ile kat edilen mesafelerin dağılımını belirlemektir. Sahip olduğum veriler:
- Her olası polen vericisi için yer ve DNA
- Yetiştirilen ve genotiplenen 60 ana bitkinin (yani polen alıcılarının) bir örneğinden toplanan tohumlar.
- Her anne bitkisinin yeri ve DNA'sı.
Donör bitkilerinin kimliğini bilmiyorum, ama bu hangi fidelerin babaları olduğunu belirleyerek genetik verilerden çıkarılabilir. Diyelim ki bu bilgi, her yavru için bir sıra ve her aday donör için bir sütun içeren G olasılıklar matrisinde bulunur , bu da her adayın sadece genetik verilere dayanarak her bir yavruya baba olma olasılığını verir. G'nin hesaplanması yaklaşık 3 saniye sürer ve her yinelemede yeniden hesaplanması gerekir, bu da işleri önemli ölçüde yavaşlatır.
Genel olarak daha yakın aday bağışçıların baba olma olasılığının daha yüksek olmasını beklediğimizden, eğer babalık ve dağılma ortaklaşa çıkarırsanız babalık çıkarımı daha doğru olur. Matris D , G ile aynı boyutlara sahiptir ve sadece anne ve aday arasındaki mesafelerin bir fonksiyonuna ve bazı parametre vektörlerine dayanan babalık olasılıklarını içerir. D ve G'de elemanların çoğaltılması, genetik ve uzamsal verilerle birlikte babalık olasılığını verir. Çarpılan değerlerin çarpımı, dağılma modelini verir.
burada GND'den dağılma mesafesi olasılığıdır, N aday sayısıdır ve ( ) GND'nin dağılmaya ne kadar katkısı olduğunu belirler.
Bu nedenle hesaplama yükünü artıran iki ek husus vardır:
- Dağılma mesafesi bilinmemektedir, ancak her yinelemede çıkarılması gerekir ve bunu yapmak için G oluşturmak pahalıdır.
- Üzerine entegre edilecek üçüncü bir parametre ( .
Bu nedenlerden dolayı ızgara enterpolasyonu yapmak için çok fazla karmaşık görünmeme rağmen, aksi halde ikna olduğum için mutluyum.
Misal
İşte kullandığım python kodunun basitleştirilmiş bir örneği. Genetik verilerden babalık tahminini basitleştirdim, çünkü bu çok fazla kod içeriyor ve 0 ile 1 arasında bir değer matrisi ile değiştiriyordu.
İlk olarak, GND'yi hesaplamak için fonksiyonları tanımlayın:
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
Sonra 2000 adayı ve 800 çocuğu simüle edin. Ayrıca, yavruların anneleri ile aday babalar arasındaki mesafelerin bir listesini ve bir kukla G matrisini simüle edin .
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]
Başlangıç parametre değerlerini ayarlayın:
# 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
Sırayla a, b ve c'yi güncelleyin ve Metropolis oranını hesaplayın.
# 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