ฉันกำลังสร้างแบบจำลองการกระจายพืชโดยใช้การแจกแจงปกติทั่วไป ( รายการวิกิพีเดีย ) ซึ่งมีฟังก์ชั่นความหนาแน่นของความน่าจะเป็น:
โดยที่คือระยะทางที่เดินทางคือพารามิเตอร์สเกลและคือพารามิเตอร์รูปร่าง ค่าเฉลี่ยระยะทางที่เดินทางได้รับจากค่าเบี่ยงเบนมาตรฐานของการแจกแจงนี้:
นี้จะสะดวกเพราะมันช่วยให้รูปร่างชี้แจงเมื่อ , รูปร่าง Gaussian เมื่อและสำหรับการกระจาย leptokurtic เมื่อ<1 การกระจายพืชนี้ขึ้นเป็นประจำในวรรณคดีกระจายพืชแม้ว่ามันจะค่อนข้างหายากโดยทั่วไปและจึงยากที่จะหาข้อมูลเกี่ยวกับ
พารามิเตอร์ที่น่าสนใจที่สุดคือและระยะห่างระหว่างการกระจาย
ฉันกำลังพยายามประเมินและโดยใช้ MCMC แต่ฉันพยายามที่จะหาวิธีที่มีประสิทธิภาพในการสุ่มตัวอย่างค่าข้อเสนอ จนถึงตอนนี้ฉันได้ใช้ Metropolis-Hastings และดึงออกมาจากการแจกแจงแบบสม่ำเสมอและและฉันได้รับระยะทางหลังเฉลี่ยประมาณ 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
จำลองผู้สมัคร 2,000 คนถัดไปและ 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 ตามลำดับและคำนวณอัตราส่วน Metropolis
# 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