I have created a function for GWR maps and I have run the code without it being in the function and it works well. However, when I create into a function I get an error. I was wondering if anyone could help, thank you!
#a=polygonshapefile
#b= Dependent variabable of shapefile
#c= Explantory variable 1
#d= Explantory vairbale 2
GWR_map <- function(a,b,c,d){
GWRbandwidth <- gwr.sel(a$b ~ a$c+a$d, a,adapt=T)
gwr.model = gwr(a$b ~ a$c+a$d, data = a, adapt=GWRbandwidth, hatmatrix=TRUE, se.fit=TRUE)
gwr.model
}
GWR_map(OA.Census,"Qualification", "Unemployed", "White_British")
The above code produces the following error:
Error in model.frame.default(formula = a$b ~ a$c + a$d, data = a, drop.unused.levels = TRUE) :
invalid type (NULL) for variable 'a$b'
You can't use function parameters with the $. Try changing your function to use the [[x]] notation instead. It should look like this:
GWR_map <- function(a,b,c,d){
GWRbandwidth <- gwr.sel(a[[b]] ~ a[[c]]+a[[d]], a,adapt=T)
gwr.model = gwr(a[[b]] ~ a[[c]]+a[[d]], data = a, adapt=GWRbandwidth, hatmatrix=TRUE, se.fit=TRUE)
gwr.model
}
The R help docs (section 6.2 on lists) explain this difference well:
Additionally, one can also use the names of the list components in double square brackets,
i.e., Lst[["name"]] is the same as Lst$name. This is especially useful, when the name of the component to be extracted is stored in another variable as in
x <- "name"; Lst[[x]] It is very important to distinguish Lst[[1]] from Lst[1]. ‘[[...]]’ is the operator used to select a single element, whereas ‘[...]’ is a general subscripting operator. Thus the former is the first object in the list Lst, and if it is a named list the name is not included. The latter
is a sublist of the list Lst consisting of the first entry only. If it is a named list, the names are transferred to the sublist.
Related
To create a more compact script, I am trying to create my first function.
The general function is:
f.mean <- function(var, fig, datafile){
require(lme4)
change <- as.symbol(paste("change", var, sep=""))
base <- as.symbol(paste("baseline", var, sep = ""))
x <- substitute(lmer(change ~ base + (1|ID), data=datafile))
out<-eval(x)
name <- paste(fig,".", var, sep="")
as.symbol(name) <- out
}
}
The purpose of this function is to input var, fig and datafile and to output a new variable named fig.var containing out (eval of LMER).
Apparently it is difficult to 'change' the variable name on the left side of the <-.
What we have tried so far:
- assign(name, out)
- as.symbol(name) <<- out
- makeActive Binding("y",function() x, .GlobalEnv)
- several rename options to rename out to the specified var name
Can someone help me to assign the out value to this 'run' specific variable name? All other suggestions are welcome as well.
As #Roland comments, in R (or any) programming one should avoid indirect environment manipulators such as assign, attach, list2env, <<-, and others which are difficult to debug and break the flow of usual programming involving explicitly defined objects and methods.
Additionally, avoid flooding your global environment of potentially hundreds or thousands of similarly structured objects that may require environment mining such as ls, mget, or eapply. Simply, use one large container like a list of named elements which is more manageable and makes code more maintainable.
Specifically, be direct in assigning objects and pass string literals (var, fig) or objects (datafile) as function parameters and have function return values. And for many inputs, build lists with lapply or Map (wrapper to mapply) to retain needed objects. Consider below adjustment that builds a formula from string literals and passes into your model with results to be returned at end.
f.mean <- function(var, fig, datafile){
require(lme4)
myformula <- as.formula(paste0("change", var, " ~ baseline", var, " + (1|ID)"))
x <- lmer(myformula, data=datafile)
return(x)
}
var_list <- # ... list/vector of var character literals
fig_list <- # ... list/vector of fig character literals
# BUILD AND NAME LIST OF LMER OUTPUTS
lmer_list <- setNames(Map(f.mean, var_list, fig_list, MorArgs=df),
paste0(fig_list, ".", var_list))
# IDENTIFY NEEDED var*fig* BY ELEMENT NAME OF LARGER CONTAINER
lmer_list$fig1.var1
lmer_list$fig2.var2
lmer_list$fig3.var3
I have a general function that calls an expression that uses a formula and I would like to pass this functions to various environments that store some specific variables and modify parts of a formula designated by a specific pattern.
Here is an example:
# Let's assume I have an environment storing a variable
env <- new.env()
env$..M.. <- "Sepal.Length"
# And a function that calls an expression
func <- function() summary(lm(..M.. ~ Species, data = iris))$r.squared
# And let's assume I am trying to evaluate it within the environment
environment(func) <- env
# And I would like to have some method that makes it evaluate as:
summary(lm(Sepal.Length ~ Species, data = iris))$r.squared
So far I came up with a very dirty solution based on deparsing the function down to string, greping and then parsing it back. It goes like this:
tfunc <- paste(deparse(func), collapse = "")
tfunc <- gsub("\\.\\.M\\.\\.", ..M.., tfunc, perl = TRUE)
tfunc <- eval(parse(text = tfunc))
So yes, it works, but I would like to find a cleaner method, that would somewhat magically substitute this ..M.. pattern into Sepal.Length without a need for all this parsing and deparsing.
So I would really appreciate some help and hints for that problem.
I copied the function from the web:
# function used to predict Best Subset Selection Regression
predict.regsubsets = function(object, newdata, id, ...) {
form = as.formula(object$call[[2]])
mat = model.matrix(form, newdata)
coefi = coef(object, id = id)
mat[, names(coefi)] %*% coefi
}
However, when I try to use the above function within another function , I kept getting the following error.
library(leaps)
abc <- function(){
regfit <- regsubsets(lpsa ~.,data = XTraining, nvmax = 8)
predict.regsubsets(regfit, data = XTesting, id = 1)
}
abc()
Error in object$call[[2]] : subscript out of bounds
I read ?call in R already. But it doesn't help me understanding what went wrong here, in particular what is $call[[2]] ?
How can I edit the function above such that when I call the above function inside another function I won't get an error ?
The culprit is the line
form = as.formula(object$call[[2]])
This implies that object (which is the variable you pass to the function, in your example regfit) has a member called call, which is a list with at least two elements. [[ ]] is the R operator used to take the elements of a list.
For instance:
> a <- list(1:10, 1:5, letters[15:20])
> a[[2]]
[1] 1 2 3 4 5
> a[[3]]
[1] "o" "p" "q" "r" "s" "t"
However
> a[[5]] # This does not work, as a only has three elements
Error in a[[5]] : subscript out of bounds
You should not check ?call but rather the help for the function that generates object, in your case regsubsets.
As you can see from ?regsubsets, or by using str(regfit), that function does not return an object with a member named call.
To get the formula from a regsubsets object you need to look at the obj member of the summary.
For instance you could use:
sm <- summary(regfit)
sm$obj$call
Your mistake is in the function abc. The argument in the predict.regsubsets is called newdata, but you refer to is as data....
The object is probably the output from a previous analysis (look at the place you got the code from what function). The line form = as.formula(objects$call[[2]]) extracts the formula used to create the object and stores it in form. In the next lines it is used to create the model matrix of the new data, and finally uses it to predict the new data.
I want to pass a variable name into a function and can't seem to do it. Simply...
library (reshape)
test <- function(x) {
cast(data, x ~ ., length)
}
test(ageg)
I get this kickback.
Error: Casting formula contains variables not found in molten data: x
I know it's simple but I can't find the answer.I want it to simply run
cast(data, ageg ~ ., length)
Try this:
test <- function (x) cast(data, as.formula(paste0(x , " ~ .")), length)
What you are trying to do is write a formula on the fly. However, a formula is possed on as quoted part of the language (IIRC). Therefore, your x is not evaluated but looked for in your data as x.
What this does on the other hand is to first create a character string by evaluating x in paste0. Then the string is converted to a formula using as.formula.
i am struggling with an assignment and i would like your input.
note: this is a homework but when i tried to add the tag it said not to add it..
i don't want the resulting code, just suggestions on how to get this working :)
so, i have a t.test function as such:
my.t.test <- function(x,s1,s2){
x1 <- x[s1]
x2 <- x[s2]
x1 <- as.numeric(x1)
x2 <- as.numeric(x2)
t.out <- t.test(x1,x2,alternative="two.sided",var.equal=T)
out <- as.numeric(t.out$p.value)
return(out)
}
a matrix 30cols x 12k rows called data and an annotation file containing col names and data on the colums named dataAnn
dataAnn first column contains a list of M (male) or F (female) corresponding to the samples (or cols) in data (that follow the same order as in dataAnn), i have to run a t.test comparing the two samples and get the p values out
when i call
raw.pValue <- apply(data,1,my.t.test,s1=dataAnn[,1]=="M",s2=dataAnn[,1]=="F")
i get the error
Error in t.test(x1, x2, alternative = "two.sided", var.equal = T) :
unused argument(s) (alternative = "two.sided", var.equal = T)
i even tried to use
raw.pValue <- apply(data,1,my.t.test,s1=unlist(data[,1:18]),s2=unlist(data[,19:30]))
to divide the cols i want to compare but in this case i get the error
Error in x[s1] : invalid subscript type 'list'
i have been looking online, i understand that the second error is caused by an indices being a list...but this didn't really clarify it for me...
any input would be appreciated!!
You have overwritten the t.test function. Try calling it something like my.t.test, or when you want to call the original one use stats::t.test (this calls the one from the stats namespace). Remember that when you have overwritten a function you need to rm it from your workspace before you can use the original one without specifying the namespace.