Loo: Adjust log-lik for non-linear transformation

I’m trying to compare two models in Stan using the loo package in R. Fitting the models is no problem. The only issue is making sure that I calculate the log-likelihood correctly in one of them. I would imagine that getting the log likelihood wrong would be an issue when comparing the models.

The baseline model is just a simple univariate normal distribution (call the original variable Y). The more sophisticated version to splits the model up into two parts, let’s call them X_1 and X_2. Both X_1 and X_2 are fit with univariate normal distributions, but the second part requires a non-linear transformation to get back to Y (e.g. Y=X_1-log(1+X_2/K), where the parentheses and K are above zero, also expressed in terms of X_2 we would have X_2=(exp(X_1-Y)-1)*K)

My question is: 1) do I need to make an adjustment to the log-likelihood to account for this non-linear transformation, and 2) if so, what type of adjustment would I need to use?

A more fleshed out example is below (though with a different naming convention, the temp variable in generated quantities is the , chg_ln_P lines up with Y, chg_ln_D lines up with X_1, and chg_r_e lines up with X_2).

Thanks.

data {
    int<lower=1> T;
    vector[T] chg_ln_P;
    vector[T] chg_ln_D;
    vector[T + 1] r_e;
    real<lower=0> r_f;
    real<lower=0> r_e_star;
    real<lower=0> g;
}
transformed data {
    vector[T] chg_r_e;
    for (i in 1:T) {
        chg_r_e[i] = r_e[i + 1] - r_e[i];
    }
}
parameters {
    real mu_chg_ln_D;
    real alpha_chg_r_e;
    real beta_chg_r_e;
    real<lower=0> sd_chg_ln_D;
    real<lower=0> sd_chg_r_e;
}
model {
    mu_chg_ln_D ~ normal(0, 0.1 /12);
    alpha_chg_r_e ~ normal(0, 0.1 /12);
    beta_chg_r_e ~ normal(0, 1);
    sd_chg_ln_D ~ cauchy(0, 0.01);
    sd_chg_r_e ~ cauchy(0, 0.01);

    chg_ln_D ~ normal(mu_chg_ln_D, sd_chg_ln_D);
    chg_r_e ~ normal(alpha_chg_r_e + beta_chg_r_e * (r_e[1:T] - r_e_star), sd_chg_r_e);
}
generated quantities {
    vector[T] log_lik;
    for (i in 1:T) {
        log_lik[i] = normal_lpdf(chg_ln_D[i] | mu_chg_ln_D, sd_chg_ln_D);
        log_lik[i] = log_lik[i] + normal_lpdf(chg_r_e[i] | alpha_chg_r_e + beta_chg_r_e * (r_e[i] - r_e_star), sd_chg_r_e);
    }
}

I figured out the transformation that makes it work. The adjusted generated quantities is below.

Basically I needed to figure out the mu and sigma that work with exp(X_1-Y)~normal(mu, sigma) and then add in the transformation for exp(X_1-Y). So instead of a log-normal, this is kind of an exponential-normal. I don’t recall seeing that before, but it works for my case.

generated quantities {
    vector[T] log_lik;
    {
        vector[T] mu_exp;
        vector[T] sd_exp;
        mu_exp = 1 + (alpha_chg_r_e + beta_chg_r_e * (r_e[1:T] - r_e_star)) ./ (r_f + r_e[1:T] - g);
        sd_exp = sd_chg_r_e ./ (r_f + r_e[1:T] - g);
        for (i in 1:T) {
            log_lik[i] = normal_lpdf(chg_ln_D[i] | mu_chg_ln_D, sd_chg_ln_D);
            log_lik[i] = log_lik[i] + normal_lpdf(exp(chg_ln_D[i] - chg_ln_P[i]) | mu_exp[i], sd_exp[i]);
            //new?
            log_lik[i] = log_lik[i] + log(exp(chg_ln_D[i] - chg_ln_P[i]));
        }
    }
}
1 Like

There is an example when Jacobian needs to be included in Regression and Other Stories: Mesquite, and the book chapter has a bit more info.

1 Like

Cool. Thanks.