Extension to Multi-trait Models
Contents
18. Extension to Multi-trait Models#
18.1. Full-conditional posteriors for \(\mathbf{G}_0\) and \(\mathbf{R}_0\)#
Suppose the covariance matrix of \(\mbf{u}\) can be written as:
where \(\mbf{G}_0\) and \(\mbf{A}\) are positive definite matricies, and \(g_{0ij}\) denotes the element from row \(i\) and column \(j\) of \(\mbf{G}_0\).
Then, the mutivariate normal prior for \(\mbf{u}\) is:
where the \(\mbf{S} = \{s_{ij} = \mbf{u}_i'\mbf{A}^{-1}\mbf{u}_j\}\). In this prior, the matrix \(\mbf{A}\) is assumed to be known, and the matrix \(\mbf{G}_0\) may be considered unknown with a scaled inverted Wishart prior:
where \(\nu_u\) and \(\mbf{V}_u\) are the degrees of freedom and scale matrix of this prior. The scale matrix \(\mbf{V}_u\) in this prior is the inverse of the scale matrix in Sorensen and Gianola (2002). The parameterization presented here is that used in the Julia Distributions package. Combining this prior with (1) gives full-conditional posterior for \(\mbf{G}_0\):
which can be recognized as an inverted Wishart distribution with \(\tilde{\nu}_u = (\nu_u+k)\) degrees of freemom and scale matrix \(\tilde{\mbf{V}}_u = (\mbf{V}_u + \mbf{S})\).
Similarly, it can be shown that the full-conditional posterior for \(\mbf{R}_0\) is a scaled inverted Wishart distribution with \(\tilde{\nu}_e = (\nu_e + n)\) degrees of freedom and scale matrix \(\tilde{\mbf{V}}_e = (\mbf{V}_e + \mbf{S}_e)\), when the residual covariance matrix has the form:
where \(\mbf{R}_0\) is an \(m \times m\) positive definite matrix, \(\mbf{I}\) is an \(n\times n\) identity matrix, \(\mbf{S}_e = \{\mbf{e}_i'\mbf{e}_j \}\), and \(\nu_e\) and \(\mbf{V}_e\) are the hyperparameters of the scaled inverted Wishart prior for \(\mbf{R}_0\).
Consider the mixed linear model
where \(\boldsymbol{\beta}\) is a vector of fixed effects, \(\mathbf{X}\) is an observed matrix that relates \(\boldsymbol{\beta}\) to \(\mathbf{y}\), \(\mathbf{u}\) is a vector of multivariate normal random effects with null means, and it is assumed that its covariance matrix can be written as
where \(\mbf{G}_0\) and \(\mbf{A}\) are positive definite matricies, and \(g_{0ij}\) denotes the element from row \(i\) and column \(j\) of \(\mbf{G}_0\). The matrix \(\mbf{A}\) is assumed to be known, and the matrix \(\mbf{G}_0\) may be considered unknown with a scaled inverted Wishart prior:
where \(\nu_u\) and \(\mbf{V}_u\) are the degrees of freedom and scale matrix of this prior. The scale matrix \(\mbf{V}_u\) in this prior is the inverse of the scale matrix in Sorensen and Gianola (2002). The parameterization presented here is that used in the Julia Distributions package.
18.2. Full-conditional Posteriors for Location Parameters#
If we denote the location parameters (\(\boldsymbol{\beta}, \mbf{u}\)) of the model by \(\boldsymbol{\theta}\), as we have seen before, the posteior distribution of \(\boldsymbol{\theta}\) is multivariate normal with mean given by the solution to
and the variance is \(\mbf{C}^{-1}\sigma^2_e\), where \(\mbf{C}\) and \(\mbf{r}\) are the coefficient matrix and right-hand-side of the MME. So, the quadratic in the exponent of this normal distribution is:
In order to use the single-site Gibbs sampler to construct a Markov chain for \(\bs{\theta}\), we need to derive the full-conditional posterior distribution for \((\theta_i|\text{ELSE})\), where \(\text{ELSE}\) stands for all other variables in the model other than \(\theta_i\). To simplify this derivation, \(\bs{\theta}\) is partitioned as:
where \(\bs{\theta}_1 = \theta_i\) and \(\bs{\theta}_2\) contains the remaining elements of \(\bs{\theta}\). Now, the quadratic (2) can be written as:
where the coefficient matrix \(\mbf{C}\) has also been partitioned to correspond to the partitioning of \(\bs{\theta}\).
To derive the distribution of \((\bs{\theta}_1|\bs{\theta}_2)\), we need to only consider the terms in (3) that involve \(\bs{\theta}_1\). These terms are (after dropping \(\frac{-1}{2\sigma^2_e}\)):
where for (4) to equal (5), \(\tilde{\bs{\theta}}_1\) must satisfy the equality:
This equlity must hold for all \(\bs{\theta}_1\), and so
because the right-hand-side of the MME corresponding to \(\hat{\bs{\theta}}_1\) is equal to
Thus, \((\bs{\theta}_1|\bs{\theta}_2) \sim \text{N}(\tilde{\bs{\theta}},\mbf{C}_{11}^{-1}\sigma^2_e)\). An alternative derivation is given in Sorensen and Gianola (2002).
18.3. Gibbs Sampler for Location Parameters#
function Gibbs!(A,x,b,varRes::Float64,nIter::Int64;outFreq=100)
n = size(x,1)
xMean = zeros(n)
for iter = 1:nIter
if iter%outFreq==0
println("at sample: ",iter)
end
for i=1:n
cVarInv = 1.0/A[i,i]
cMean = cVarInv*(b[i] - A[:,i]'x) + x[i]
x[i] = randn()*sqrt(cVarInv) + cMean
end
xMean += (x - xMean)/iter
end
return xMean
end
Gibbs! (generic function with 1 method)
using NBInclude
@nbinclude("../MME/3.7.3.BuildMME.ipynb"; regex=r"#\s*EXECUTE")
updateLhsRhs! (generic function with 1 method)
18.4. Structures for Building MME#
#EXECUTE
using DataFrames, SparseArrays, LinearAlgebra, Random, JWAS, CSV
using Printf
mutable struct ModelTerm
trmString::AbstractString
iModel::Int64 # the model (trait) this term belongs to
startPos::Int64
endPos::Int64
randomType::String
end
mutable struct RandomEffect
modelTermVec::Array{ModelTerm,1}
νpr::Float64
Spr::Array{Float64,2}
Vi::Array{Float64,2}
meanV::Array{Float64,2}
Ai
estimate::Bool
outSamples::Bool
outFreq::Int64
outStream
end
mutable struct MME
modelEquations::Array{AbstractString,1} #"[y1 = A + B + A*B ;y2 = A + B"]
covVec::Array{String} #["age"]
modelTermVec::Array{ModelTerm,1} #[modelTerm("A") , modelTerm("A*B")]
modelTermDict::Dict{AbstractString,ModelTerm}
randomEffectsVec::Array{RandomEffect,1} #[RandomEffect("Ind"), RandomEffect("Mat")]
ped # false or a pedigee structure defined in JWAS.PedModule
depVarVec::Array{AbstractString,1} #["y1","y2"]
X::SparseMatrixCSC{Float64,Int64} #design matrix
mmeLhs::SparseMatrixCSC{Float64,Int64} #left-hand side for MME
mmeRhs::Array{Float64,1} #right-hand side for MME
mmeSpl::Array{Float64,1} #sample of location effects
varRes::Array{Float64,2} #residual variance
νRes::Float64 #prior degrees of freedom for varRes
SRes::Array{Float64,2} #prior scale parameter for resVar
y::Array{Float64,1} #matrix of values for dependent variable
meanVarRes::Array{Float64,2}
end
function ModelTerm(str::AbstractString,iModel)
ModelTerm(str,iModel,0,0,"fixed")
end
ModelTerm
18.5. Functions for Building MME#
#EXECUTE
function initMME(modelEquations::AbstractString,varRes;νRes=5.0) # "y1 = A + A*B; y2 = A + B"
if modelEquations==""
error("modelEquations is empty\n")
end
modelVec = [strip(i) for i in split(modelEquations,[';','\n'],keepempty=false)]
nModels = size(modelVec,1)
depVarVec = Array{AbstractString,1}()
modelTermVec = Array{ModelTerm,1}() # modelTerms across all the models
modelTermDict = Dict{AbstractString,ModelTerm}()
for (m,model) = enumerate(modelVec)
leftRight = split(model,"=") # "y", "A+A*B"
depVarVec = [depVarVec; strip(leftRight[1])] # ["y1","y2"]
modelParts = strip(leftRight[2]) # "A+A*B"
termsVec = split(modelParts,"+") # "A","A*B"
modelTermVeci = [ModelTerm(string(m)*":"*strip(trmStr),m) for trmStr in termsVec]
modelTermVec = [modelTermVec;modelTermVeci]
end
for i in modelTermVec
modelTermDict[i.trmString] = i
end
randomEffectsVec = []
ped = false
covVec = []
X = spzeros(0,0)
mmeLhs = spzeros(0,0)
mmeRhs = []
mmeSol = []
y = Array{Float64,1}(undef,0)
m = size(varRes,1)
varRes = m==1 ? fill(varRes,1,1) : varRes
SRes = varRes*(νRes - m - 1)
meanVarRes = zero(varRes)
return MME(modelVec,covVec,modelTermVec,modelTermDict,randomEffectsVec,ped,
depVarVec,X,mmeLhs,mmeRhs,mmeSol,varRes,νRes,SRes,y,meanVarRes)
end
initMME (generic function with 1 method)
varRes = 1.0
mme = initMME("y = sex + breed + age",varRes)
mme.covVec = ["age"];
mme.modelTermVec[1].trmString
"1:sex"
mme.modelTermVec[1].trmString[3:end]
"sex"
#EXECUTE
# This function returns returns a dictionary with the names in the pedigree as the keys and their
# sequential numbers as the associated values
# It also returns vector with the keys in sequential order.
function mkDict(ped::JWAS.PedModule.Pedigree)
d = Dict()
names = Array{String}(undef,length(ped.idMap))
for i in ped.idMap
d[i.first] = i.second.seqID
names[i.second.seqID] = i.first
end
return d,names
end
# This function returns
# a dictionary with the unique values in the vector "a" as the keys and their
# sequential numbers as the associated values
# It also returns vector with the keys in sequential order.
function mkDict(a)
d = Dict()
aUnique = unique(a)
names = Array{String}(undef,size(aUnique,1))
for (i,s) in enumerate(aUnique)
names[i] = s
d[s] = i
end
return d,names
end
function getX(mme,modelTerm::ModelTerm,covariables,df)
n = size(df,1)
nModels = size(mme.modelEquations,1)
trmString = split(modelTerm.trmString,':')[2]
if trmString == "intercept"
ii = (modelTerm.iModel-1)*n .+ (1:n) # row numbers
jj = ones(n)
val = 1.0
p = 1
X = sparse(ii,jj,val,n*nModels,p)
colNames = modelTerm.trmString
return X,colNames
end
factors = strip.(split(trmString,"*"))
covs = [i in covariables for i in factors]
if covs[1] == false
str = string.(df[:,Symbol(factors[1])])
val = 1.0
else
str = fill(factors[1],n)
val = df[:,Symbol(factors[1])]
end
for i in 2:length(factors)
if covs[i] == false
str = str .*" x ".*string.(df[:,Symbol(factors[i])])
val = val .* 1.0
else
str = str .*" x ".*fill(factors[i],n)
val = val .* df[:,Symbol(factors[i])]
end
end
dict,colNames = modelTerm.randomType != "A" ? mkDict(str) : mkDict(mme.ped)
str = modelTerm.randomType != "A" ? str : string.(df[:,Symbol(factors[1])])
ii = (modelTerm.iModel-1)*n .+ (1:n) # row numbers
jj = [dict[i] for i in str] # column numbers
p = length(colNames)
X = sparse(ii,jj,val,n*nModels,p)
return X, strip(modelTerm.trmString)*": ".*colNames
end
function setRandom!(mme::MME,trmStrings::String,V,ped=false;
estimate::Bool=false,
νPrior::Float64=4.1,
outSamples::Bool=false,
outFreq::Int64=100
)
m = size(V,1)
if outSamples==true
fileName = "V($trmStrings).samples"
outStream = open(fileName,"w")
for i=1:m,j=i:m
if i==j==1
@printf(outStream,"%6s", "V[$i,$j]")
else
@printf(outStream," %6s", "V[$i,$j]")
end
end
@printf(outStream,"\n")
else
outStream = nothing
end
var = m==1 ? fill(V,1,1) : V
trmVec = strip.(split(trmStrings,[',';' '],keepempty=false))
modelTerms = []
[begin
trmString = split(modelTerm.trmString,':')[2]
if trmString in trmVec
push!(modelTerms,modelTerm)
end
end
for modelTerm in mme.modelTermVec
]
if length(modelTerms) != size(var,1)
println("size of var: $(size(var,1)) does not match the number of random effects: $(length(modelTerms))")
return
end
if ped==false
[trm.randomType = "I" for trm in modelTerms]
Ai = I
else
[trm.randomType = "A" for trm in modelTerms]
mme.ped = pedigree
Ai = JWAS.PedModule.AInverse(pedigree)
end
Spr = (νPrior - m - 1)*var
randomEffect = RandomEffect(modelTerms,νPrior,Spr,inv(var),zero(var),Ai,
estimate,outSamples,outFreq,outStream)
push!(mme.randomEffectsVec,randomEffect)
end
function addGiMats!(mme::MME)
for randomEffect in mme.randomEffectsVec
for (i,modelTermi) in enumerate(randomEffect.modelTermVec), (j,modelTermj) in enumerate(randomEffect.modelTermVec)
starti = modelTermi.startPos
startj = modelTermj.startPos
endi = modelTermi.endPos
endj = modelTermj.endPos
mme.mmeLhs[starti:endi,startj:endj] = mme.mmeLhs[starti:endi,startj:endj] + randomEffect.Ai*randomEffect.Vi[i,j]
end
end
end
addGiMats! (generic function with 1 method)
#EXECUTE
function getLhsRhs!(mme,df)
n = size(df,1)
X,colNames = getX(mme,mme.modelTermVec[1],mme.covVec,df)
mme.modelTermVec[1].startPos = 1
mme.modelTermVec[1].endPos = mme.modelTermVec[1].startPos + size(X,2) - 1
for i = 2:size(mme.modelTermVec,1)
Xi,namesi = getX(mme,mme.modelTermVec[i],mme.covVec,df)
X = [X Xi]
mme.modelTermVec[i].startPos = mme.modelTermVec[i-1].endPos + 1
mme.modelTermVec[i].endPos = mme.modelTermVec[i].startPos + size(Xi,2) - 1
colNames = [colNames; namesi]
end
y = Array{Float64,1}()
for v in mme.depVarVec
y = [y;df[:,Symbol(v)]]
end
Ri = kron(inv(mme.varRes),sparse(I, n, n))
mme.X = X
mme.mmeLhs = X'Ri*X
mme.mmeRhs = X'Ri*y
mme.mmeSpl = zero(mme.mmeRhs)
mme.y = y
addGiMats!(mme)
return mme.mmeLhs,mme.mmeRhs,colNames
end
function updateLhs!(mme)
m = size(mme.varRes,1)
n = Int(size(mme.y,1)/m)
Ri = kron(inv(mme.varRes),sparse(I, n, n))
mme.mmeLhs = mme.X'Ri*mme.X
mme.mmeRhs = mme.X'Ri*mme.y
addGiMats!(mme)
end
updateLhs! (generic function with 1 method)
Random.seed!(31415)
animal= ["animal1","animal2","animal3","animal4","animal5","animal6"]
sex = ["m","f","f","m","f","f"]
breed = ["Angus","Angus","Hereford","Hereford","Angus","Angus"]
age = [40,36,38,42,40,36]
df = DataFrame(animal=animal,sex=sex,breed=breed,age=age,y=round.(randn(6),digits=3))
| animal | sex | breed | age | y | |
|---|---|---|---|---|---|
| String | String | String | Int64 | Float64 | |
| 1 | animal1 | m | Angus | 40 | -0.859 |
| 2 | animal2 | f | Angus | 36 | 0.631 |
| 3 | animal3 | f | Hereford | 38 | 1.775 |
| 4 | animal4 | m | Hereford | 42 | -0.17 |
| 5 | animal5 | f | Angus | 40 | -0.561 |
| 6 | animal6 | f | Angus | 36 | 0.214 |
mme = initMME("y = intercept + sex + breed + age",varRes)
mme.covVec = ["age"];
lhs,rhs,names = getLhsRhs!(mme,df)
[names Matrix(lhs) rhs]
6×8 Array{Any,2}:
"1:intercept" 6.0 2.0 4.0 4.0 2.0 232.0 1.03
"1:sex: m" 2.0 2.0 0.0 1.0 1.0 82.0 -1.029
"1:sex: f" 4.0 0.0 4.0 3.0 1.0 150.0 2.059
"1:breed: Angus" 4.0 1.0 3.0 4.0 0.0 152.0 -0.575
"1:breed: Hereford" 2.0 1.0 1.0 0.0 2.0 80.0 1.605
"1:age: age" 232.0 82.0 150.0 152.0 80.0 9000.0 33.93
mme.modelTermVec
4-element Array{ModelTerm,1}:
ModelTerm("1:intercept", 1, 1, 1, "fixed")
ModelTerm("1:sex", 1, 2, 3, "fixed")
ModelTerm("1:breed", 1, 4, 5, "fixed")
ModelTerm("1:age", 1, 6, 6, "fixed")
pedigree = get_pedigree("pedFile",separator=",",header=false);
The delimiter in pedFile is ','.
coding pedigree... 100%|████████████████████████████████| Time: 0:00:00
Finished!
data = CSV.read("data.phen")
| Ind | Mat | y1 | y2 | x | |
|---|---|---|---|---|---|
| Int64 | Int64 | Float64 | Float64 | Float64 | |
| 1 | 3 | 2 | 8.9 | 9.2 | 11.9 |
| 2 | 4 | 2 | 9.7 | 5.7 | 10.8 |
| 3 | 5 | 4 | 8.8 | 8.5 | 11.7 |
varRes = 1.0
mme = initMME("y1 = intercept + Ind",varRes);
setRandom!(mme,"Ind",1.0,pedigree);
#setRandom!(mme,"Ind",1.0);
lhs,rhs,names = getLhsRhs!(mme,data)
[names Matrix(lhs) rhs]
6×8 Array{Any,2}:
"1:intercept" 3.0 0.0 0.0 1.0 1.0 1.0 27.4
"1:Ind: 1" 0.0 2.0 1.0 -1.0 -1.0 0.0 0.0
"1:Ind: 2" 0.0 1.0 2.0 -1.0 -1.0 0.0 0.0
"1:Ind: 4" 1.0 -1.0 -1.0 3.5 0.5 -1.0 9.7
"1:Ind: 3" 1.0 -1.0 -1.0 0.5 3.5 -1.0 8.9
"1:Ind: 5" 1.0 0.0 0.0 -1.0 -1.0 3.0 8.8
Matrix(mme.randomEffectsVec[1].Ai)
5×5 Array{Float64,2}:
2.0 1.0 -1.0 -1.0 0.0
1.0 2.0 -1.0 -1.0 0.0
-1.0 -1.0 2.5 0.5 -1.0
-1.0 -1.0 0.5 2.5 -1.0
0.0 0.0 -1.0 -1.0 2.0
size(mme.mmeLhs)
(6, 6)
Matrix(mme.X'mme.X)
6×6 Array{Float64,2}:
3.0 0.0 0.0 1.0 1.0 1.0
0.0 0.0 0.0 0.0 0.0 0.0
0.0 0.0 0.0 0.0 0.0 0.0
1.0 0.0 0.0 1.0 0.0 0.0
1.0 0.0 0.0 0.0 1.0 0.0
1.0 0.0 0.0 0.0 0.0 1.0
mme.modelTermVec
2-element Array{ModelTerm,1}:
ModelTerm("intercept", 1, 1, "fixed")
ModelTerm("Ind", 2, 6, "A")
varRes = 1.0
mme = initMME("y1 = intercept + Ind + Mat",varRes);
setRandom!(mme,"Ind",1.0,pedigree)
setRandom!(mme,"Mat",1.0,pedigree);
lhs,rhs,names = getLhsRhs!(mme,data)
[names Matrix(lhs)]
11×12 Array{Any,2}:
"intercept" 3.0 0.0 0.0 1.0 1.0 1.0 0.0 2.0 1.0 0.0 0.0
"Ind: 1" 0.0 2.0 1.0 -1.0 -1.0 0.0 0.0 0.0 0.0 0.0 0.0
"Ind: 2" 0.0 1.0 2.0 -1.0 -1.0 0.0 0.0 0.0 0.0 0.0 0.0
"Ind: 4" 1.0 -1.0 -1.0 3.5 0.5 -1.0 0.0 1.0 0.0 0.0 0.0
"Ind: 3" 1.0 -1.0 -1.0 0.5 3.5 -1.0 0.0 1.0 0.0 0.0 0.0
"Ind: 5" 1.0 0.0 0.0 -1.0 -1.0 3.0 0.0 0.0 1.0 0.0 0.0
"Mat: 1" 0.0 0.0 0.0 0.0 0.0 0.0 2.0 1.0 -1.0 -1.0 0.0
"Mat: 2" 2.0 0.0 0.0 1.0 1.0 0.0 1.0 4.0 -1.0 -1.0 0.0
"Mat: 4" 1.0 0.0 0.0 0.0 0.0 1.0 -1.0 -1.0 3.5 0.5 -1.0
"Mat: 3" 0.0 0.0 0.0 0.0 0.0 0.0 -1.0 -1.0 0.5 2.5 -1.0
"Mat: 5" 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -1.0 -1.0 2.0
Matrix(mme.X'mme.X)
11×11 Array{Float64,2}:
3.0 0.0 0.0 1.0 1.0 1.0 0.0 2.0 1.0 0.0 0.0
0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
1.0 0.0 0.0 1.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0
1.0 0.0 0.0 0.0 1.0 0.0 0.0 1.0 0.0 0.0 0.0
1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 1.0 0.0 0.0
0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
2.0 0.0 0.0 1.0 1.0 0.0 0.0 2.0 0.0 0.0 0.0
1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 1.0 0.0 0.0
0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
V = [1 0.5
0.5 2.0]
2×2 Array{Float64,2}:
1.0 0.5
0.5 2.0
varRes = 1.0
mme = initMME("y1 = intercept + Ind + Mat",varRes);
setRandom!(mme,"Ind, Mat",1.0,pedigree);
size of var: 1 does not match the number of random effects: 2
varRes = 1.0
mme = initMME("y1 = intercept + Ind + Mat",varRes);
setRandom!(mme,"Ind, Mat",V,pedigree);
lhs,rhs,names = getLhsRhs!(mme,data)
Matrix(lhs)
11×11 Array{Float64,2}:
3.0 0.0 0.0 1.0 … 1.0 0.0 0.0
0.0 2.28571 1.14286 -1.14286 0.285714 0.285714 0.0
0.0 1.14286 2.28571 -1.14286 0.285714 0.285714 0.0
1.0 -1.14286 -1.14286 3.85714 -0.714286 -0.142857 0.285714
1.0 -1.14286 -1.14286 0.571429 -0.142857 -0.714286 0.285714
1.0 0.0 0.0 -1.14286 … 1.28571 0.285714 -0.571429
0.0 -0.571429 -0.285714 0.285714 -0.571429 -0.571429 0.0
2.0 -0.285714 -0.571429 1.28571 -0.571429 -0.571429 0.0
1.0 0.285714 0.285714 -0.714286 2.42857 0.285714 -0.571429
0.0 0.285714 0.285714 -0.142857 0.285714 1.42857 -0.571429
0.0 0.0 0.0 0.285714 … -0.571429 -0.571429 1.14286
varRes = 1.0
mme = initMME("y1 = intercept + Ind + Ind*x",varRes);
mme.covVec = ["x"]
setRandom!(mme,"Ind",1.0,pedigree);
size(mme.randomEffectsVec,1)
1
setRandom!(mme,"Ind*x",1.0,pedigree);
size(mme.randomEffectsVec,1)
2
lhs,rhs,names = getLhsRhs!(mme,data)
[names Matrix(lhs)]
11×12 Array{Any,2}:
"1:intercept" 3.0 0.0 0.0 1.0 … 0.0 0.0 10.8 11.9 11.7
"1:Ind: 1" 0.0 2.0 1.0 -1.0 0.0 0.0 0.0 0.0 0.0
"1:Ind: 2" 0.0 1.0 2.0 -1.0 0.0 0.0 0.0 0.0 0.0
"1:Ind: 4" 1.0 -1.0 -1.0 3.5 0.0 0.0 10.8 0.0 0.0
"1:Ind: 3" 1.0 -1.0 -1.0 0.5 0.0 0.0 0.0 11.9 0.0
"1:Ind: 5" 1.0 0.0 0.0 -1.0 … 0.0 0.0 0.0 0.0 11.7
"1:Ind*x: 1" 0.0 0.0 0.0 0.0 2.0 1.0 -1.0 -1.0 0.0
"1:Ind*x: 2" 0.0 0.0 0.0 0.0 1.0 2.0 -1.0 -1.0 0.0
"1:Ind*x: 4" 10.8 0.0 0.0 10.8 -1.0 -1.0 119.14 0.5 -1.0
"1:Ind*x: 3" 11.9 0.0 0.0 0.0 -1.0 -1.0 0.5 144.11 -1.0
"1:Ind*x: 5" 11.7 0.0 0.0 0.0 … 0.0 0.0 -1.0 -1.0 138.89
Matrix(mme.X'mme.X)
11×11 Array{Float64,2}:
3.0 0.0 0.0 1.0 1.0 1.0 0.0 0.0 10.8 11.9 11.7
0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
1.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 10.8 0.0 0.0
1.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 11.9 0.0
1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 11.7
0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
10.8 0.0 0.0 10.8 0.0 0.0 0.0 0.0 116.64 0.0 0.0
11.9 0.0 0.0 0.0 11.9 0.0 0.0 0.0 0.0 141.61 0.0
11.7 0.0 0.0 0.0 0.0 11.7 0.0 0.0 0.0 0.0 136.89
varRes = 1.0
mme = initMME("y1 = intercept + Ind + Ind*x",varRes);
mme.covVec = ["x"]
setRandom!(mme,"Ind, Ind*x",V,pedigree);
size(mme.randomEffectsVec,1)
1
lhs,rhs,names = getLhsRhs!(mme,data)
[names Matrix(lhs) rhs]
11×13 Array{Any,2}:
"1:intercept" 3.0 0.0 0.0 … 11.9 11.7 27.4
"1:Ind: 1" 0.0 2.28571 1.14286 0.285714 0.0 0.0
"1:Ind: 2" 0.0 1.14286 2.28571 0.285714 0.0 0.0
"1:Ind: 4" 1.0 -1.14286 -1.14286 -0.142857 0.285714 9.7
"1:Ind: 3" 1.0 -1.14286 -1.14286 11.1857 0.285714 8.9
"1:Ind: 5" 1.0 0.0 0.0 … 0.285714 11.1286 8.8
"1:Ind*x: 1" 0.0 -0.571429 -0.285714 -0.571429 0.0 0.0
"1:Ind*x: 2" 0.0 -0.285714 -0.571429 -0.571429 0.0 0.0
"1:Ind*x: 4" 10.8 0.285714 0.285714 0.285714 -0.571429 104.76
"1:Ind*x: 3" 11.9 0.285714 0.285714 143.039 -0.571429 105.91
"1:Ind*x: 5" 11.7 0.0 0.0 … -0.571429 138.033 102.96
Matrix(mme.X)
3×11 Array{Float64,2}:
1.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 11.9 0.0
1.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 10.8 0.0 0.0
1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 11.7
Matrix(mme.X'mme.X)
11×11 Array{Float64,2}:
3.0 0.0 0.0 1.0 1.0 1.0 0.0 0.0 10.8 11.9 11.7
0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
1.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 10.8 0.0 0.0
1.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 11.9 0.0
1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 11.7
0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
10.8 0.0 0.0 10.8 0.0 0.0 0.0 0.0 116.64 0.0 0.0
11.9 0.0 0.0 0.0 11.9 0.0 0.0 0.0 0.0 141.61 0.0
11.7 0.0 0.0 0.0 0.0 11.7 0.0 0.0 0.0 0.0 136.89
varRes = 1.0
mme = initMME("y1 = intercept + Ind + Ind*x",varRes);
mme.covVec = ["x"]
setRandom!(mme,"Ind",1.0,pedigree)
setRandom!(mme,"Ind*x",1.0);
lhs,rhs,names = getLhsRhs!(mme,data)
[names Matrix(lhs) rhs]
9×11 Array{Any,2}:
"1:intercept" 3.0 0.0 0.0 1.0 … 11.9 10.8 11.7 27.4
"1:Ind: 1" 0.0 2.0 1.0 -1.0 0.0 0.0 0.0 0.0
"1:Ind: 2" 0.0 1.0 2.0 -1.0 0.0 0.0 0.0 0.0
"1:Ind: 4" 1.0 -1.0 -1.0 3.5 0.0 10.8 0.0 9.7
"1:Ind: 3" 1.0 -1.0 -1.0 0.5 11.9 0.0 0.0 8.9
"1:Ind: 5" 1.0 0.0 0.0 -1.0 … 0.0 0.0 11.7 8.8
"1:Ind*x: 3 x x" 11.9 0.0 0.0 0.0 142.61 0.0 0.0 105.91
"1:Ind*x: 4 x x" 10.8 0.0 0.0 10.8 0.0 117.64 0.0 104.76
"1:Ind*x: 5 x x" 11.7 0.0 0.0 0.0 0.0 0.0 137.89 102.96
varRes =[1 0.5
0.5 2.0]
V = [1.0 0.0 0.0
0.0 2.0 0.0
0.0 0.0 3.0]
mme = initMME("y1 = intercept + Ind + Ind*x;
y2 = intercept + Ind",varRes);
mme.covVec = ["x"]
#setRandom!(mme,"Ind Ind*x",V,pedigree);
lhs,rhs,names = getLhsRhs!(mme,data)
[names Matrix(lhs)]
11×12 Array{Any,2}:
"1:intercept" 3.42857 1.14286 … -0.285714 -0.285714 -0.285714
"1:Ind: 3" 1.14286 1.14286 -0.285714 0.0 0.0
"1:Ind: 4" 1.14286 0.0 0.0 -0.285714 0.0
"1:Ind: 5" 1.14286 0.0 0.0 0.0 -0.285714
"1:Ind*x: 3 x x" 13.6 13.6 -3.4 0.0 0.0
"1:Ind*x: 4 x x" 12.3429 0.0 … 0.0 -3.08571 0.0
"1:Ind*x: 5 x x" 13.3714 0.0 0.0 0.0 -3.34286
"2:intercept" -0.857143 -0.285714 0.571429 0.571429 0.571429
"2:Ind: 3" -0.285714 -0.285714 0.571429 0.0 0.0
"2:Ind: 4" -0.285714 0.0 0.0 0.571429 0.0
"2:Ind: 5" -0.285714 0.0 … 0.0 0.0 0.571429
mme.randomEffectsVec[1].modelTermVec
3-element Array{ModelTerm,1}:
ModelTerm("1:Ind", 1, 2, 6, "A")
ModelTerm("1:Ind*x", 1, 7, 11, "A")
ModelTerm("2:Ind", 2, 13, 17, "A")
inv(V)
3×3 Array{Float64,2}:
1.0 0.0 0.0
0.0 0.5 0.0
0.0 0.0 0.333333
varRes =[1 0.5
0.5 2.0]
V = [1.0 0.0 0.0
0.0 2.0 0.0
0.0 0.0 3.0]
mme = initMME("y1 = intercept + Ind + Ind*x;
y2 = intercept + Ind",varRes);
mme.covVec = ["x"]
setRandom!(mme,"Ind Ind*x",V,pedigree);
lhs,rhs,names = getLhsRhs!(mme,data)
[names Matrix(lhs)]
17×18 Array{Any,2}:
"1:intercept" 3.42857 0.0 0.0 … -0.285714 -0.285714 -0.285714
"1:Ind: 1" 0.0 2.0 1.0 0.0 0.0 0.0
"1:Ind: 2" 0.0 1.0 2.0 0.0 0.0 0.0
"1:Ind: 4" 1.14286 -1.0 -1.0 -0.285714 0.0 0.0
"1:Ind: 3" 1.14286 -1.0 -1.0 0.0 -0.285714 0.0
"1:Ind: 5" 1.14286 0.0 0.0 … 0.0 0.0 -0.285714
"1:Ind*x: 1" 0.0 0.0 0.0 0.0 0.0 0.0
"1:Ind*x: 2" 0.0 0.0 0.0 0.0 0.0 0.0
"1:Ind*x: 4" 12.3429 0.0 0.0 -3.08571 0.0 0.0
"1:Ind*x: 3" 13.6 0.0 0.0 0.0 -3.4 0.0
"1:Ind*x: 5" 13.3714 0.0 0.0 … 0.0 0.0 -3.34286
"2:intercept" -0.857143 0.0 0.0 0.571429 0.571429 0.571429
"2:Ind: 1" 0.0 0.0 0.0 -0.333333 -0.333333 0.0
"2:Ind: 2" 0.0 0.0 0.0 -0.333333 -0.333333 0.0
"2:Ind: 4" -0.285714 0.0 0.0 1.40476 0.166667 -0.333333
"2:Ind: 3" -0.285714 0.0 0.0 … 0.166667 1.40476 -0.333333
"2:Ind: 5" -0.285714 0.0 0.0 -0.333333 -0.333333 1.2381
pedigree = get_pedigree("simData.ped",separator=",",header=false);
The delimiter in simData.ped is ','.
Pedigree information:
#individuals: 1248
#sires: 50
#dams: 198
#founders: 248
using Statistics
function sampleLoc!(mme)
A = mme.mmeLhs
b = mme.mmeRhs
x = mme.mmeSpl
n = size(x,1)
for i=1:n
cVarInv = 1.0/A[i,i]
cMean = cVarInv*(b[i] - A[:,i]'x) + x[i]
x[i] = randn()*sqrt(cVarInv) + cMean
end
end
sampleLoc! (generic function with 1 method)
18.6. Full-conditional Posteriors for Covariance Matrices in Multi-trait Models#
Full-conditional posteriors for covariance matrices in multi-trait models are given here
18.7. Gibbs Sampler for Covariance Matrices#
function sampleVar!(mme,iter=0)
for randomEffect in mme.randomEffectsVec
if randomEffect.estimate == false continue end
modelTerm1 = randomEffect.modelTermVec[1]
k = modelTerm1.endPos - modelTerm1.startPos
m = size(randomEffect.modelTermVec,1)
S = zeros(m,m)
for i=1:m
modelTermi = randomEffect.modelTermVec[i]
starti = modelTermi.startPos
endi = modelTermi.endPos
ui = mme.mmeSpl[starti:endi]
for j=i:m
modelTermj = randomEffect.modelTermVec[j]
startj = modelTermj.startPos
endj = modelTermj.endPos
uj = mme.mmeSpl[startj:endj]
S[i,j] = ui'randomEffect.Ai*uj
S[j,i] = S[i,j]
end
end
Vpo = randomEffect.Spr + S
νpo = randomEffect.νpr + k
V = rand(InverseWishart(νpo,Vpo))
randomEffect.Vi = inv(V)
if iter>0
randomEffect.meanV += (V - randomEffect.meanV)/iter
end
if randomEffect.outSamples==true && iter%randomEffect.outFreq==0
for i=1:m,j=i:m
if i==j==1
@printf(randomEffect.outStream,"%10.5e", V[i,j])
else
@printf(randomEffect.outStream," %10.5e", V[i,j])
end
end
@printf(randomEffect.outStream,"\n")
end
end
end
sampleVar! (generic function with 2 methods)
18.8. Gibbs Sampler for Residual Covariance Matrix#
function sampleVarRes!(mme,iter=0)
m = size(mme.varRes,1)
n = Int(size(mme.y,1)/m)
S = zeros(m,m)
e = mme.y - mme.X*mme.mmeSpl
for i=1:m
starti = (i - 1)*n + 1
endi = starti + n - 1
ei = e[starti:endi]
for j=i:m
startj = (j - 1)*n + 1
endj = startj + n - 1
ej = e[startj:endj]
S[i,j] = ei'ej
S[j,i] = S[i,j]
end
end
νpo = n + mme.νRes
Spo = S + mme.SRes
mme.varRes = rand(InverseWishart(νpo,Spo))
if iter>0
mme.meanVarRes += (mme.varRes - mme.meanVarRes)/iter
end
end
sampleVarRes! (generic function with 2 methods)
using Distributions
using Plots
using ProgressMeter
function runMCMC!(mme,nIter,burnIn)
@showprogress "MCMC sampling" for iter = 1:nIter
sampleLoc!(mme)
sampleVar!(mme,iter-burnIn)
sampleVarRes!(mme,iter-burnIn)
updateLhsRhs!(mme)
end
for randomEffect in mme.randomEffectsVec
if randomEffect.outStream != nothing close(randomEffect.outStream) end
end
end
runMCMC! (generic function with 1 method)
function runMean(x)
meanx = 0
[meanx += (v-meanx)/i for (i,v) in enumerate(x)]
end
runMean (generic function with 1 method)
18.9. Numerical Example#
dataTwoTrait = CSV.read("dataTwoTrait.phen",DataFrame)
first(dataTwoTrait,5)
| Ind | y1 | y2 | |
|---|---|---|---|
| Int64 | Float64 | Float64 | |
| 1 | 251 | 4.975 | 0.312 |
| 2 | 252 | 2.069 | -4.109 |
| 3 | 253 | 3.413 | -0.052 |
| 4 | 254 | 8.806 | -1.066 |
| 5 | 255 | 5.759 | -1.057 |
varGen = [10.0 2.0; 2.0 3.0]
varRes = [10.0 0.0; 0.0 3.0]
mme = initMME("y1 = intercept + Ind
y2 = intercept + Ind",varRes);
setRandom!(mme,"Ind",varGen,pedigree,estimate=true,outSamples=true);
lhs,rhs,names = getLhsRhs!(mme,dataTwoTrait);
nIter = 10_000
burnIn = 1_000
1000
mme.randomEffectsVec[1].modelTermVec
2-element Vector{ModelTerm}:
ModelTerm("1:Ind", 1, 2, 1249, "A")
ModelTerm("2:Ind", 2, 1251, 2498, "A")
runMCMC!(mme,nIter,burnIn)
MCMC sampling 100%|██████████████████████████████████████| Time: 0:00:15
mme.randomEffectsVec[1].meanV
2×2 Matrix{Float64}:
11.3768 2.11806
2.11806 2.9284
mme.meanVarRes
2×2 Matrix{Float64}:
9.19382 1.80055
1.80055 3.05443