R - using the assign() function for subsetting an array - r

I have tried to get the gist of my problem in the following reproducible example :
mat <- matrix(3:6,nr=2,nc=2)
j=1
> eval(parse(text=paste0("m",c("a","b")[j],"t","[1,1]")))
[1] 3
> assign(paste0("m",c("a","b")[j],"t","[1,1]"),45)
> mat
[,1] [,2]
[1,] 3 5
[2,] 4 6
My problem is that mat[1,1] is still equal to 3 and not 45 as I would have expected.

A primer on R: "Every operation is a function call." What this means, in a practical sense for your question, is that you can't use assign() with more than just a name. mat[1,1] is not a name - it is the name mat and the function call [. So, using the expression mat[1,1] within assign will not work, because it is trying to find an R object named mat[1,1] (which I think is disastrous for a few reasons...)
This seems like a really weird use case. You might want to consider instead working in a function, which has its own environment that you can manipulate without working in the global environment.
Alternatively, you can do this:
eval(parse(text=paste0("m",c("a","b")[j],"t","[1,1] <- 45")))
eval(parse(text=paste0("m",c("a","b")[j],"t","[1,1]")))
I am struggling to think of a reason you would want to - but it is, in theory, possible. Basically, you just add the assignment to the text that you are parsing, then pass it to eval().

Related

How does the `[<-` function work in R?

I've seen a couple of people using [<- as a function with Polish notation, for example
x <- matrix(1:4, nrow = 2)
`[<-`(x, 1, 2, 7)
which returns
[,1] [,2]
[1,] 1 7
[2,] 2 4
I've tried playing around with [<- a little, and it looks like using it this way prints the result of something like x[1,2] <- 7 without actually performing the assignment. But I can't figure out for sure what this function actually does, because the documentation given for ?"[" only mentions it in passing, and I can't search google or SO for "[<-".
And yes, I know that actually using it is probably a horrible idea, I'm just curious for the sake of a better understanding of R.
This is what you would need to do to get the assignment to stick:
`<-`( `[`( x, 1, 2), 7) # or x <- `[<-`( x, 1, 2, 7)
x
[,1] [,2]
[1,] 1 7
[2,] 2 4
Essentially what is happening is that [ is creating a pointer into row-col location of x and then <- (which is really a synonym for assign that can also be used in an infix notation) is doing the actual "permanent" assignment. Do not be misled into thinking this is a call-by-reference assignment. I'm reasonably sure there will still be a temporary value of x created.
Your version did make a subassignment (as can be seen by what it returned) but that assignment was only in the local environment of the call to [<- which did not encompass the global environment.
Since `[`(x, y) slices an object, and `<-`(x, z) performs assignment, it seems like `[<-`(x,y,z) would perform the assignment x[y] <- y. #42-'s answer is a great explanation of what [<- actually does, and the top answer to `levels<-`( What sorcery is this? provides some insight into why R works this way.
To see what [<- actually does under the hood, you have to go to the C source code, which for [<- can be found at http://svn.r-project.org/R/trunk/src/main/subassign.c (the relevant parts start at around line 1470). You can see that x, the object being "assigned to" is protected so that only the local version is mutated. Instead, we're using VectorAssign, MatrixAssign, ArrayAssign, etc. to perform assignment locally and then returning the result.

Why did a show up in my table name?

I ran this in R:
a <- factor(c("A","A","B","A","B","B","C","A","C"))
And then I made a table
results <- table(a)
but when I run
> attributes(results)
$dim
[1] 3
$dimnames
$dimnames$a
But I'm confused why does a show up in my attributes? I've programmed in Java before and I thought variable names weren't supposed to show up in your functions .
R functions can not only see the data you pass to them, but they can see the actual call that was run to invoke them. So when you run, table(a) the table() function not only sees the values of a, but is also can see that those values came from a variable named a.
So by default table() likes to name each dimension in the resulting table. If you don't pass explicit names in the call via the dnn= parameter, table() will look back to the call, and turn the variable name into a character and use that value for the dimension name.
So after table() has ran, it has no direct connection to the variable a, it merely used the name of that variable as a character label of the results.
Many functions in R do this. For example this is similar to how plot(height~weight, data=data.frame(height=runif(10), weight=runif(10))) knows to use the names "weight" and "height" for the axis labels on the plot.
Here's a simple example to show one way this can be accomplished.
paramnames <- function(...) {
as.character(substitute(...()))
}
paramnames(a,b,x)
# [1] "a" "b" "x"
I think the only answer is because the designers wanted it that way. It seems reasonable to label table objects with the names of variables that formed the margins:
> b <- c(1,1,1,2,2,2, 3,3,3)
> table(a, b)
b
a 1 2 3
A 2 1 1
B 1 2 0
C 0 0 2
R was intended as a clone of S, and S was intended as a tool for working statisticians. R also has a handy function for working with table objects, as.data.frame:
> as.data.frame(results)
a Freq
1 A 4
2 B 3
3 C 2
If you want to build a function that performs the same sort of labeling or that otherwise retrieves the name of the object passed to your function then there is the deparse(substitute(.))-maneuver:
myfunc <- function(x) { nam <- deparse(substitute(x)); print(nam)}
> myfunc <- function(x) { nam <- deparse(substitute(x)); print(nam)}
> myfunc(z)
[1] "z"
> str(z)
Error in str(z) : object 'z' not found
So "z" doesn't even need to exist. Highly "irregular" if you ask me. If you "ask" myfunc what its argument list looks like you get the expected answer:
> formals(myfunc)
$x
But that is a list with an R-name for its single element x. R names are language elements, whereas the names function will retrieve it as a character value, "x", which is not a language element:
> names(formals(myfunc))
[1] "x"
R has some of the aspects of Lisp (interpreted, functional (usually)) although the dividing line between its language functions and the data objects seems less porous to me, but I'm not particularly proficient in Lisp.

Is there a way to use a variable without the need of defining it (in R)?

I use following code:
tempdata <- rbind(tempdata,newdata) # bind rowwise
as far as I know, tempdata (like all objects, variables, ...) needs to be defined. Because there are only numerical values, I define it as tempdata<-0. It's not a really big problem, but when using rbind afterwards, the first row with 0 is kept at the first place and I have to use some kind of
tempdata<-tempdata[-1,] # deletes first row
I can't define it as tempdata<-'', because this would be a character, right?
Well as I said, not really a problem for me, but would there be a better way, especially if I or someone would use rbind() many times in the code and therefore maybe the first row has to be "cleared" not only once...
The same could be a problem when using cbind().
Maybe someone knows a better solution?
If you are using rbind/cbind to build some results from an iterative procedure, you may declare the "empty" object to store the data in. For numeric data, use numeric(0), which is a zero-length numeric vector. It is compatible with any binding:
rbind(numeric(0), 1:3)
[,1] [,2] [,3]
[1,] 1 2 3
cbind(numeric(0), 1:3)
[,1]
[1,] 1
[2,] 2
[3,] 3
The same holds for NULL (as pointed by #jbaums). It may even be more convenient since you don't have to specify the data type manually (the same will also work with numeric(0) due to implicit type conversion):
rbind(NULL, letters[1:3])
[,1] [,2] [,3]
[1,] "a" "b" "c"

In R, how to use values as the variable names

I know the function get can help you transform values to variable names, like get(test[1]). But I find it is not compatible when the values is in a list format. Look at below example:
> A = c("obj1$length","obj1$width","obj1$height","obj1$weight")
> obj1 <- NULL
> obj1$length=c(1:4);obj1$width=c(5:8);obj1$height=c(9:12);obj1$weight=c(13:16)
> get(A[1])
Error in get(A[1]) : object 'obj1$length' not found
In this case, how can I retrieve the variable name?
get doesn't work like that you need to specify the variable and environment (the list is coerced to one) separately:
get("length",obj1)
[1] 1 2 3 4
Do do it with the data you have, you need to use eval and parse:
eval(parse(text=A[1]))
[1] 1 2 3 4
However, I suggest you rethink your approach to the problem as get, eval and parse are blunt tools that can bite you later.
I think that eval() function will do the trick, among other uses.
eval(A[1])
>[1] 1 2 3 4
You could also find useful this simple function I implemented (based in the commonly used combo eval, parse, paste):
evaluate<-function(..., envir=.GlobalEnv){ eval(parse(text=paste( ... ,sep="")), envir=envir) }
It concatenates and evaluates several character type objects. If you want it to be used inside another function, add at the begining of your function
envir <- environment()
and use it like this:
evaluate([some character objects], envir=envir)
Try, for example
myvariable1<-"aaa"; myvariable2<-"bbb"; aaa<-15; bbb<-3
evaluate(myvariable1," * ",myvariable2).
I find it very usefull when I have to evaluate similar sentences with several variables, or when I want to create variables with automatically generated names.
for(i in 1:100){evaluate("variable",i,"<-2*",i)}

Scoping problem when sfApply is used within function (package snowfall - R)

Let me add another scoping problem in R, this time with the snowfall package. If I define a function in my global environment, and I try to use that one later in an sfApply() inside another function, my first function isn't found any more :
#Runnable code. Don't forget to stop the cluster with sfStop()
require(snowfall)
sfInit(parallel=TRUE,cpus=3)
func1 <- function(x){
y <- x+1
y
}
func2 <- function(x){
y <- sfApply(x,2,function(i) func1(i) )
y
}
y <- matrix(1:10,ncol=2)
func2(y)
sfStop()
This gives :
> func2(y)
Error in checkForRemoteErrors(val) :
2 nodes produced errors; first error: could not find function "func1"
If I nest my function inside the other function however, it works. It also works when I use the sfApply() in the global environment. Thing is, I don't want to nest my function func1 inside that function2, as that would cause that func1 is defined many times (func2 is used in a loop-like structure).
I've tried already simplifying the code to get rid of the double looping, but that's quite impossible due to the nature of the problem. Any ideas?
I think you want to sfExport(func1), though I'm not sure if you need to do it in your .GlobalEnv or inside of func2. Hope that helps...
> y <- matrix(1:10,ncol=2)
> sfExport(list=list("func1"))
> func2(y)
[,1] [,2]
[1,] 2 7
[2,] 3 8
[3,] 4 9
[4,] 5 10
[5,] 6 11
Methinks you are now confusing scoping with parallel computing. You are invoking new R sessions---and it is commonly your responsibility to re-create your environment on the nodes.
An alternative would be to use foreach et al. There has examples in the foreach (or iterator ?) docs that show exactly this. Oh, see, and Josh has by now recommended the same thing.

Resources