OK, here's why I think this isn't going to be so easy.
First, keep in mind that what's best practice for efficiency
isn't the same as what's best practice for clarity. Which
are we aiming for? How direct should the translations of the
BUGS models be?
I was originally suggesting
* a line-by-line very direct translation
* a conversion of that to one using the priors, etc. we like,
possibly rearranging data structures for efficiency, etc.
* an efficient version of the good model
* optionally an efficient version of the direct translation
The best practices on arrays vs. matrices are in the
manual chapter on arrays vs. matrices, so I suppose the
duplication of effort can begin by shoveling that chapter
into the best practices Wiki.
Then there's the advice to always use matrix functions
and shorter functions like elementwise functions if
you can to shorten the code.
But then given that this is just the transformed data
block, the vectorization and so forth aren't that important
since they only get executed once. There's a section in the
manual on execution that's important to read to understand when
to put things in transformed data, transformed parameters, and
generated quantities.
Best practice is to always declare things as transformed data or
generated quantities if possible, always delcare things as local
variables if possible. Lots of users inadvertently make everything
a transformed parameter or local variable in the model that should
be transformed data or a generated quantity. So this all needs
to go in the best practices.
Another best practice is to use capital letters for
constants and then matching lower-case letters for loops.
This won't match BUGS, so I'm not sure where that goes
in the best practices vs. translation of BUGS models.
And follow Gelman et al. in variable naming, so no capital
letters like Y.
Are mean_x and sd_x used elsewhere? If not,
best practicses would dictate they be local variables.
This is so that their memory doesn't linger past when
they're used. I see they are, but this should be mentioned
as a best practice if we're making a list.
We also need best practices for formatting. I'm tired of
reading crazily formatted user models --- there's an appendix
to the manual for that.
Now onto the show.
So I'd suggest this:
matrix[N,M] x;
transformed data {
matrix[N,M] z;
vector[M] mean_x;
vector[M] sd_x;
for (m in 1:M) {
mean_x[m] <- mean(col(x,m));
sd_x[m] <- mean(col(x,m));
}
for (n in 1:N)
z[n] <- (x[n] - mean_x) ./ sd_x;
}
But maybe that ./ is too complicated to read?
Or maybe people don't like z[n] referring to a row
of a matrix?
This isn't ideal for speed, since the col(x,m)
operations have to copy. So you can make a local
col_x_m <- col(x,m)
to reuse it. A critical piece of best practices is
to define expressions only once and reuse them --- it's very
important for efficiency, but can make things harder to read.
And then you want to rearrange and the z[n] assignments are
not memory local, so aren't efficient for large matrices. But
then there's a tradeoff with wanting to be able to define mu
with a matrix operation. Also, do we really need to define
mu and sigma as transformed parameters? It's overhead in writing
and in print and whatnot. If not, use this:
y ~ normal(beta0 + z * beta, sqrt(sigma_sq));
I like the "_" to separate words in names, but your mileage may
vary.
So many pieces of advice!
For the rest of that model, we don't ever really want to
be using step functions --- relational operators are much clearer, so
I'd rewrite
outlier_3 <- step(fabs((Y[3] - mu[3]) / sigma) - 2.5);
as
outlier_3 <- fabs(Y[3] - mu[3]) / sigma - 2.5 > 0
or better still
outlier_3 <- fabs(Y[3] - mu[3]) / sigma > 2.5
or even better for efficiency (multiplication is faster than
division),
outlier_3 <- fabs(Y[3] - mu[3]) > 2.5 * sigma;
Best practice is not to include parens around things where the
language knows how to parameterize. One might be tempted to
write ... > (2.5 * sigma).
Of course, rather than writing the same thing three times
with cut-and-paste, best practice would dictate writing
a function and actually declaring the booleans properly as
constrained integers. First the function.
int is_outlier(double y, double mu, double sigma) {
return fabs(y - mu) > 2.5 * sigma;
}
Then declare outlier_3, etc. as int<lower=0,upper=1>.
Best practice is to always have bounds for error checking and
self-documenting code.
Also for Andrew, random variables are not capitalized, so our
best practice notation is to use lower-case y.
Of course, Andrew doesn't like those priors, so then there's
the step of actually making the priors better and stating
best practices for those. There's a bunch of advice extracted
from Andrew in the regression chapter of the manual. But it's
quite involved and varies based on whether you're doing MCMC or
optimization.
Also, this
for (j in 1:p)
b[j] <- beta[j] / sd_x[j];
should be rewritten as:
b <- beta ./ sd_x;
But then you see why you want row vectors vs. vectors
so that you can do all the matrix algebra with minimal
transpositions. With mean_x being a row vector and b being
a vector, (mean_x * b) is a dot product. Or you can use dot_product(a,b),
which is more efficient than making mean_x a vector and using
mean_x' * b (tranpose makes a copy).
Is BUGS (best practice spelling!) really taking
beta ~ normal(0, 1e5)?
If so, we want full precision, so the exact translation
should be:
beta ~ normal(0, sqrt(1e5));
or to eliminate the sqrt operation without losing precision,
either define a transformed data variable or use this
beta ~ normal(0, 316.227766016838);
I prefer 1e5 to 100000, so I think scientific notation should
be a best practice if we're drilling down to that level.
- Bob
> ---clip---
>
> I think mean_x and sd_x should be same type. Which is better, and why row_vector and not vector? It's not affecting the performance, but it's just confusing now.
>
> Aki
>
> --
> You received this message because you are subscribed to the Google Groups "stan development mailing list" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to
stan-dev+u...@googlegroups.com.
> For more options, visit
https://groups.google.com/d/optout.