Yo soy la modelización de la dispersión de la planta el uso generalizado de la distribución normal (entrada de la wikipedia), que tiene la función de densidad de probabilidad:
$$ \frac{b}{2a\Gamma(1/b)} e^{-(\frac{d}{a})^b} $$
where $d$ is distance travelled, $$ is a scale parameter, and $b$ is the shape parameter. Mean distance travelled is given by the standard deviation of this distribution:
$$ \sqrt{\frac{a^2 \Gamma(3/b)}{\Gamma(1/b)}} $$
This is convenient because it allows for an exponential shape when $b=1$, a Gaussian shape when $b=2$, and for a leptokurtic distribution when $b<1$. This distribution crops up regularly in the plant dispersal literature, even though it is pretty rare in general, and hence difficult to find information about.
The most interesting parameters are $b$ and mean dispersal distance.
I am trying to estimate $$ and $b$ using MCMC, but I am struggling to come up with an efficient way to sample proposal values. So far, I have used Metropolis-Hastings, and drawn from uniform distributions $0 < a < 400 $ and $ 0 < b<3$, and I get posterior mean dispersal distances of about 200-400 metres, which does make biological sense. However, convergence is really slow, and I am not convinced it is exploring the full parameter space.
Its tricky to come up with a better proposal distribution for $un$ and $b$, because they depend on one another, without having much meaning on their own. The mean dispersal distance does have a clear biological meaning, but a given mean dispersal distance could be explained by infinitely many combinations of $$ and $b$. As such $$ and $b$ are correlated in the posterior.
So far I have used Metropolis Hastings, but I am open to any other algorithm that would work here.
Question: Can anyone suggest a more efficient way to draw proposal values for $$ and $b$?
Edit: información Adicional sobre el sistema: estoy estudiando una población de plantas a lo largo de un valle. El objetivo es determinar la distribución de las distancias recorridas entre por el polen entre las plantas de los donantes y las plantas que polinizan. Los datos que tengo son:
- La ubicación y el ADN para cada posible donante de polen
- Semillas recolectadas a partir de una muestra de 60 materna plantas (es decir, el polen receptores) que han sido cultivados y genotipo.
- La ubicación y el ADN de cada materna de la planta.
No sé la identidad de las plantas donantes, pero esto puede ser inferido a partir de los datos genéticos mediante la determinación de que los donantes son los padres de cada plántula. Digamos que esta información está contenida en una matriz de probabilidades de G con una fila para cada una de las crías y una columna para cada uno de los candidatos de los donantes, que da la probabilidad de cada uno de los candidatos a ser el padre de cada uno de los descendientes basado en los datos genéticos sólo. G toma alrededor de 3 segundos para calcular, y debe ser recalculado en cada iteración, lo que ralentiza las cosas considerablemente.
Ya que generalmente se espera que cerca de candidatos a los donantes a ser más propensos a ser padres, paternidad inferencia es más precisa si usted conjuntamente inferir la paternidad y la dispersión. La matriz D tiene las mismas dimensiones como G, y contiene las probabilidades de paternidad basadas únicamente en función de las distancias entre la madre y el candidato y algunos vector de parámetros. La multiplicación de los elementos de D y G da la probabilidad conjunta de la paternidad dado genéticos y datos espaciales. El producto de la multiplicación de los valores da la probabilidad de dispersión de la modelo.
Como se describió anteriormente he estado usando el GND para el modelo de dispersión. De hecho, yo en realidad utiliza una mezcla de TIERRA y una distribución uniforme para permitir la posibilidad de que muy distante de los candidatos tener una mayor probabilidad de paternidad debido a la casualidad (la genética es desordenado, que iba a inflar la aparente cola de la MASA, si se ignora. Por lo que la probabilidad de la distancia de dispersión $d$ es:
$$ c \Pr(d|a,b) + \frac{(1-c)}{N}$$
where $\Pr(d|a,b)$ is the probability of dispersal distance from the GND, N is the number of candidates, and $c$ ($0< c <1$) determina la cantidad de la contribución de la MASA que hace a la dispersión.
Por consiguiente, existen dos consideraciones adicionales que aumentan la carga computacional:
- Distancia de dispersión no se conoce, pero se deben deducir en cada iteración, y la creación de G para hacer esto es caro.
- Hay un tercer parámetro, $c$, para integrar más.
Por estas razones es que a mí me parecía estar cada vez un poco demasiado complejo para realizar la cuadrícula de interpolación, pero estoy feliz de estar convencido de lo contrario.
Ejemplo
Aquí es un ejemplo simplificado de un código python que he utilizado. He simplificado de estimación de la paternidad de los datos genéticos, ya que esto implicaría una gran cantidad de código, y la reemplazó con una matriz de valores entre 0 y 1.
En primer lugar, definir funciones para calcular la MASA:
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
Siguiente simular 2000 candidatos, y 800 descendencia. También simular una lista de las distancias entre las madres de los hijos y el candidato de los padres, y un maniquí G de la matriz.
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]
Conjunto inicial de valores de parámetro:
# 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
Actualización a, b y c, y a su vez, y calcular la Metrópoli relació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