A <- list(X = c(Z = 15))
How do I access 15 in the above example
We can try using a combination of list access syntax along with vector access syntax:
A <- list(X = c(Z = 15))
A$X["Z"]
Z
15
Above A$X refers to the element in the list named X, which happens to be a vector. Then, A$X["Z"] accesses the element in the vector named Z, which is the value 15.
Can also access it with indices:
A[[c(1, 1)]]
You can simply do:
A[[1]]
This gets the first "component" of the list.
A[[1]]
Z
15
Or if you want to go step by step, then:
A[1][[1]]
Z
15
Related
I want to extract values from a list of (named) lists in R.
Example
The data looks as follows:
data <- list('1' = list(x = c(1,2,3), y = c(2,3,4), z = c(2,3,7)),
'2' = list(x = c(2,3,4,5), y = c(3,4,5,6), z = c(1,2,3,5)))
From a specified list (e.g., '1'), I would like to extract all the first/second/etc elements from the lists. The choice for the index of the element should be random.
For example, if I want to sample from the first list (i.e., '1'), I generate a random index and extract the x, y, and z values corresponding to that random index. Say the index is 2, then the elements should be x=2, y=3, and z=3.
Approach
I thought a function should be able to do the job. The first step was to call the list from the function:
This works:
x <- function(i){
data$`1`
}
x(1)
But this doesn't:
x <- function(i){
data$`i`
}
x(1)
Question
How do I call a list of named lists from within the function? And what is the most convenient way to sample data corresponding to the selected index?
Do you need something like this ?
get_elements <- function(data, i) {
#select the main list
tmp <- data[[i]]
#Check the length of each sublist, select minimum value
#and sample 1 number from 1 to that number
rand_int <- sample(min(lengths(tmp)), 1)
#select that element from each sub-list
sapply(tmp, `[[`, rand_int)
}
get_elements(data, 1)
If I understood your problem correctly a solution would be with the "purrr" package:
library(purrr)
# list "name"
i <- '1'
# index
j <- 2
# to get the needed info as a list:
purrr::map(data[[i]], ~ .x[j])
# to get the needed info as a data.frame:
purrr::map_df(data[[i]], ~ .x[j])
Below, I'm wondering how to use BASE R function quantile() separately across elements in L that are named EFL and ESL?
Note: this is a toy example, L could contain any number of similarly named elements.
foo <- function(X) {
X <- as.matrix(X)
tab <- table(row(X), factor(X, levels = sort(unique(as.vector(X)))))
w <- diag(ncol(tab))
rosum <- rowSums(tab)
obs_oc <- tab * (t(w %*% t(tab)) - 1)
obs_c <- colSums(obs_oc)
max_oc <- tab * (rosum - 1)
max_c <- colSums(max_oc)
SA <- obs_c / max_c
h <- names(SA)
h[is.na(h)] <- "NA"
setNames(SA, h)
}
DAT <- read.csv("https://raw.githubusercontent.com/rnorouzian/m/master/X.csv", row.names = 1)
L <- replicate(50, foo(DAT[sample(1:nrow(DAT), replace = TRUE),]), simplify = FALSE)
# How to use `quantile()` separately across all similarly named elements (e.g., EFL, ESL) in `L[[i]]` i = 1,... 5
# quantile(all EFL elements across `L`)
# quantile(all ESL elements across `L`)
The previous solution I used do.call to rbind each list into a matrix and array and then calculate the quantile over each data.frame row.
sapply(as.data.frame(do.call(rbind, L)), quantile)
However, when there is a missing row, it does not take that into account. To accurately get the rows you need to fill the missing rows. I used data.table's rbindlist (you could also use plyr::rbind.fill) with fill=TRUE to fill the missing values. It requires each to be a data.frame/table/list, so I converted each to a data.frame, but before doing so you need to transpose (t()) the data so that the rows line up to each element. It could be written in a single line, but it's easier read what is happening in multiple lines.
L2 = lapply(L, function(x){as.data.frame(t(x))})
df = data.table::rbindlist(L2, fill=TRUE) # or plyr::rbind.fill(L2)
sapply(df, quantile, na.rm = TRUE)
You can also use purrr::transpose:
Lt <- purrr::tranpose(L)
quantile(unlist(Lt$EFL),.8)
quantile(unlist(Lt$ESL),.8)
I had a vector like this :
x= c(0.542949849, 0.242292905, 0.163459552, 0.069668097, 0.042969073, 0.035829825)
and I want to plot (x[i], x[i+1]). Using Excel I got this :
How can I get this graphic in R ? I tried this :
for(i in 1:5){
plot(x[i], x[i+1])
par(new = TRUE)
}
but it doesn't give the excepted result
Here are two solutions.
The first uses base R only.
x <- c(0.542949849, 0.242292905, 0.163459552, 0.069668097, 0.042969073, 0.035829825)
plot(range(x), range(x), type = "n")
for(i in seq_along(x)[-length(x)]){
points(x[i], x[i+1])
}
The second uses package tsDyn.
tsDyn::autopairs(x, type = "points")
Try this:
plot(embed(rev(x), 2))
or
plot(embed(x, 2)[, 2:1])
You can get what you want but you have to add a few intermediate steps.
You need to put in a qualifier to force the array to be numeric. This is the equivalent of forcing the array to be an array of float values. Otherwise all you get is integer values in your array.
You need to redefine the sub-components of x to 2 new vectors. Vector 'a' has an index of elements from 1 to 5 of the x array. It appears on the x-axis. Vector 'b' has an index of elements from 2 to 6 of the x array. It appears on the y-axis. The first elements in vectors a and b index position 1 are equivalent to x[i],x[i+1] where i is 1.
You need to bind the 2 vectors together and then plot the result.
x <- as.numeric(c(0.542949849, 0.242292905, 0.163459552, 0.069668097, 0.042969073, 0.035829825))
a <- x[1:5]
b <- x[2:6]
c <- cbind(a,b)
plot(c)
and the result graph is as follows
I have a function of this form:
foo<-function(x,y){
if(length(y)==1){
return(x*y)
}
else{
return(x-y[1]*y[2])
}
}
and for the y argument I pass either a number or a vector of numbers:
> #test function:
> foo(1,2)
[1] 2
> foo(1,c(1,2))
[1] -1
Now I wish to use mapply to this function, but I run into problems when I wish to pass a vector for the y argument:
df<-data.frame(
"a"<-floor(runif(6, 1,10)),
"b"<-floor(runif(6, 18,80)),
"c"<-floor(runif(6, 1,80)),
"d"<-floor(runif(6, 100,800)),
"e"<-floor(runif(6, 1000,4000)),
"f"<-floor(runif(6, 1,10)),
"g"<-floor(runif(6, 5,80))
)
names(df)=c("a","b","c","d","e","f","g")
The following works fine:
> mapply(FUN=foo,df["a"],df["b"])
,but I run into trouble when I try to do the following:
> mapply(FUN=foo,df["a"],cbind(df["b"],df["c"]))
I'm very grateful for tips on how to better use an argument that have verying length, or how to pass the argument to mapply!
There are a lot of possible fixes here. Fundamentally, you need to turn 2nd input into mapply into a list with two elements in each list. One way to achieve that is to do something like:
tmp <- as.data.frame(t(df[c('b', 'c')]))
result <- mapply(FUN=foo,df["a"], tmp)
since a data frame is a list. This is going to run the function on all combinations of df["a"] and tmp. The elements you want will be along the diagonal (1st element of df['a'] with the first element of tmp, so the final answer is
diag(result)
BTW, when you are inside a function such as data.frame, use = for assignment instead of <-. You also do not need the quotes around the letters (they are being ignored). so you're call to data.frame should look like
df<-data.frame(
a = floor(runif(6, 1,10)),
b = floor(runif(6, 18,80)),
c = floor(runif(6, 1,80)),
d = floor(runif(6, 100,800)),
e = floor(runif(6, 1000,4000)),
f = floor(runif(6, 1,10)),
g = floor(runif(6, 5,80))
)
Which allows you to avoid having to name the data frame after you define it.
Update without diagonal call
f1 <- function(x) {
if(length(x) ==2 ) x[1] * x[2]
else x[1] - x[2]*x[3]
}
apply(df[,c("a","b", "c")], 1, f1)
I want to create a function f in R which takes a list x and a vector y as its arguments and returns a list whose elements are products after multiplying each element of the vector by each element of the list.
x = list(x1 = runif(10), x2 = rnorm(10), x3 = 1:10, x4 = seq(1,.1,-.1))
y = c(2, 1, 3)
I want f(x,y) to return a list whose elements are x[[i]] * y[j] for each i = 1:length(x)
and j = 1:length(y)
This would work:
lapply(x, function(z) lapply(y, "*", z))
However you need to do a bit of work on moving things around with indexing as right now you're bordering on let me order up a function and you guys make it for me.
You could use mapply("*", x, y), but you need to modify "y" so that each multiplier is repeated length(x) times. In other words, the following should work:
mapply("*", x, rep(y, each = length(x)))
You may need to add names back in to the results.
If the length of each list item is the same (in your example, they all contain 10 values), the following is a variation on #Tyler's answer:
lapply(y, "*", do.call(rbind, x))
This will result in a list of matrices of the results.
This should also work - depend on what form of outcome you prefer
lapply(x , outer , y)