for rstan

7 views
Skip to first unread message

Andrew Gelman

unread,
Aug 10, 2012, 5:44:41 AM8/10/12
to stan...@googlegroups.com
J
In the schools example we can enter data as follows:

dat <- list(J = 8,
y = c(28, 8, -3, 7, -1, 1, 18, 12),
sigma_y = c(15, 10, 16, 11, 9, 11, 10, 18))

That's fine. But suppose we already had the data objects in R. So we already had R objects named J, y, and sigma_y. Then we could define the data as follows:

dat <- list (J=J, y=y, sigma_y=sigma_y).

But that is ugly. Instad I assume we could write a function that looks something like this:

dat <- collect ("J", "y", "sigma.y")

which would create the object without the need for the awkward "J=J" etc. synax.

Or maybe that function exists already? (I don't know if the name "collect" is a good one, I just made this up as a reminder that it's collecting a bunch of objects.)

Thx
A

Jiqiang Guo

unread,
Aug 10, 2012, 7:39:35 AM8/10/12
to stan...@googlegroups.com
Thanks. 
No, there is not a function like this.  I guess we could let data be a vector of strings (names), which could be easily differentiated from list.  In this case, I could just get the variables from the global environment.  So instead of having a function such as collect, how about we can just write 

dat <-  c("J", "y", "sigma.y") 

Jiqiang 

Andrew Gelman

unread,
Aug 10, 2012, 10:13:23 AM8/10/12
to stan...@googlegroups.com
That would be fine; whatever is most convenient.

Bob Carpenter

unread,
Aug 10, 2012, 12:30:10 PM8/10/12
to stan...@googlegroups.com
On 8/10/12 7:39 AM, Jiqiang Guo wrote:> Thanks.
> No, there is not a function like this. I guess we could let data be a vector of strings (names), which could be easily
> differentiated from list. In this case, I could just get the variables from the global environment. So instead of
> having a function such as collect, how about we can just write
>
> dat <- c("J", "y", "sigma.y")

I believe that's what R2WinBUGS does.

I strongly prefer the explicit coercion. I find
all the implicit coercion of things in R very confusing.
I originally found the notation

list(a = a, b = b)

confusing until I realized R lets you drop quotes in some
contexts, so this is the same as

list("a" = a, "b" = b)

I'd have expected something like the following

list("a" <- a, "b" <- b)

With an explicit names_to_list function we could also take
an optional environment variable or data frame (the latter
being the ggplot2 idiom).

- Bob

Andrew Gelman

unread,
Aug 10, 2012, 5:00:21 PM8/10/12
to stan...@googlegroups.com
Bob,
I have no problem with the explicit coercion . . . but do you mind the following?
The full version is to write
dat <- list (J=10, y=c(18,12,3, …. etc.
But we have an R function that will convert list("x","y","z") to list (x=x, y=y, z=z). Or even something intermediate, e.g., you give it list(J=10,"y") and it returns list (J=10, y=y).
It can all be in R, no need to be in Stan. But otherwise the whole list (a=a, b=b) etc. thing is a real pain in the ass and it also violates the "don't repeat code" principle.
A

Bob Carpenter

unread,
Aug 10, 2012, 6:03:16 PM8/10/12
to stan...@googlegroups.com


On 8/10/12 5:00 PM, Andrew Gelman wrote:
> Bob,
> I have no problem with the explicit coercion . . . but do you mind the following?
> The full version is to write
> dat <- list (J=10, y=c(18,12,3, �. etc.
> But we have an R function that will convert list("x","y","z") to list (x=x, y=y, z=z). Or even something intermediate, e.g., you give it list(J=10,"y") and it returns list (J=10, y=y).
> It can all be in R, no need to be in Stan. But otherwise the whole list (a=a, b=b) etc. thing is a real pain in the ass and it also violates the "don't repeat code" principle.

I prefer explicit commands where things get
converted to a single data type for a function
rather than doing with R2WinBUGS did and allowing
a range of different input types, such as a vector
of strings that are implicitly read from the enviromment
or an explicit list.

This improves modularity immensely because the function
to converts environments plus mixed lists/vectors or whatever
is documented and tested separately and not part of the maintenance/testing
responsibility of the stan() function. It's another function
that's independently testing. This helps immensely with
both testing and doc modularity.

I also know it's not the R way of doing things,
and I think being idiomatic in R trumps doing things
modularly. So it's really up to the R users' judgments
here.

- Bob

Andrew Gelman

unread,
Aug 10, 2012, 6:10:57 PM8/10/12
to stan...@googlegroups.com
I think that, given Bob's scruples, the best thing is for the bugs() function to reuqire the explicit list and for the R package to include an additional function with a name such as makelist. Thus, the usage could look like this:

dat <- list (J=10, y=c(18,12,-3))
stan (data=dat…)

or

stan (data=list (J=10, y=c(18,12,-3)))

Or, if J and y are already defined:

dat <- list (J=J, y=y)
stan (data=dat…)

or

dat <- makelist ("J", "y")
stan (data=dat…)

or

stan (data=makelist("J","y")…)

Does that make sense? This provides the clean code that I (as an R user) would like---I hate hate hate telling people to write code such as "list (y=y, x=x)", it really looks mysterious)--while keeping the stan() part clean as per Bob's preferences.

A

On Aug 11, 2012, at 12:03 AM, Bob Carpenter wrote:

>
>
> On 8/10/12 5:00 PM, Andrew Gelman wrote:
>> Bob,
>> I have no problem with the explicit coercion . . . but do you mind the following?
>> The full version is to write
>> dat <- list (J=10, y=c(18,12,3, …. etc.

Bob Carpenter

unread,
Aug 10, 2012, 6:15:18 PM8/10/12
to stan...@googlegroups.com


On 8/10/12 6:10 PM, Andrew Gelman wrote:
> I think that, given Bob's scruples, the best thing is for the bugs() function to reuqire the explicit list and for the R package to include an additional function with a name such as makelist. Thus, the usage could look like this:
>
> dat <- list (J=10, y=c(18,12,-3))
> stan (data=dat�)
>
> or
>
> stan (data=list (J=10, y=c(18,12,-3)))
>
> Or, if J and y are already defined:
>
> dat <- list (J=J, y=y)
> stan (data=dat�)
>
> or
>
> dat <- makelist ("J", "y")
> stan (data=dat�)
>
> or
>
> stan (data=makelist("J","y")�)
>
> Does that make sense? This provides the clean code that I (as an R user) would like---I hate hate hate telling people to write code such as "list (y=y, x=x)", it really looks mysterious)--while keeping the stan() part clean as per Bob's preferences.

This shouldn't be mysterious to an experienced R user,
but we'll probably get non-experts like me coming into
R just to use Stan (before BUGS, I only used R
occassionally for plotting or to calc a statistic).

I was confused because R auto-inserts quotes in
some contexts, like the name of variables in a list.
I wouldn't have been confused when I first saw it if
it had been:

data <- list("y"=y, "mu"=mu, "sigma"=sigma);

I'm sort of surprised list("y"<-y, ...) doesn't work.

- Bob


Andrew Gelman

unread,
Aug 10, 2012, 6:20:39 PM8/10/12
to stan...@googlegroups.com
I think inexpereinced R users will be fine because they can imitate the syntax of the schools example which is right there in the help file.

On Aug 11, 2012, at 12:15 AM, Bob Carpenter wrote:

>
>
> On 8/10/12 6:10 PM, Andrew Gelman wrote:
>> I think that, given Bob's scruples, the best thing is for the bugs() function to reuqire the explicit list and for the R package to include an additional function with a name such as makelist. Thus, the usage could look like this:
>>
>> dat <- list (J=10, y=c(18,12,-3))
>> stan (data=dat…)
>>
>> or
>>
>> stan (data=list (J=10, y=c(18,12,-3)))
>>
>> Or, if J and y are already defined:
>>
>> dat <- list (J=J, y=y)
>> stan (data=dat…)
>>
>> or
>>
>> dat <- makelist ("J", "y")
>> stan (data=dat…)
>>
>> or
>>
>> stan (data=makelist("J","y")…)

Ben Goodrich

unread,
Aug 10, 2012, 6:59:21 PM8/10/12
to stan...@googlegroups.com
On Friday, August 10, 2012 6:15:18 PM UTC-4, Bob Carpenter wrote:
> Does that make sense?  This provides the clean code that I (as an R user) would like---I hate hate hate telling people to write code such as "list (y=y, x=x)", it really looks mysterious)--while keeping the stan() part clean as per Bob's preferences.

This shouldn't be mysterious to an experienced R user,
but we'll probably get non-experts like me coming into
R just to use Stan (before BUGS, I only used R
occassionally for plotting or to calc a statistic).

I was confused because R auto-inserts quotes in
some contexts, like the name of variables in a list.
I wouldn't have been confused when I first saw it if
it had been:

   data <- list("y"=y, "mu"=mu, "sigma"=sigma);

I'm sort of surprised list("y"<-y, ...) doesn't work.

I agree that this aspect of the R language is confusing to newcomers to R. But the problem is that newcomers don't know much about R. And it is hard to accommodate people who don't know much about R without confusing the people who do know about R.

For all R functions the thing to the left of the equals sign is the argument name and the thing to the right is the value for that argument. For example, the first argument to the mean() function is called x

> args(mean)
function (x, ...)

This is confusing to newcomers too:

y <- rnorm(100)
mean(x = y)

while they are more comfortable with

y <- rnorm(100)
mean(y)

even though they are equivalent and the latter relies on positional matching, which is fragile when the function accepts more than one argument.

The list() function takes any number of arguments

> args(list)
function (...)

So, list(y = y, x = x) utilizes two arguments, y and x, and gives them the value of y and x in the global environment. Also valid but also confusing to newcomers would be list(a = y, b = x), which also utilizes two arguments, a and b, and gives them the value of y and x in the global environment. Newcomers are happier with list(y, x) but do not recognize that the elements of the resulting list will not have identifying names. This is verbose but fine

my_list <- list(y, x)
names(my_list) <- c("y", "x")

But the point is that RStan ultimately needs names in order to produce useful output. It isn't that hard to put a function like this into RStan

get_vars <-
  function(x) {

    if(!is.list(x)) stop("'x' must be a list")
    x <- lapply(x, get)
    return(x)
}

in which case

get_vars(list("y", "x"))

will return a list of two elements containing the values of y and x in the calling environment, but we still need names. If the list were just character strings, we could use those as names

get_vars <-
  function(x) {

    if(!is.list(x)) stop("'x' must be a list")
    if(!all(sapply(x, is.character))) stop("all elements of 'x' must be characters")
    xnames <- unlist(x)
    x <- lapply(x, get)
    names(x) <- xnames
    return(x)
}

But mixing, like

get_vars(list("N", x = y))

wouldn't work. It is probably worth putting the second version of get_vars() behind the RStan NAMESPACE so that the user can specify list("y", "x"), but better still would be for the user to learn the damn language.

Ben

Reply all
Reply to author
Forward
0 new messages