Thanks for your kindly guidance. It is what I need.
And could I ask two additional questions?
-
Referencing Stan’s Manual chapter 20, I wrote model code in below. But when I kicked simulated data to the model, I got pretty far parameter. Do you have any advice?
-
Even if MAP estimation, but the model works slow. Maybe it attributes to inverse transformation, but is there speedup techniques?
Note: I formulated Jacobian adjustment for variable change as
p(\theta) = vonmises(t^{-1}_{1, \nu}(\theta)|\mu, \kappa)|\frac{d}{d\theta} t^{-1}_{1, \nu}(\theta)|
and
|\frac{d}{d\theta} t^{-1}_{1, \nu}(\theta)| = \frac{1}{\frac{dt_{1, \nu}(\theta)}{d\theta}} =\frac{1}{1+\nu\sin(\theta)}
so
\log(p(\theta)) = vonmises\_lpdf(t^{-1}_{1, \nu}(\theta)|\mu, \kappa) - \log(1+\nu\sin(\theta))
Stan
code
functions{
// system of inverse Batschelet transformation
vector invBatschelet(vector y_init, vector t, real[] x_r, int[] x_i){
// Get length of array
int I = x_i[1];
// value of interest
vector[I] y ;
// parameters (take it as fixed value would be understandable)
vector[I] theta = t[:I] ;
real nu = t[I+1] ;
// construct equation to be zero
y = -theta + y_init - nu * (1 + cos(y_init)) ;
return y ;
}
}
data {
int I ;
vector<lower=-pi(), upper=pi()>[I] RADIAN ;
}
transformed data {
real x_r[0] ;
int x_i[1] ;
vector<lower=-pi(), upper=pi()>[I] THETA_INIT ;
// set integer parameter to pass solver
x_i[1] = I ;
// set initial value of inverse transformed value
for (i in 1:I){
THETA_INIT[i] = 0 ;
}
}
parameters {
unit_vector[2] O ;
real<lower=0.0> kappa ;
real<lower=-1.0, upper=1.0> nu ;
}
transformed parameters{
real mu ;
vector<lower=-pi(), upper=pi()>[I] THETA ;
vector[I+1] t ;
mu = atan2(O[1], O[2]) ;
for (i in 1:I){
// transform angle by location parameter
t[i] = RADIAN[i] - mu ;
if (t[i] > pi()){
t[i] = t[i] - 2*pi() ;
}else if (t[i] <= -pi()){
t[i] = t[i] + 2*pi() ;
}
}
t[I+1] = nu ;
THETA = algebra_solver(invBatschelet, THETA_INIT, t, x_r, x_i) ;
}
model {
THETA ~ von_mises(mu, kappa) ;
// Jacobian adjustment by
target += -log(1 + nu*sin(RADIAN)) ;
}
Python
code
from pystan import StanModel
from scipy.stats import vonmises
import numpy as np
model_code = ... # Paste above code
model = StanModel(model_code=model)
# Generate simulation data
I = 1000
RADIAN = vonmises.rvs(size=I, loc=0, kappa=0.3)
stan_data = {
"I": I,
"RADIAN": RADIAN
}
# Kick into the model
fit = model.optimizing(stan_data)
fit
Result
# Ideally, mu=0, kappa=0.3, nu=0
OrderedDict([('O', array([0.86992951, 0.49317608])),
('kappa', array(1.15716819)),
('nu', array(1.)),
('mu', array(1.05505937)),
...