在Stan/RStan中声明其他对象时,如何使用声明为数据的对象的函数



假设我想声明一个具有ncol列的矩阵mat,其中ncol是一些数据foo的函数。我可以用下面的data块来实现这一点,这需要我向Stan传递一个带有ncol值的数据文件。

在数据文件中不包含ncol的情况下,如何在Stan程序中实现这一点

data{
vector[2] foo;
int ncol; // assume ncol = sum(foo)
matrix[2, ncol] mat;
}

下面我描述了我考虑过的一些方法,但我不确定它们是否有效以及为什么无效。

方法1:在数据块中进行操作和分配

data块内的ncol进行运算和赋值。但是,Stan参考手册指出,data块中不允许进行分配。因此,这不应该起作用:

data{
vector[2] foo;
int ncol = sum(foo); // illegal: assignment isn't allowed in data!
matrix[2, ncol] mat;
}

方法2:将操作和分配移动到转换的数据块

transformed_data块中分配。我的理解是,我不能将数据直接传递到transformed_data块中的对象,这意味着如果我将数据移动到mat,我将无法将数据传递到那里(见下文(。类似地,我无法通过将mat保留在data中来解决这个问题,因为它的维度将取决于transformed_data,这是非法的。

data{
vector[2] foo;
}
transformed_data{
int ncol = sum(foo);
matrix[2, ncol] mat; // can't read and assign to `mat` because it's not in `data`?
}

方法3:操作但不在数据块中签名

mat的声明中计算但不分配ncol的值。我认为这不会起作用,除非foo总是先读入,而且我不确定它是否合法。

data{
vector[2] foo;
matrix[2, sum(foo)] mat; // possible illegal in data block?
}

方法3在这方面取得了成功,而所有其他方法都没有。它是合法的,因为:

  • data块中声明的对象可以在data块内的后续声明中使用
  • 它不会为data块中声明的对象赋值。这有点微妙,因为它确实计算用于声明对象的值

在下文中,我展示了方法3成功地完成了我在问题中想要做的事情,而其他方法则没有。

基线示例:传递rstan额外数据

# Code that does not be changed across runs
# Packages
library(rstan)
# Program file name
relpath <- "example_stan_program.stan"
# Function to run the Stan program with specified presets
run_example <- function(model_code, data){
stan(model_code = model_code,
data = data,
iter = 1, warmup = 0, 
chains = 1, cores = 1, 
refresh = 0,
algorithm = "Fixed_param", 
verbose = F)
}
# Baseline Stan program
baseline <- "
data{ 
array[2] int foo;
int bar; // assumes bar = sum(foo)
matrix[2, bar] mat;
}
transformed data{
print(foo);
print(bar);
print(mat);
}
"
# Baseline data
dat_baseline <- list(
foo = c(1,1),
bar = sum(c(1,1)),
mat = matrix(1:4, nrow = 2, ncol = 2)
)
# Run program
out <- run_example(baseline, dat_baseline)
#> [1,1]
#> 2
#> [[1,3],[2,4]]

方法3:在data块中无赋值计算

operate <- "
data{ 
array[2] int foo;
matrix[2, sum(foo)] mat;
}
transformed data{
print(foo);
print(mat);
}
"
# Example Data
dat_operate <- list(
foo = c(1,1),
mat = matrix(1:4, nrow = 2, ncol = 2)
)
# Run program (we could also get bar in transformed_data if desired)
out <- run_example(operate, dat_operate)
#> [1,1]
#> [[1,3],[2,4]]

演示其他方法不成功

方法1:在data中操作和分配(错误(

operate <- "
data{ 
array[2] int foo;
int bar = sum(foo); // cannot assign in data block
matrix[2, bar] mat;
}
transformed data{
print(foo);
print(bar);
print(mat);
}
"
# Example Data
dat_operate <- list(
foo = c(1,1),
mat = matrix(1:4, nrow = 2, ncol = 2)
)
# Run program
out <- run_example(operate, dat_operate)
#> Error in stanc(file = file, model_code = model_code, model_name = model_name, : 0
#> 
#> Syntax error in 'string', line 3, column 12 to column 15, parsing error:
#> 
#> Cannot assign to variables in the `data` or `parameters` blocks; expected ';'
#> after variable declaration.

方法2:在transformed data中进行运算和分配(无错误,但为空矩阵(

operate_tr <- "
data{ 
array[2] int foo;
}
transformed data{
int bar = sum(foo);
matrix[2, bar] mat; // empty because values not read in data block
print(foo);
print(bar);
print(mat);
}
"
# Example Data
dat_operate_tr <- list(
foo = c(1,1),
mat = matrix(1:4, nrow = 2, ncol = 2)
)
# Run program
out <- run_example(operate_tr, dat_operate_tr)
#> [1,1]
#> 2
#> [[nan,nan],[nan,nan]]

最新更新