I have used JAGS called via rjags to produce the mcmc.list object foldD_samples, which contains trace monitors for a large number of stochastic nodes (>800 nodes).
I would now like to use R to compute a fairly complicated, scalar-valued function of these nodes, and write the output to an mcmc object so that I can use coda to summarize the posterior and run convergence diagnostics.
However, I haven't been able to figure out how get the posterior draws from foldD_samples into a dataframe. Any help much appreciated.
Here is the structure of the mcmc.list:
str(foldD_samples)
List of 3
$ : mcmc [1:5000, 1:821] -0.667 -0.197 -0.302 -0.204 -0.394 ...
..- attr(*, "dimnames")=List of 2
.. ..$ : NULL
.. ..$ : chr [1:821] "beta0" "beta1" "beta2" "dtau" ...
..- attr(*, "mcpar")= num [1:3] 4100 504000 100
$ : mcmc [1:5000, 1:821] -0.686 -0.385 -0.53 -0.457 -0.519 ...
..- attr(*, "dimnames")=List of 2
.. ..$ : NULL
.. ..$ : chr [1:821] "beta0" "beta1" "beta2" "dtau" ...
..- attr(*, "mcpar")= num [1:3] 4100 504000 100
$ : mcmc [1:5000, 1:821] -0.492 -0.679 -0.299 -0.429 -0.421 ...
..- attr(*, "dimnames")=List of 2
.. ..$ : NULL
.. ..$ : chr [1:821] "beta0" "beta1" "beta2" "dtau" ...
..- attr(*, "mcpar")= num [1:3] 4100 504000 100
- attr(*, "class")= chr "mcmc.list"
Cheers,
Jacob
As it's a list structure you can use either of these methods to bind the matrices together.
do.call(rbind.data.frame, foldD_samples)
or
rbindlist(lapply(foldD_samples, as.data.frame)) # thanks to BenBolker
A mwe
library(rjags)
library(coda)
library(data.table)
mod <- textConnection("model {
A ~ dnorm(0, 1)
B ~ dnorm(0, 1)
}")
# evaluate
mod <- jags.model(mod, n.chains = 4, n.adapt = 50000)
pos <- coda.samples(mod, c("A", "B"), 10000)
out <- do.call(rbind.data.frame, pos)
out2 <- rbindlist(lapply(pos, as.data.frame))
all.equal(out, out2, check.attributes=FALSE)
The answer given by user20650 will certainly work, but it can be quite slow. Also note that as of this writing, rbind_list() is deprecated in place of bind_rows().
Something I've written for my own purposes converts the mcmc.list to a "long format" data.frame. On my machine, it is about 4-7x faster than the above methods, and adds two additional columns: one for the chain number, and one for the step number.
parameter_names <- varnames(mcmc_list)
saved_steps <- as.integer(row.names(mcmc_list[[1]]))
out <- data.frame("chain" = factor(rep(1 : length(mcmc_list), each = length(saved_steps))),
"step" = rep(saved_steps, length(mcmc_list)) )
for (param in parameter_names) {
out[param] <- NA
}
for (a_chain in 1 : length(mcmc_list)) {
out[out$chain == a_chain, parameter_names ] <- as.data.frame(mcmc_list[[a_chain]])
}
return(out)
Working with an mcmc.list object of 3 chains, 50,000 rows total,
rbind_list/do.call method: 0.71 sec avg elapsed time
my method: 0.12 sec avg elapsed time
Edit: some further reading of code in the library "coda" shows that as.matrix() is much faster.
parameter_names <- varnames(mcmc_list)
saved_steps <- as.integer(row.names(mcmc_list[[1]]))
out <- data.frame("chain" = factor(rep(1 : length(mcmc_list), each = length(saved_steps))),
"step" = rep(saved_steps, length(mcmc_list)) )
out <- cbind(out, as.data.frame(as.matrix(chain_samples)))
Takes on overage 0.03 seconds elapsed time.
Related
I'm using R on Alteryx to perform some statical analysis from my data.
It appears the error message " ! All Columns in a tibble must be vectors." as the following error message:
Does anybody can help me?
Below is my entire code:
library("tibble")
# Calling Data from Connection #1
data <- read.Alteryx("#1")
average_wilcox <- c("1","1","1","1","1","1","1")
# Creating data frame for in case it comes an empty table
df <- data.frame(average_wilcox)
#Verify if p-value is empty
# In case is different that empty, executes the steps for the Hypothesis Test for non-normal data
if (length(data$p.value) == 0) {
write.Alteryx(df, 1)
} else if (data$p.value != '') {
Week1 <- read.Alteryx("#2", mode="data.frame")
"&"
Week2 <- read.Alteryx("#3", mode="data.frame")
# MANN WHITNEY TEST (AVERAGE TEST FOR NON NORMAL)
Week1_data <- Week1$Wk1_feature_value
Week2_data <- Week2$Wk2_feature_value
# DEFINE VECTORS
week1 <- c(Week1_data)
week2 <- c(Week2_data)
merge(cbind(Week1, X=1:length(week1)),
cbind(Week2, X=1:length(week2)), all.y =T) [-1]
# MANN WHITNEY TEST (MEAN TEST FOR NON NORMAL)
average_wilcox <- wilcox.test(week1,week2, alternative='two.sided', conf.level=.95)
average_test <- tibble(average_wilcox)
average_test[] <- lapply(average_test, as.character)
write.Alteryx(average_test, 1)
}
#### NORMAL HYPOTHESIS TEST ####
# Calling Data from Connection #4
data1 <- read.Alteryx("#4")
df1 <- data.frame(Date=as.Date(character()),"p.value"=character(),User=character(),stringsAsFactors=FALSE)
# Verify if p-value is empty
# In case if different than empty, executes the steps for the Hypothesis Test for normal data
if(length(data1$p.value) == 0) {
write.Alteryx(df1, 3)
} else if (data1$p.value != '') {
Week1 <- read.Alteryx("#2", mode="data.frame")
"&"
Week2 <- read.Alteryx("#3", mode="data.frame")
# T TEST (MEAN TEST FOR NORMAL)
Week1_data <- Week1$Wk1_feature_value
Week2_data <- Week2$Wk2_feature_value
# DEFINE VECTORS
week1 <- c(Week1_data)
week2 <- c(Week2_data)
# T TEST (MEAN TEST FOR NORMAL)
t_test <- t.test(week1,week2, alternative='two.sided',conf.level=.95)
write.Alteryx(t_test,3)
}
Please, anybody knows what I have to do?
Many thanks,
Wil
Reason is that both wilcox.test and t.test returns a list of vectors, which may have difference in length. So, using that list in write.Alteryx is triggering the error as it expects a data.frame/tibble/data.table. e.g.
> str(t.test(1:10, y = c(7:20)))
List of 10
$ statistic : Named num -5.43
..- attr(*, "names")= chr "t"
$ parameter : Named num 22
..- attr(*, "names")= chr "df"
$ p.value : num 1.86e-05
$ conf.int : num [1:2] -11.05 -4.95
..- attr(*, "conf.level")= num 0.95
$ estimate : Named num [1:2] 5.5 13.5
..- attr(*, "names")= chr [1:2] "mean of x" "mean of y"
$ null.value : Named num 0
..- attr(*, "names")= chr "difference in means"
$ stderr : num 1.47
$ alternative: chr "two.sided"
$ method : chr "Welch Two Sample t-test"
$ data.name : chr "1:10 and c(7:20)"
- attr(*, "class")= chr "htest"
> x <- c(0.80, 0.83, 1.89, 1.04, 1.45, 1.38, 1.91, 1.64, 0.73, 1.46)
> y <- c(1.15, 0.88, 0.90, 0.74, 1.21)
> str(wilcox.test(x, y, alternative = "g") )
List of 7
$ statistic : Named num 35
..- attr(*, "names")= chr "W"
$ parameter : NULL
$ p.value : num 0.127
$ null.value : Named num 0
..- attr(*, "names")= chr "location shift"
$ alternative: chr "greater"
$ method : chr "Wilcoxon rank sum exact test"
$ data.name : chr "x and y"
- attr(*, "class")= chr "htest"
An option is to convert the output from both t.test and wilcox.test to a data.frame/tibble. tidy/glance from broom does this
...
library(broom)
average_wilcox <- tidy(wilcox.test(week1,week2, alternative='two.sided', conf.level=.95))
write.Alteryx(average_wilcox, 1)
...
t_test <- tidy(t.test(week1,week2, alternative='two.sided',conf.level=.95))
write.Alteryx(t_test,3)
I am using the package circular in R to fit a von Mises distribution to a set of data:
Mises <- mle.vonmises(x = angle, mu = NULL, kappa = NULL, bias = FALSE, control.circular = list())
The results are from the class circular. Is there a way to extract both mu and kappa to have them as numerics? I need to do that many times (I guess using group_by()), so writing down manually the displayed values of mu and kappa is not an option.
Thanks for the help!
The output of mle.vonmises is a list.
> str(Mises)
List of 8
$ call : language mle.vonmises(x = x)
$ mu : 'circular' num -0.0264 # it is a numeric value
..- attr(*, "circularp")=List of 6
.. ..$ type : chr "angles"
.. ..$ units : chr "radians"
.. ..$ template: chr "none"
.. ..$ modulo : chr "asis"
.. ..$ zero : num 0
.. ..$ rotation: chr "counter"
$ kappa : num 5.21
$ se.mu : num 0.0654
$ se.kappa : num 0.973
$ est.mu : num 1
$ est.kappa: num 1
$ bias : logi FALSE
- attr(*, "class")= chr "mle.vonmises"
We can use standard extractors to extract the list elements ie. $ or [[. Regarding conversion to numeric, the mu is already numeric class.
> class(Mises$mu)
[1] "circular" "numeric"
It also include some attributes with an additional class circular built on top of numeric which can be removed by either wrapping with as.numeric or as.vector or set the attributes to NULL
as.numeric(Mises$mu)
#[1] -0.02639894
Mises$kappa
[1] 5.214254
data
library(circular)
x <- rvonmises(n=50, mu=circular(0), kappa=5)
Mises <- mle.vonmises(x)
Note: The following analysis is solely for reproducible objects -- and is not being put forth as a legitimate way to analyze the bacteria data from MASS.
library(glmmADMB)
library(glmmTMB)
data(bacteria,package="MASS")
bacteria$present <- as.numeric(bacteria$y)-1
bacteria$early <- factor(as.numeric(bacteria$week > 3) + 1)
bfit2 <- glmmadmb(present ~ trt ,
random = ~ (1 | ID) + (1 | early),
family = "binomial", data = bacteria)
bfit2$S
bfit2$sd_S
bfit3 <- glmmTMB(present ~ trt + (1 | ID) + (1 | early),
family = "binomial", data = bacteria)
summary(bfit3)$varcor
confint(bfit3)
In my understanding,
bfit2$S contains estimates for the variance of random effects for glmmADMB
bfit3$varcor contains estimates for the standard deviation of random effects for glmmTMB (that is, the sqrt() of the elements of bfit2$S)
bfit2$sd_S contains standard errors of the estimates in bfit2$S for glmmADMB (as noted in this SO post)
Where are the standard errors for bfit3$varcor stored in a glmmTMB object? UPDATE: confint is implemented for glmmTMB objects, so if calculating 95% CI is the end goal then that's available (Thanks kaskr).
> bfit2$S
$ID
(Intercept)
(Intercept) 1.4047
$early
(Intercept)
(Intercept) 0.51465
> bfit2$sd_S
$ID
(Intercept)
(Intercept) 0.94743
$early
(Intercept)
(Intercept) 0.61533
> summary(bfit3)$varcor
Conditional model:
Groups Name Std.Dev.
ID (Intercept) 1.18513
early (Intercept) 0.71733
> confint(bfit3)
2.5 % 97.5 % Estimate
cond.(Intercept) 1.1934429 4.1351114 2.6642771
cond.trtdrug -2.6375284 -0.0503639 -1.3439462
cond.trtdrug+ -2.0819454 0.5325683 -0.7746885
cond.Std.Dev.ID.(Intercept) 0.6118984 2.2953603 1.1851276
cond.Std.Dev.early.(Intercept) 0.2222685 2.3150437 0.7173293
As we can see, sqrt(1.4047) = 1.18513 and sqrt(0.51465) = 0.71733 so that indicates bfit2$S gives the estimates for the variances and summary(bfit3)$varcor gives the estimates for the standard deviation.
2nd update:
After some digging, I realized that bfit3$sdr returns the variance components on the log-sd-scale, along with the standard errors. So one thought was to avoid confint and back calculate the SEs by calculating 95%CIs on log-sd-scale and then transforming to desired scale and then dividing width of CI by 2*1.96.
## to get the standard errors from glmmTMB:
bfit3$sdr
## note that theta is just log(sd)
exp(summary(bfit3$sdr, "fixed")[4,1])
exp(summary(bfit3$sdr, "fixed")[5,1])
## calculate the (wald) lower and upper on the log(sd) scale:
low.log.sd.id <- summary(bfit3$sdr, "fixed")[4,1] - 1.96*summary(bfit3$sdr, "fixed")[4,2]
low.log.sd.early <- summary(bfit3$sdr, "fixed")[5,1] - 1.96*summary(bfit3$sdr, "fixed")[5,2]
upp.log.sd.id <- summary(bfit3$sdr, "fixed")[4,1] + 1.96*summary(bfit3$sdr, "fixed")[4,2]
upp.log.sd.early <- summary(bfit3$sdr, "fixed")[5,1] + 1.96*summary(bfit3$sdr, "fixed")[5,2]
## convert to variance scale by taking exp and then squaring
low.var.id <- exp(low.log.sd.id)^2
upp.var.id <- exp(upp.log.sd.id)^2
low.var.early <- exp(low.log.sd.early)^2
upp.var.early <- exp(upp.log.sd.early)^2
## back calculate SEs
(upp.var.id - low.var.id) / (2*1.96)
(upp.var.early - low.var.early) / (2*1.96)
## see how they compare to the confint answers for sd:
sqrt(c(low.var.id, upp.var.id))
sqrt(c(low.var.early, upp.var.early))
Run it:
> ## to get the standard errors from glmmTMB:
> bfit3$sdr
sdreport(.) result
Estimate Std. Error
beta 2.6642771 0.7504394
beta -1.3439462 0.6600031
beta -0.7746885 0.6669800
theta 0.1698504 0.3372712
theta -0.3322203 0.5977910
Maximum gradient component: 4.83237e-06
> ## note that theta is just log(sd)
> exp(summary(bfit3$sdr, "fixed")[4,1])
[1] 1.185128
> exp(summary(bfit3$sdr, "fixed")[5,1])
[1] 0.7173293
> ## calculate the (wald) lower and upper on the log(sd) scale:
> low.log.sd.id <- summary(bfit3$sdr, "fixed")[4,1] - 1.96*summary(bfit3$sdr, "fixed")[4,2]
> low.log.sd.early <- summary(bfit3$sdr, "fixed")[5,1] - 1.96*summary(bfit3$sdr, "fixed")[5,2]
> upp.log.sd.id <- summary(bfit3$sdr, "fixed")[4,1] + 1.96*summary(bfit3$sdr, "fixed")[4,2]
> upp.log.sd.early <- summary(bfit3$sdr, "fixed")[5,1] + 1.96*summary(bfit3$sdr, "fixed")[5,2]
> ## convert to variance scale by taking exp and then squaring
> low.var.id <- exp(low.log.sd.id)^2
> upp.var.id <- exp(upp.log.sd.id)^2
> low.var.early <- exp(low.log.sd.early)^2
> upp.var.early <- exp(upp.log.sd.early)^2
> ## back calculate SEs
> (upp.var.id - low.var.id) / (2*1.96)
[1] 1.24857
> (upp.var.early - low.var.early) / (2*1.96)
[1] 1.354657
> ## see how they compare to the confint answers for sd:
> sqrt(c(low.var.id, upp.var.id))
[1] 0.611891 2.295388
> sqrt(c(low.var.early, upp.var.early))
[1] 0.2222637 2.3150935
The last two rows above match the last two rows of the confint(bfit3) output pretty well. Now I guess I just wonder why the SEs for glmmADMB were 0.94743 and 0.61533 whereas the back-calculated ones for glmmTMB are 1.24857 and 1.354657 respectively...(?)
Not 100% sure about your analysis, but here's what I did to check (including digging in the guts of glmmADMB and using slightly obscure aspects of glmmTMB):
run glmmADMB, and dig into the ADMB .std output file to check on the results:
n par estimate sd
4 tmpL 1.6985e-01 3.3727e-01
5 tmpL -3.2901e-01 5.9780e-01
...
62 S 1.4045 9.474e-01
63 S 5.178e-01 6.191e-01
These lines are, respectively, the internal parameters (tmpL: log-standard deviations) and the transformed parameters (variances).
Re-do the transformation and check:
tmpL <- c(0.16985,-0.32901)
cbind(admb.raw=exp(2*tmpL),
admb=unlist(bfit2$S),
tmb =unlist(VarCorr(bfit3)))
## admb.raw admb tmb
## ID 1.4045262 1.40450 1.4045274
## early 0.5178757 0.51788 0.5145613
We get from the standard deviation of the log-std dev of the random effect to the standard deviation of the variance by multiplying by the derivative of the transformation (V = exp(2*logsd), so dV/d(logsd) = 2*exp(2*logsd))
## sd of log-sd from glmmTMB
tmb_sd <- sqrt(diag(vcov(bfit3,full=TRUE)))[4:5]
tmb_logsd <- bfit3$sdr$par.fixed[4:5]
tmpL_sd <- c(0.33727,0.5978)
cbind(admb.raw=tmpL_sd*2*exp(2*tmpL),
admb=unlist(bfit2$sd_S),
tmb=tmb_sd*2*exp(2*tmb_logsd))
## admb.raw admb tmb
## ID 0.9474091 0.94741 0.9474132
## early 0.6191722 0.61918 0.6152003
So these all seem to match up OK.
The $varcor object is a list. The standard deviations are stored as attributes:
str( summary(bfit3)$varcor )
List of 2
$ cond:List of 2
..$ ID : num [1, 1] 1.4
.. ..- attr(*, "dimnames")=List of 2
.. .. ..$ : chr "(Intercept)"
.. .. ..$ : chr "(Intercept)"
.. ..- attr(*, "stddev")= Named num 1.19
.. .. ..- attr(*, "names")= chr "(Intercept)"
.. ..- attr(*, "correlation")= num [1, 1] 1
.. .. ..- attr(*, "dimnames")=List of 2
.. .. .. ..$ : chr "(Intercept)"
.. .. .. ..$ : chr "(Intercept)"
.. ..- attr(*, "blockCode")= Named num 1
.. .. ..- attr(*, "names")= chr "us"
..$ early: num [1, 1] 0.515
.. ..- attr(*, "dimnames")=List of 2
.. .. ..$ : chr "(Intercept)"
.. .. ..$ : chr "(Intercept)"
.. ..- attr(*, "stddev")= Named num 0.717
.. .. ..- attr(*, "names")= chr "(Intercept)"
.. ..- attr(*, "correlation")= num [1, 1] 1
.. .. ..- attr(*, "dimnames")=List of 2
.. .. .. ..$ : chr "(Intercept)"
.. .. .. ..$ : chr "(Intercept)"
.. ..- attr(*, "blockCode")= Named num 1
.. .. ..- attr(*, "names")= chr "us"
..- attr(*, "sc")= num 1
..- attr(*, "useSc")= logi FALSE
$ zi : NULL
- attr(*, "sc")= logi FALSE
- attr(*, "class")= chr "VarCorr.glmmTMB"
This will loop over the .$cond elements of that object:
sapply( summary(bfit3)$varcor$cond, function(x) attr( x, "stddev") )
ID.(Intercept) early.(Intercept)
1.1851276 0.7173293
I wonder why preProcess function from R's caret package used for imputation of dataset's missing values returns less observations than in original dataset?
For example:
library(caret)
t <- data.frame(seq_len(100000),seq_len(100000))
for (i in 1:100000)
{
if (i %% 10 == 0) t[i,1] <- NA;
if (i %% 100 == 0) t[i,2] <- NA
}
preProcValues <- preProcess(t, method = c("knnImpute"))
preProcValues will contain only 90000 observations of 2 variables while 100000 is expected.
From the documentation:
The function preProcess estimates the required parameters for each
operation and predict.preProcess is used to apply them to specific
data sets.
Here, preProcValues is not t after imputation, it contains the parameters required to perform the imputation on t using predict.preProcess.
You should not be expecting 100K observations in preProcValues
Hint: Have a look at the source code to see what is going on under the hood with NA values
Using your example (modified to use method = "medianImpute" - See this question (and the above-mentioned source code) for why what you are trying to do wouldn't work with "knnImpute")
preProcValues <- preProcess(t, method = "medianImpute")
> preProcValues$dim[1]
#[1] 90000
Here we replace the NA values in t with the median (50K)
t2 <- predict(preProcValues, t)
> dim(t2)[1]
#[1] 100000
preProcess does not return values, it simply sets up the whole preprocess model based on the provided data. So, you need to run predict (requiring also the RANN package), but even if you do so with your artificial data you'll get an error:
Error in FUN(newX[, i], ...) :
cannot impute when all predictors are missing in the new data point
as the k-nn imputation can not work in rows where both your predictors are NA's.
Here's a demonstration with only 20 rows, for clarity and easy inspection:
library(caret)
t <- data.frame(seq_len(20),seq_len(20))
for (i in 1:20)
{
if (i %% 3 == 0) t[i,1] <- NA;
if (i %% 7 == 0) t[i,2] <- NA
}
names(t) <- c('V1', 'V2')
preProcValues <- preProcess(t, method = c("knnImpute"))
library(RANN)
t_imp <- predict(preProcValues, t)
When viewing the result, keep in mind that methods "center", "scale" have been automaticaly added to your preprocessing, even if you did not invoke them explicitly:
> str(preProcValues)
List of 19
$ call : language preProcess.default(x = t, method = c("knnImpute"))
$ dim : int [1:2] 12 2
$ bc : NULL
$ yj : NULL
$ et : NULL
$ mean : Named num [1:2] 10.5 10.5
..- attr(*, "names")= chr [1:2] "V1" "V2"
$ std : Named num [1:2] 6.25 6.14
..- attr(*, "names")= chr [1:2] "V1" "V2"
$ ranges : NULL
$ rotation : NULL
$ method : chr [1:3] "knnImpute" "scale" "center"
$ thresh : num 0.95
$ pcaComp : NULL
$ numComp : NULL
$ ica : NULL
$ k : num 5
$ knnSummary:function (x, ...)
$ bagImp : NULL
$ median : NULL
$ data : num [1:12, 1:2] -1.434 -1.283 -0.981 -0.83 -0.377 ...
..- attr(*, "dimnames")=List of 2
.. ..$ : chr [1:12] "1" "2" "4" "5" ...
.. ..$ : chr [1:2] "V1" "V2"
..- attr(*, "scaled:center")= Named num [1:2] 10.5 10.5
.. ..- attr(*, "names")= chr [1:2] "V1" "V2"
..- attr(*, "scaled:scale")= Named num [1:2] 6.63 6.63
.. ..- attr(*, "names")= chr [1:2] "V1" "V2"
- attr(*, "class")= chr "preProcess"
Is there a convenient way to extract the data from a gam plot, without actually plotting the gam object?
Here's a dummy example. plot.data has the data I want in it, but I don't want the plot window to be affected.
library(mgcv)
x=1:10000/1000
y = sin(x)+rnorm(10000,sd=2)
m = gam(y~s(x))
plot.data<-plot(m,plot=F)
It doesn't look like plot.gam has the option for not plotting. But you could try
plot.data <- {
dev.new()
res <- plot(m)
dev.off()
res
}
or possibly
plot.data <- {
pdf(NULL)
res <- plot(m)
invisible(dev.off())
res
}
If you're using gam() from the package gam, then you can get those data in list form by calling preplot(m). Here's what that looks like for your data:
library(gam)
x = 1:10000/1000
y = sin(x)+rnorm(10000,sd=2)
m = gam(y~s(x))
preplot(m)
List of 1
$ s(x):List of 5
..$ x : num [1:10000] 0.001 0.002 0.003 0.004 0.005 0.006 0.007 0.008 0.009 0.01 ...
..$ y : Named num [1:10000] 0.421 0.421 0.421 0.421 0.421 ...
.. ..- attr(*, "names")= chr [1:10000] "1" "2" "3" "4" ...
..$ se.y: Named num [1:10000] 0.0783 0.0782 0.0781 0.0781 0.078 ...
.. ..- attr(*, "names")= chr [1:10000] "1" "2" "3" "4" ...
..$ xlab: chr "x"
..$ ylab: chr "s(x)"
..- attr(*, "class")= chr "preplot.gam"
- attr(*, "class")= chr "preplot.gam"
The x and y components of that list are what I think you're after. Presumably, if you've got more than one smoothing term in your model, the ith component of the preplot list will correspond to the ith smoothing term in your original call to gam().