I want to make some calculations using loop in R.
I try assign but it still does not work well.
Can anyone give me a hint about how to setting up correct variable in R, please?
# My data
data <- read.table(textConnection("
a1 a2
a1 1.00000000 0.4803088
a1 0.48030878 1.0000000
"), header = TRUE)
no <- 2
for (k in 1:no){
paste0("dat.",k) <- aggregate(data[,c(paste0("a",k),paste0("b",k), paste0("b",k))],list(data$id),mean)
paste0("cor.",k) <- cor(paste0("dat.mean.",k),use = "complete.obs")
paste0("cal.",k) <- as.data.frame(paste0("dat.mean.",k))
paste0("lm.",k) <- lm(paste0("a",k) ~ paste0("b",k),data = paste0("lm.cal.",k))
}
I'm not sure which language you are coming from (SAS maybe?) but R is a proper functional programming language and doesn't use things like macros to automate tasks. Here's a more R-like way to approach the problem
no <- 2
results <- lapply(1:no, function(k) {
# use aggregate function to make correlation calculation.
this_dat_mean <- aggregate(data[,c(paste0("y", c("f","p","c"), "_",k))], list(data$id), mean)
this_cor <- cor(this_dat_mean, use = "complete.obs")
#write.table(this_cor, "file_path", row.names=T, col.names=T, quote=F)
# calculate the lm
this_lm_cal <- as.data.frame(this_dat_mean)
this_lm <- lm(reformulate(paste0("yc_",k), paste0("yf_",k)), data = this_lm_cal)
#write.table(this_lm, "file_path2", row.names=T, col.names=T, quote=F)
list(lm=this_lm, cor=this_cor)
})
Notice that we use a function to iterate over the inputs of interest. This function has a bunch of local variables. We can return a list of values that we want to preserve from the function. We can get at them by looking at
results[[1]]$lm
results[[2]]$cor
for example. It's better to create a (possibly named) list of values in R than to create a bunch of similarly named variables.
The lm model isn't a data.frame so you can't use write.table with that. Not sure what the goal was there.
For your use case, I second the point by MrFlick and suggest rewriting your code.
However, as I sometimes myself prefer dynamically generated variables in some situations and R is messy and do allow you to do so in selective ways (some things work, some do not), I would like to briefly explain you how:
> k=4
> paste0("lm.", k)
[1] "lm.4"
> paste0("lm.", k) <- 1515
Error in paste0("lm.", k) <- 1515 :
target of assignment expands to non-language object
> assign ( paste0("lm.", k) , 1515 )
> paste0("lm.", k)
[1] "lm.4"
> eval(parse(text = paste0("lm.", k) ))
[1] 1515
> str(eval(parse(text = paste0("lm.", k) )))
num 1515
> str(paste0("lm.", k) )
chr "lm.4"
in summary: every time you use a glued-together variable, you have to refer to it through eval/parse. And remember that <-will not work as opperator - use assign()
Related
I have built my own function, where it returns many values. I really need to extract several values at once. For example, suppose the following is my function
myfunc <- function(x,y){
res <- x+y
res2 <- x^2
res3 <- x*2
out <- list()
out$add <- res
out$squ <- res2
out$or <- res3
out$ADD <- res+res2+res3
out$fi <- res^2+res2+res3
return(out)
}
Then,
> myres
$add
[1] 7
$squ
[1] 9
$or
[1] 6
$ADD
[1] 22
$fi
[1] 64
suppose I want to extract two values at a time, for example,
myres$add, and myres$ADD
is there a way to find them automatically in R instead of repeating it. My original function is very complicated and this will help a lot.
Perhaps, you can try something like this -
res <- myfunc(6, 4)
extract_values <- c('add', 'ADD')
res[extract_values]
#$add
#[1] 10
#$ADD
#[1] 58
You could concatenate them or join in a list:
c(myres$add, myres$squ)
list(myres$add, myres$squ)
If you only want one call to myres you could also index like this:
myres[c(1, 2)]
What you want is known as destructuring, and unfortunately R does not natively support it. There are multiple packages which support this. The one with the (IMHO) nicest syntax is my own package ‘unpack’, which allows you to write positional unpacking as follows:
c[add, ., ., ADD, .] = myfunc(3, 4)
After this, the variables add and ADD are directly available to the caller.
A similar solution (more powerful but with a less nice syntax) is provided by the ‘zeallot’ package.
I want to use information from a field and include it in a R function, e.g.:
data #name of the data.frame with only one raw
"(if(nclusters>0){OptmizationInputs[3,3]*beta[1]}else{0})" # this is the raw
If I want to use this information inside a function how could I do it?
Another example:
A=c('x^2')
B=function (x) A
B(2)
"x^2" # this is the return. I would like to have the return something like 2^2=4.
Use body<- and parse
A <- 'x^2'
B <- function(x) {}
body(B) <- parse(text = A)
B(3)
## [1] 9
There are more ideas here
Another option using plyr:
A <- 'x^2'
library(plyr)
body(B) <- as.quoted(A)[[1]]
> B(5)
[1] 25
A <- "x^2"; x <- 2
BB <- function(z){ print( as.expression(do.call("substitute",
list( parse(text=A)[[1]], list(x=eval(x) ) )))[[1]] );
cat( "is equal to ", eval(parse(text=A)))
}
BB(2)
#2^2
#is equal to 4
Managing expressions in R is very weird. substitute refuses to evaluate its first argument so you need to use do.call to allow the evaluation to occur before the substitution. Furthermore the printed representation of the expressions hides their underlying representation. Try removing the fairly cryptic (to my way of thinking) [[1]] after the as.expression(.) result.
Thanks in advance, and sorry if this question has been answered previously - I have looked pretty extensively. I have a dataset containing a row of with concatenated information, specifically: name,color code,some function expression. For example, one value may be:
cost#FF0033#log(x)+6.
I have all of the code to extract the information, and I end up with a vector of expressions that I would like to convert to a list of actual functions.
For example:
func.list <- list()
test.func <- c("x","x+1","x+2","x+3","x+4")
where test.func is the vector of expressions. What I would like is:
func.list[[3]]
To be equivalent to
function(x){x+3}
I know that I can create a function using:
somefunc <- function(x){eval(parse(text="x+1"))}
to convert a character value into a function. The problem comes when I try and loop through to make multiple functions. For an example of something I tried that didn't work:
for(i in 1:length(test.func)){
temp <- test.func[i]
f <- assign(function(x){eval(expr=parse(text=temp))})
func.list[[i]] <- f
}
Based on another post (http://stats.stackexchange.com/questions/3836/how-to-create-a-vector-of-functions) I also tried this:
makefunc <- function(y){y;function(x){y}}
for(i in 1:length(test.func)){
func.list[[i]] <- assign(x=paste("f",i,sep=""),value=makefunc(eval(parse(text=test.func[i]))))
}
Which gives the following error: Error in eval(expr, envir, enclos) : object 'x' not found
The eventual goal is to take the list of functions and apply the jth function to the jth column of the data.frame, so that the user of the script can specify how to normalize each column within the concatenated information given by the column header.
Maybe initialize your list with a single generic function, and then update them using:
foo <- function(x){x+3}
> body(foo) <- quote(x+4)
> foo
function (x)
x + 4
More specifically, starting from a character, you'd probably do something like:
body(foo) <- parse(text = "x+5")
Just to add onto joran's answer, this is what finally worked:
test.data <- matrix(data=rep(1,25),5,5)
test.data <- data.frame(test.data)
test.func <- c("x","x+1","x+2","x+3","x+4")
func.list <- list()
for(i in 1:length(test.func)){
func.list[[i]] <- function(x){}
body(func.list[[i]]) <- parse(text=test.func[i])
}
processed <- mapply(do.call,func.list,lapply(test.data,list))
Thanks again, joran.
This is what I do:
f <- list(identity="x",plus1 = "x+1", square= "x^2")
funCreator <- function(snippet){
txt <- snippet
function(x){
exprs <- parse(text = txt)
eval(exprs)
}
}
listOfFunctions <- lapply(setNames(f,names(f)),function(x){funCreator(x)}) # I like to have some control of the names of the functions
listOfFunctions[[1]] # try to see what the actual function looks like?
library(pryr)
unenclose(listOfFunctions[[3]]) # good way to see the actual function http://adv-r.had.co.nz/Functional-programming.html
# Call your funcions
listOfFunctions[[2]](3) # 3+1 = 4
do.call(listOfFunctions[[3]],list(3)) # 3^2 = 9
attach(listOfFunctions) # you can also attach your list of functions and call them by name
square(3) # 3^2 = 9
identity(7) # 7 ## masked object identity, better detach it now!
detach(listOfFunctions)
I got a bunch dynamically created regressions stored in some list called regressions. Now I´d like to rename their coefficients efficiently. What I have so far is this loop that works:
for (i in 1:length(params[,1])){
names(regressions[[i]]$coefficients)[pos] <- paste(params[i,1],".lag",params[i,2],sep="")
}
I've been trying for quite a while to get this done a little more generally with the help of a function, cause this not the only list of regressions I have. However I could not get anything else to work. Here a few other tries basically based on lapply:
correctNames <- function(reglist,namevec,pos){
names(reglist[[i]]$coefficients)[pos] <- as.character(namevec)
}
lapply(regressions,correctNames(reglist,namevec,pos),
reglist=regressions,namevec=params[,1],pos=2)
Another try was to write a function with a for loop which also works internally as print shows but does not assign the names globally (where the regressions list is stored).
correctNames <- function(reglist,pos,namevec){
for (i in 1:length(params[,1])){
names(reglist[[i]]$coefficients)[pos] <- paste(namevec,".lag",namevec,sep="")
}
#this test proves it's work inside the function...
print(reglist[[10]]
}
Ah, gimme a break.
There's no "i" inside that first version of "correctNames" function; and you probably don't realize that you are not assigning it to "regressions", only to a copy of the regression object. Try instead:
correctNames <- function(reglist,namevec,pos){
names(reglist$coefficients)[pos] <- as.character(namevec)
return(reglist) }
newregs <- mapply(correctNames,
reglist=regressions,
namevec=as.character(params[,1]),
MoreArgs= list( pos=2))
After seeing the note from Ramnath and noticing that the code did work but was giving flaky names for the "params" I looked at params and saw that it was a factor, and so changed the argument in the mapply call to as.character(params[,1]).
> newregs[1,1]
[[1]]
(Intercept) log(M1)
-5.753758 2.178137
If this is a follow up to your earlier question, then here is what I would do
coefs = plyr::ldply(regressions, coef)
coefs = transform(coefs, reg_name = paste(x, '.lag', l, sep = ""))[,-c(1, 2)]
names(coefs) = c('intercept', 'reg_coef', 'reg_name')
This gives you
intercept reg_coef reg_name
1 -5.753758 2.178137 log(M1).lag0
2 7.356434 7.532603 rs.lag0
3 7.198149 8.993312 rl.lag0
4 -5.840754 2.193382 log(M1).lag1
5 7.366914 7.419599 rs.lag1
6 7.211223 8.879969 rl.lag1
7 -5.988306 2.220994 log(M1).lag4
8 7.395494 7.127231 rs.lag4
9 7.246161 8.582998 rl.lag4
Frequently I encounter situations where I need to create a lot of similar models for different variables. Usually I dump them into the list. Here is the example of dummy code:
modlist <- lapply(1:10,function(l) {
data <- data.frame(Y=rnorm(10),X=rnorm(10))
lm(Y~.,data=data)
})
Now getting the fit for example is very easy:
lapply(modlist,predict)
What I want to do sometimes is to extract one element from the list. The obvious way is
sapply(modlist,function(l)l$rank)
This does what I want, but I wonder if there is a shorter way to get the same result?
probably these are a little bit simple:
> z <- list(list(a=1, b=2), list(a=3, b=4))
> sapply(z, `[[`, "b")
[1] 2 4
> sapply(z, get, x="b")
[1] 2 4
and you can define a function like:
> `%c%` <- function(x, n)sapply(x, `[[`, n)
> z %c% "b"
[1] 2 4
and also this looks like an extension of $:
> `%$%` <- function(x, n) sapply(x, `[[`, as.character(as.list(match.call())$n))
> z%$%b
[1] 2 4
I usually use kohske way, but here is another trick:
sapply(modlist, with, rank)
It is more useful when you need more elements, e.g.:
sapply(modlist, with, c(rank, df.residual))
As I remember I stole it from hadley (from plyr documentation I think).
Main difference between [[ and with solutions is in case missing elements. [[ returns NULL when element is missing. with throw an error unless there exist an object in global workspace having same name as searched element. So e.g.:
dah <- 1
lapply(modlist, with, dah)
returns list of ones when modlist don't have any dah element.
With Hadley's new lowliner package you can supply map() with a numeric index or an element name to elegantly pluck components out of a list. map() is the equivalent of lapply() with some extra tricks.
library("lowliner")
l <- list(
list(a = 1, b = 2),
list(a = 3, b = 4)
)
map(l, "b")
map(l, 2)
There is also a version that simplifies the result to a vector
map_v(l, "a")
map_v(l, 1)