How to use lapply to size objects in environment? - r

I want to make a table with all the dim() of objects in the environment. ls() returns a list of characters which lapply will not take as object names and operate properly on. What to do? Using R.
> lapply(ls(), dim)
just returns
[[1]]
NULL

You may use parse and eval to change the string vector to env objects and then use dim.
lapply(ls(), function(x) dim(eval(parse(text=x))))

1) Use eapply and then optionally use Filter to remove components with no dim. This creates a named list with the dimensions in the corresponding components.
Filter(length, eapply(.GlobalEnv, dim))
2) A variation would be to create a matrix result such that the row names are the variable names.
do.call("rbind", eapply(.GlobalEnv, dim))
3) or to restrict the output to data frames and not arrays (as arrays might cause problems if there are arrays not of two dimensions) then:
df_dim <- function(x) if (is.data.frame(x)) dim(x)
do.call("rbind", eapply(.GlobalEnv, df_dim))
4) or to restrict it to objects having 2 dimensions including both data frames and arrays:
two_dim <- function(x, dimx = dim(x)) if (length(dimx) == 2) dimx
do.call("rbind", eapply(.GlobalEnv, two_dim))
or
do.call("rbind", Filter(function(x) length(x) == 2, eapply(.GlobalEnv, dim)))

Related

Addressing to subsequent objects in loop function in R

I need to create a loop function in which I need to address to subsequent objects which names end with numbers i.e. object1, object 2, object3. So the code should look like this:
object1 <- c(1,2,3,4,5)
object2 <- c(2,3,4,5,6)
object3 <- c(3,4,5,6,7)
for (i in 1:3) {
assign (paste0("new_object",i), mean(object???))
}
So I need a equivalent to just typing
new_object1 <- mean(object1)
new_object2 <- mean(object2)
new_object3 <- mean(object3)
Many thanks in advance!
It would be get to return the values of that object by pasteing the 'i' with the 'object' string
for (i in 1:3) {
assign(paste0("new_object",i), mean(get(paste0('object', i)))
}
But, it is not a recommended way as it is creating new objects in the global env.
Instead, if the intention is to get the mean of all the 'object's,
sapply(mget(paste0("object", 1:3)), mean)
Or if there are more than three, use ls with pattern
sapply(mget(ls(pattern = '^object\\d+$')), mean)
Here, mget returns the value of more than one objects in a list, loop through the list with sapply and apply the mean function on the list element.
Creating objects can also be done from the list with list2env
out <- lapply( mget(ls(pattern = '^object\\d+$')), mean)
names(out) <- paste0('new_', names(out))
list2env(out, .GlobalEnv) # not recommended based on the same reason above

remove names of several objects in R

I have many irregularly named objects whose names, in order to be able to use some other package, I need to set to NULL.
E.g.,
v <- 1
w <- 2
names(v) <- "hello"
names(w) <- "world"
I can write
names(v) <- names(w) <- NULL
but for succinctness I would prefer something like
names(c(v,w)) <- NULL
which however does not work ("Error in names(c(v, w)) <- NULL : could not find function "c<-"). This is not unexpected, of course - from ?names: it is a function "to get or set the names of an object".
One option is to place it in a list and set the names to NULL. It is better not to have multiple objects in the global environment
lst1 <- lapply(list(v = v, w = w), setNames, NULL)
Also, as #joran mentioned, unname can be used as well or as.vector (which remove the attributes)
lst1 <- lapply(list(v = v, w = w), unname)
If the intention is to change the already existing objects,
list2env(lst1, envir = .GlobalEnv)
v
#[1] 1
It is better not to create multiple objects in the global env

Loop over elements in vector, and elements are matrices

I started using R today, so I apologize if this is too basic.
First I construct 2 matrices, and construct a vector, whose entries are these matrices. Then, I try to loop over the elements of the vector, i.e. the matrices. However, when I do, I get a "argument of length zero" error.
cam <- 1:12
ped <- 13:24
dim(cam) <- c(3,4)
dim(ped) <- c(4,3)
mats <- c('cam','ped')
for (i in 1:2) {
rownames(mats[i]) <- LETTERS[1:dim(mats[i])[1]]
colnames(mats[i]) <- LETTERS[1:dim(mats[i])[2]]
}
The error text is as follows:
Error in 1:dim(mats[i])[1] : argument of length 0
The question: how to loop over elements of a vector, these elements being matrices? (I'm guessing I'm not calling the elements correctly). Thank you for patience.
The go-to option in R is to use lists:
cam <- 1:12 ; dim(cam) <- c(3,4)
# same as matrix(1:12, nrow = 3, ncol = 4)
ped <- 13:24 ; dim(ped) <- c(4,3)
# save the list ( '=' sign for naming purposes only here)
mats <- list(cam = cam, ped = ped)
# notice the double brackets '[[' which is used for picking the list
for (i in 1:length(mats) {
rownames(mats[[i]]) <- LETTERS[1:dim(mats[[i]])[1]]
colnames(mats[[i]]) <- LETTERS[1:dim(mats[[i]])[2]]
}
# finally you can call the whole list at once as follows:
mats
# or seperately using $ or [[
mats$cam # mats[['cam']]
mats$ped # mats[['ped']]
ALTERNATIVELY
If you really want to get crazy you can take advantage of the get() and assign() functions. get() calls an object by character, and assign() can create one.
mats <- c('cam','ped')
mats.new <- NULL # initialize a matrix placeholder
for (i in 1:length(mats)) {
mats.new <- get(mats[i]) # save as a new matrix each loop
# use dimnames with a list input to do both the row and column at once
dimnames(mats.new) <- list(LETTERS[1:dim(mats.new)[1]],
LETTERS[1:dim(mats.new)[2]])
assign(mats[i],mats.new) # create (re-write) the matrix
}
If the datasets are placed in a list we can use lapply
lst <- lapply(mget(mats), function(x) {
dimnames(x) <- list(LETTERS[seq_len(nrow(x))], LETTERS[seq_len(ncol(x))])
x})
It is better to keep it in a list. In case the original objects needs to be changed
list2env(lst, envir = .GlobalEnv)

Update first value in each list element in R

I would like to replace the first value in each list element with the second value from the same element.
For example I would like a function to transform lst into lst2
lst<-list(c(0:4),c(5:9))
lst
lst2<-list(c(1, c(1:4)),c(6,c(6:9)))
lst2
I know that I can do
lst[[1]][1]=lst[[1]][2]
lst[[2]][1]=lst[[2]][2]
But I would like a function to iterate over all list elements. I have tried various things (all unsuccessful) with lapply such as:
lapply(list, function(x) x[1]=x[2])
We can use lapply to loop over the list and we need to return the x if we are using anonymous function call.
lstN <- lapply(lst, function(x) {x[1] <- x[2]
x})
identical(lst2, lstN)
#[1] TRUE

How to make the elements of a matrix callable functions

I want to make a matrix of functions (that I wrote). Then access them element wise and call.
So I have : func1(x) , func2(y), func3(z) and func4(t) that are four R functions I wrote that work fine.They return numerics.
Now if I do:
a_matrix <- matrix(c(a=func1,b=func2,c=func3,d=func4),2,2)
a_func<-a_matrix[1,1]
a_func(x)
I get the following error:
error:attempt to call non-function.
Instead of matrix if I use list,
a_list<-list(a=func1,b=func2,c=func3,d=func4)
a_func<-list$a
a_func(x)
gives expected result
typeof(list$a)
[1] "closure"
If I do :
typeof(a_matrix)
[1] "list"
typeof(a_matrix[1,1])
[1] "list"
(am using R 3.1.1)
When you create non-atomic matrices like that, they are basically made into fancy lists. Similar rules apply to these lists as to regular lists when it comes to indexing; namely that [ ] will always return another list, and [[ ]] will extract the element without the list wrapper. You really want
func1 <- function(x) x+1
func2 <- function(x) x+2
func3 <- function(x) x+3
func4 <- function(x) x+4
a_matrix <- matrix(c(a=func1,b=func2,c=func3,d=func4),2,2)
a_func <- a_matrix[[1,1]]
a_func(5)
# [1] 6
You'd get the same results with your standard list syntax if you did
a_list <- list(a=func1,b=func2,c=func3,d=func4)
a_func <- a_list["a"]
a_func(5)
# Error: could not find function "a_func"
a_func <- a_list[["a"]]
a_func(5)
# [1] 6

Resources