Converting specific parts of lists to a dataframe - r

I have a large list of 2 elements containing lists of species containing lists of 25 vectors, resembling a set like this:
l1 <- list(time=runif(100), space=runif(100))
l2 <- list(time=runif(100), space=runif(100))
list1 <- list(test1=list(species1=l1, species2=l2),test2=list(species1=l1, species2=l2))
I think, its essentially a list of a list of lists.of vectors.
I want to create a data.frame from all space-vectors of all 'species' in just one of the two sublists:
final <- as.data.frame(cbind(unlist(list1[[2]]$species1$space), unlist(list1[[2]]$species2$space)))
names(final) <- names(list1[[2]])
Essentially, i need a loop/apply command that navigates me through list1[[2]]$species and picks all vectors called space.
Thank you very much!

We can use a nested loop to extract the 'space' elements
data.frame(lapply(list1, function(x)
sapply(x, "[", 'space')))

Related

Assign names to sublists in a list

I have a list that contains three sublists, each of those sublists containing two objects.
Now I am looking for an efficent way to assign names to those objects in the sublists. In this case, the single objects of each sublist are supposed to have the same names (Matrix1 and Matrix2).
Here is a easy reproducible example:
# create random matrices
matrix1 <- matrix(rnorm(36),nrow=6)
matrix2 <- matrix(rnorm(36),nrow=6)
# combine the matrices to three lists
sublist1 <- list(matrix1, matrix2)
sublist2 <- list(matrix1, matrix2)
sublist3 <- list(matrix1, matrix2)
# combine the lists to one top list
Toplist <- list(sublist1, sublist2, sublist3)
I can do this by using a for loop:
# assign names via for loop
for (i in 1:length(Toplist)) {
names(Toplist[[i]]) <- c("Matrix1", "Matrix2")
}
I am sure there must be a more elegant way using a nested lapply command. But I struggled to implement the names() command inside it.
Anybody with a hint?
Try lapply(Toplist,setNames,c("a","b")).

How can I run a for loop that subsets multiple lists all of which contain dataframes

I have 5 lists called "nightclub", "hospital", "bar", "attraction", "social_facility" all of which contain a data frame called osm_points. I want to create a new list with 5 dataframes with the names of the original dataframes that only contain 3 vectors "osm_id","name","addr.postcode" with no NA values for the vector "addr.postcode". Below is my attempted code, I do not know another way to subset lists without $ (which gives me an error for having an atomic vector), or without the square brackets. Let know if you guys have some advice.
vectors <- c("osm_id","name","addr.postcode")
features <- c("nightclub", "hospital", "bar", "attraction", "social_facility")
datasets <- list()
n <- 0
for (i in features){
n <- n + 1
datasets[[n]] <- paste(i)[["osm_points"]][!is.na(paste(i)[["osm_points"]][["addr.postcode"]]), variables]
}
I managed to do this operation without a for loop (below), but I want to be able to code better and do it all in one operation. Thanks so much for your help.
nightclub1 <- nightclub$osm_points[!is.na(nightclub$osm_points$addr.postcode), variables]
Thanks !!
Try this code using lapply :
result <- lapply(mget(features), function(x)
x$osm_points[!is.na(x$osm_points$addr.postcode), vectors])
result should have list of 5 dataframe one for each features with only vectors column and without NA value for addr.postcode.
You need to put your lists into a list to have something to iterate over.
As you have it, features is a character vector. In your first iteration i is "nightclub", a string. paste(i) changes nothing, it is still "nightclub". So your code becomes "nightclub"[["osm_points"]]..., but you need nightclub[["osm_points"]].
## make a list of lists
list_of_lists <- mget(features)
## then you can do
for(i in seq_along(list_of_lists)) {
datasets[[i]] <- list_of_lists[[i]][["osm_points"]]...
}
Substituting list_of_lists[[i]] wherever you currently have paste(i).

Remove Non-Matching Dataframe Names Nested in A List

I have two lists consisting of dataframes - df_quintile and disease_df_quintile. I do not know how to represent them concisely, but this is how they look like in Rstudio:
Notice, disease_df_quintile consists of 5 dataframes (dataframes 1 through 5), while disease_df_quintile consists of 4 (dataframes 2 through 5). I would like to cross check both lists and remove any dataframes that are not shared by both lists - so in this case, I would like to remove the first dataframe from the df_quintile list. How can I achieve this?
Thank you.
Independently of the content of the list, you can first find the repeated names and then subsetting the lists:
##-- Fake lists
l1 <- as.list(1:5)
names(l1) <- 1:5
l2 <- as.list(2:5)
names(l2) <- 2:5
##-- Common names and subsetting
common_names <- intersect(names(l1), names(l2))
l1 <- l1[common_names]
l2 <- l2[common_names]
You can match the list's names and keep the common ones.
keep <- match(names(disease_df_quintile), names(df_quintile))
new_df_quintile <- df_quintile[keep]

How to split a list of vectors to sub-lists by increasing order.

I have a list of n vectors. I would like to split it to sub-list where the number of the vectors at each list is different. The number of the vectors is increased sequentially from one list to another. For example,
if I have a list with 6 vectors. Then, I would like to split it to several list as follows:
The first list contains one vector. Then, the second list contains 2 vectors and so on. For example,
Suppose I have the list x as follows:
x <- list(x1=c(1,2,3), x2=c(1,4,3), x3=c(3,4,6), x4=c(4,8,4), x5=c(4,33,4), x6=c(9,6,7))
Then, I would like to split it into 3 lists,
list1 = x1
list2 = list(x2, x3)
list3 = list(x4,x5, x6)
I have similar question (How to splitting a list of vectors to small lists in decreasing order in r) but in a decreasing order.
How I can generate it to arbitrary number of vectors. For example, how if I have 10 or 20 vectors?
Any idea, please?
I'd stick them all in a list of lists
MyLists <- list()
i <- 1
for (inc in 1:3){
MyLists[[inc]] <- x[i:(i+inc-1)]
i <- i+inc
}
Now MyLists[[1]] is list1, etc.
Building off farnsy's answer, If you need each list in a separate indexed list in the global environment you could do something like this.
#your Stater list
x <- list(x1=c(1,2,3), x2=c(1,4,3), x3=c(3,4,6),
x4=c(4,8,4), x5=c(4,33,4), x6=c(9,6,7))
#using a paste parse eval approach to evaluate a string
i<-1
for(inc in 1:3){
eval(parse(text =
paste0("list", inc, "<-list(",
paste0("x$",names(x)[i:(i+inc-1)],collapse = ","),
")")
))
i <- i+inc
}

Subsetting elements in list a based on elements list b

I have 2 lists:
c1 <- c("e","f","g","h")
c2 <- c("j","k","l","m")
list1 <- list(c1,c2)
i1 <- c(1,3)
i2 <- c(2,4)
list2 <- list(i1,i2)
I would like to subset the character vectors in list a based on integer vectors in list b. This way I would end up with a new list (list3) containing c1 (with only e and g) and c2 (with only k and m). I'm currently looking into the possibilities of plyr so the solution should preferably be with plyr. I tried something similar to this but to no avail.
list3 <- llply(list1, function (x) x[list2])
You could try with base R using Map, which would be more compact than the one with llply. Basically, you have two lists with same number of list elements and wanted to subset one each list element of the first list ("list1") based on the index list elements of ("list2"). Map will compare the corresponding elements of "list1" and "list2" and subset using [
Map(`[`, list1, list2)
which is the same as
Map(function(x,y) x[y], list1, list2)
Or using llply from plyr (you don't really need llply). This could be achieved with lapply itself. The key is to compare the corresponding elements of both lists and the possible way you can link both (when they have same elements) is to use seq_along which will get you the sequence of elements in one list (1:3) and use that index to get the corresponding elements of both list and then subset.
llply(seq_along(list1), function(i) list1[[i]][list2[[i]]])

Resources