Setting an object to itself - r

I am new to R and have a question on the function posted here: R RStudio Resetting debug / function environment. Why are the objects set to themselves (e.g. "getmean = getmean" etc.)? Couldn't it simply be written as follows: list(set, get, setmean, getmean)

The difference is that
aa <- list(set, get, setmean, getmean)
is an unnamed list and
bb <- list(set=set, get=get, setmean=setmean, getmean=getmean)
is a named list. Compare names(aa) and names(bb).
And that = is not assignment. It's really just giving a label to a list item. It's one of the reasons R programmers try to only use <- for assignment and leave = with this special meaning. You could have easily also done
cc <- list(apple=set, banana=get, ornage=setmean, grape=getmean)
cc$apple()
It doesn't have to be the exact same name.

Because list(set, get, setmean, getmean) won't tag the list elements with the correct names. Here's an example of the difference between tagged and untagged lists:
> list(1, 2, 3)
[[1]]
[1] 1
[[2]]
[1] 2
[[3]]
[1] 3
> list(foo=1, bar=2, baz=3)
$foo
[1] 1
$bar
[1] 2
$baz
[1] 3
Note that in the context of argument lists, = is used to supply named arguments, it does not do any assignments (unlike <-). Thus list(foo=1, bar=2, baz=3) is very different from list(foo<-1, bar<-2, baz<-3).

The question has been answered, but you could also do this to achieve the same result.
> object <- c('set', 'get', 'setmean', 'getmean')
> setNames(object = as.list(object), nm = object)
# $set
# [1] "set"
#
# $get
# [1] "get"
#
# $setmean
# [1] "setmean"
#
# $getmean
# [1] "getmean"
The quotations are dependent on what these values actually are.
And you can set different names with like this
> setNames(as.list(object), letters[1:4])
# $a
# [1] "set"
#
# $b
# [1] "get"
#
# $c
# [1] "setmean"
#
# $d
# [1] "getmean"
setNames comes in handy when working with lapply.

Related

R - Naming multiple functions in a for loop

I have the following data frame:
> coc_comp_model[1:3,]
Relationship Output Input |r-Value| Y-Intercept Gradient
1 DG-r ~ DG-cl DG-r DG-cl 0.8271167 0.0027217513 12.9901380
2 CA3-r ~ CA3-cl CA3-r CA3-cl 0.7461309 0.0350767684 27.6107963
3 CA2-r ~ CA2-cl CA2-r CA2-cl 0.9732584 -0.0040992226 35.8299582
I want to create simple functions for each row of the data frame. here's what I've tried:
for(i in 1:nrow(coc_comp_model)) {
coc_glm_f[i] <- function(x)
x*coc_comp_model$Gradient[i] + coc_comp_model$Y-Intercept[i]
}
also tried making a vector of functions, which also does ont work either.
Thanks for reading this/helping.
Something like this:
myfunc<-function(datrow, x){
x*as.numeric(datrow[6]) + as.numeric(datrow[5] )
}
Then you can use apply to call it on each row, changing x as desired:
apply(hzdata, 1, myfunc, x = 0.5)
note: using dput() to share your data is much easier than a pasting in a subset.
There is no such thing as a vector of functions. There are 6 atomic vector types in R: raw, logical, integer, double, complex, and character, plus there is the heterogeneous list type, and finally there is the lesser known expression type, which is basically a vector of parse trees (such as you get from a call to the substitute() function). Those are all the vector types in R.
printAndType <- function(x) { print(x); typeof(x); };
printAndType(as.raw(1:3));
## [1] 01 02 03
## [1] "raw"
printAndType(c(T,F));
## [1] TRUE FALSE
## [1] "logical"
printAndType(1:3);
## [1] 1 2 3
## [1] "integer"
printAndType(as.double(1:3));
## [1] 1 2 3
## [1] "double"
printAndType(c(1i,2i,3i));
## [1] 0+1i 0+2i 0+3i
## [1] "complex"
printAndType(letters[1:3]);
## [1] "a" "b" "c"
## [1] "character"
printAndType(list(c(T,F),1:3,letters[1:3]));
## [[1]]
## [1] TRUE FALSE
##
## [[2]]
## [1] 1 2 3
##
## [[3]]
## [1] "a" "b" "c"
##
## [1] "list"
printAndType(expression(a+1,sum(1,2+3*4),if (T) 1 else 2));
## expression(a + 1, sum(1, 2 + 3 * 4), if (T) 1 else 2)
## [1] "expression"
If you want to store multiple functions in a single object, you have to use a list, and you must use the double-bracket indexing operator in the lvalue to assign to it:
fl <- list();
for (i in 1:3) fl[[i]] <- (function(i) { force(i); function(a) a+i; })(i);
fl;
## [[1]]
## function (a)
## a + i
## <environment: 0x600da11a0>
##
## [[2]]
## function (a)
## a + i
## <environment: 0x600da1ab0>
##
## [[3]]
## function (a)
## a + i
## <environment: 0x600da23f8>
sapply(fl,function(f) environment(f)$i);
## [1] 1 2 3
sapply(fl,function(f) f(3));
## [1] 4 5 6
In the above code I also demonstrate the proper way to closure around a loop variable. This requires creating a temporary function evaluation environment to hold a copy of i, and the returned function will then closure around that evaluation environment so that it can access the iteration-specific i. This holds true for other languages that support dynamic functions and closures, such as JavaScript. In R there is an additional requirement of forcing the promise to be resolved via force(), otherwise, for each generated function independently, the promise wouldn't be resolved until the first evaluation of that particular generated function, which would at that time lock in the current value of the promise target (the global i variable in this case) for that particular generated function. It should also be mentioned that this is an extremely wasteful design, to generate a temporary function for every iteration and evaluate it, which generates a new evaluation environment with a copy of the loop variable.
If you wanted to use this design then your code would become:
coc_glm_f <- list();
for (i in 1:nrow(coc_comp_model)) {
coc_glm_f[[i]] <- (function(i) { force(i); function(x) x*coc_comp_model$Gradient[i] + coc_comp_model$`Y-Intercept`[i]; })(i);
};
However, it probably doesn't make sense to create a separate function for every row of the data.frame. If you intended the x parameter to take a scalar value (by which I mean a one-element vector), then you can define the function as follows:
coc_glm_f <- function(x) x*coc_comp_model$Gradient + coc_comp_model$`Y-Intercept`;
This function is vectorized, meaning you can pass a vector for x, where each element of x would correspond to a row of coc_comp_model. For example:
coc_comp_model <- data.frame(Relationship=c('DG-r ~ DG-cl','CA3-r ~ CA3-cl','CA2-r ~ CA2-cl'),Output=c('DG-r','CA3-r','CA2-r'),Input=c('DG-cl','CA3-cl','CA2-cl'),`|r-Value|`=c(0.8271167,0.7461309,0.9732584),`Y-Intercept`=c(0.0027217513,0.0350767684,-0.0040992226),Gradient=c(12.9901380,27.6107963,35.8299582),check.names=F);
coc_glm_f(seq_len(nrow(coc_comp_model)));
## [1] 12.99286 55.25667 107.48578

subclassing S4 class that contains a list with names: access by name

The puzzle is accessing elements of a list in the object's "pseudo-slot".
That's successful using 2 out of 4 approaches one might try:
setClass("TempA", contains="list")
A = new("TempA", list(a=1,b=2))
A
Just printing A does not show the list names.
## An object of class "TempA"
## [[1]]
## [1] 1
##
## [[2]]
## [1] 2
Nevertheless, you can extract the elements by name.
A[["b"]]
## [1] 2
And names() extracts the names.
names(A)
## [1] "a" "b"
But there are no names here in the pseudo-slot.
A#.Data
## [[1]]
## [1] 1
##
## [[2]]
## [1] 2
So where are the names hiding, if not in the pseudo-slot itself?
The plot thickens. My goal is to subclass (to add some slots; not shown here).
But if we subclass, even the two successful approaches above now fail. The list's names are apparently nowhere.
setClass("TempB", contains="TempA")
B = new("TempB", list(a=1,b=2))
names(B) ## no names.
## NULL
B[["b"]] ## NULL
## NULL
Here's a different approach. Does this do it? Nope.
B2 = new("TempB", new("TempA", list(a=1,b=2)))
B2[["a"]] # NULL
## NULL
names(B2) # NULL
## NULL
names(as(B2, "TempA")) ## still no dice
## NULL
In summary, when the pseudo-slot is a named list, trying to view or use those names is successful for only 2 out of 4 obvious approaches, and zero out of the 4 after subclassing. Working around the problem is not the issue; that's pretty easy. (Though I'd like to know how to write an accessor for a TempB object using the names.) I just want to understand.
S4 implements slots as attributes, while R stores names of list elements as an attribute on the list. There is thus a conflict, mentioned in ?Classes. The 'solution' is to create a class with a 'names' slot
A = setClass("A", representation("list", names="character"))
but this also requires explicit management of the names, e.g.,
setMethod("[", c("A", "ANY", "missing", "missing"),
function(x, i, j, ..., drop=TRUE)
{
initialize(x, x#.Data[i], names=names(x)[i], ...)
})
Leading to
> a = A(list(a=1, b=2))
> a[2:1]
An object of class "A"
[[1]]
[1] 2
[[2]]
[1] 1
Slot "names":
[1] "b" "a"
but also obviously incomplete
> a[20]
An object of class "A"
[[1]]
NULL
Slot "names":
[1] NA
Ah, Martin, your answer led me to some discoveries that surprised me! Thank you. Pointing me to look at the instance's attributes was key. I'd missed that paragraph in ?Classes.
The following shows that the names attribute of the list in the .Data slot transfers to the instance itself:
attributes(A)$names
## [1] "a" "b"
So, do ALL attributes move from the .Data slot to the instance? Yes indeed!
tempList = list(a=3, b=4)
attributes(tempList)$dummy = "dummy"
E = new("TempA", tempList)
attributes(E)$names
## $names
## [1] "a" "b"
##
attributes(E)$dummy
## $dummy
## [1] "dummy"
attributes(E#.Data)
## NULL
Well, not all attributes. The results with object B2 above in the original question show that, if the .Data item is itself an instance, its attributes do not transfer to the containing instance.
That still leaves open a question. Of course you don't want to transfer the $class attribute! But why not transfer all the other attributes?

Using do.call to call a list of functions

I am having trouble figuring out how to use do.call to call and run a list of functions.
for example:
make.draw = function(i){i;function()runif(i)}
function.list = list()
for (i in 1:3) function.list[[i]] = make.draw(i)
will result in
> function.list[[1]]()
[1] 0.2996515
> function.list[[2]]()
[1] 0.7276203 0.4704813
> function.list[[3]]()
[1] 0.9092999 0.7307774 0.4647443
what I want to do is create a function that calls all three functions in the list at one go. from what I understand as.call() can be used to do this but I am having trouble connecting the dots and getting 6 uniform random draws from function.list.
Did you want something like this?
lapply(function.list, do.call, list())
# [[1]]
# [1] 0.5777857
# [[2]]
# [1] 0.8970102 0.5892031
# [[3]]
# [1] 0.4712016 0.2624851 0.2353192
make.draw = function(i){runif(i)}
Map(make.draw, 1:3)
#[[1]]
#[1] 0.03442084
#[[2]]
#[1] 0.6899443 0.8896434
#[[3]]
#[1] 0.3899678 0.2845898 0.4920698

Assigning list attributes in an environment

The title is the self-contained question. An example clarifies it: Consider
x=list(a=1, b="name")
f <- function(){
assign('y[["d"]]', FALSE, parent.frame() )
}
g <- function(y) {f(); print(y)}
g(x)
$a
[1] 1
$b
[1] "name"
whereas I would like to get
g(x)
$a
[1] 1
$b
[1] "name"
$d
[1] FALSE
A few remarks. I knew what is wrong in my original example, but am using it to make clear my objective. I want to avoid <<-, and want x to be changed in the parent frame.
I think my understanding of environments is primitive, and any references are appreciated.
The first argument to assign must be a variable name, not the character representation of an expression. Try replacing f with:
f <- function() with(parent.frame(), y$d <- FALSE)
Note that a, b and d are list components, not list attributes. If we wanted to add an attribute "d" to y in f's parent frame we would do this:
f <- function() with(parent.frame(), attr(y, "d") <- FALSE)
Also, note that depending on what you want to do it may (or may not) be better to have x be an environment or a proto object (from the proto package).
assign's first argument needs to be an object name. Your use of assign is basically the same as the counter-example at the end of the the assign help page. Observe:
> x=list(a=1, b="name")
> f <- function(){
+ assign('x["d"]', FALSE, parent.frame() )
+ }
> g <- function(y) {f(); print(`x["d"]`)}
> g(x)
[1] FALSE # a variable with the name `x["d"]` was created
This may be where you want to use "<<-" but it's generally considered suspect.
> f <- function(){
+ x$d <<- FALSE
+ }
> g <- function(y) {f(); print(y)}
> g(x)
$a
[1] 1
$b
[1] "name"
$d
[1] FALSE
A further thought, offered in the absence of any goal for this exercise and ignoring the term "attributes" which Gabor has pointed out has a specific meaning in R, but may not have been your goal. If all you want is the output to match your specs then this achieves that goal but take notice that no alteration of x in the global environment is occurring.
> f <- function(){
+ assign('y', c(x, d=FALSE), parent.frame() )
+ }
> g <- function(y) {f(); print(y)}
> g(x)
$a
[1] 1
$b
[1] "name"
$d
[1] FALSE
> x # `x` is unchanged
$a
[1] 1
$b
[1] "name"
The parent.frame for f is what might be called the "interior of g but the alteration does not propagate out to the global environment.

Create "missing objects" (aka: "empty symbols" , "empty objects") / needed for formals manipulation/

How to create an "empty object" in R? [edit: I don't know how to rightly call this "thing" so I am calling it "empty object", others: "empty symbol", "zero length symbol", "missing object" might also be used]
[edit2: finally I tend to settle down on the "missing symbol object" for the name of the "thing". It also appears that J.Chambers is using this terminology in his 2008 book, see comments for #mbq's answer. According to Chambers, the "missing symbol" has a zero-length string as it's contents. Thus, as.symbol("") should create such an object, which it doesn't in current version of R(2.11.1) ]
The simplest way I could find is
x <- alist(a=)$a
[Clarification]
Note that "empty object" is not a NULL object or a vector of length 0.
"Empty object" x in my above example could be used in the function's formals manipulation, which is what I need it for.
Here is an example:
> al <- alist(a = 323, b = , c = 434)
> al
$a
[1] 323
$b
$c
[1] 434
>
> al[["c"]] <- numeric()
> al
$a
[1] 323
$b
$c #not empty
numeric(0)
>
> al[["c"]] <- list()
> al
$a
[1] 323
$b
$c #not empty
list()
>
>
> al[["c"]] <- NULL #object removed
> al
$a
[1] 323
$b
>
> al[["c"]] <- alist(a = )$a
> al
$a
[1] 323
$b
$c #empty
So, I am just looking for a way to create empty objects for use in function's formals manipulations. I am pretty sure there must be a way in base R.
Here is an example:
> foo <- function(a = 3232, b = 234){b+a}
> formals(foo)
$a
[1] 3232
$b
[1] 234
> formals(foo)$c <- alist(a = )$a
> formals(foo)
$a
[1] 3232
$b
[1] 234
$c
> foo <- function(a = 3232, b = 234){b+a}
> formals(foo)
$a
[1] 3232
$b
[1] 234
> formals(foo)$c <- alist(a = )$a
> formals(foo)
$a
[1] 3232
$b
[1] 234
$c
Thanks.
Try substitute():
foo <- function(a = 3232, b = 234) {}
formals(foo)$c <- substitute()
foo
# function (a = 3232, b = 234, c)
What have you done with alist(a=)$a is not an empty object, it is empty symbol/name ('' compiled as symbol name). I'm pretty sure it can't be replicated in any other way (as.symbol('') raises error).
As others have said, you're not creating an empty object. x holds a value, which is an unevaluated expression.
?alist says:
‘alist’ handles its arguments as if they described function arguments.
So the values are not evaluated, and tagged arguments with no value are
allowed whereas ‘list’ simply ignores them. ‘alist’ is most often used in
conjunction with ‘formals’.
This is the easiest way I can determine to add an argument with no value to a function:
> foo <- function(a = 3232, b = 234){b+a}
> formals(foo) <- c(formals(foo),alist(c=))
> formals(foo)
$a
[1] 3232
$b
[1] 234
$c
Depending on the type :
x <- list()
# empty vectors
y <- numeric(0)
z <- logical(0)
...
Now you have to think whether you really want to create an empty object.
edit : You can indeed use the NULL option as well. The main difference is that the NULL object doesn't have a type. See also ?"NULL"
There is no 'empty object'. There's NULL, NA (in various flavours), zero-length lists and so on. Where does your concept of 'empty object' come from, and what are the properties of an 'empty object'?
What you have created with alist is a monster:
> x<-alist(a=)$a
> x
Error: argument "x" is missing, with no default
[its some kind of unevaluated function argument expression thing. Not an 'empty object' in any sense of the word I know]
Also d <- c()
Also d <- ""
(padding padding padding)

Resources