replicate within list element to make nested list - r

say we have
a <- list(letters[1:4],letters[5:6])
how can we duplicate within each element to get a list like
b <- list(list(letters[1:4],letters[1:4]),list(letters[5:6],letters[5:6]))
I could make an empty list, for a[1] and a[2] fill it with replicated vectors then add it all in one big list.
but i think there should be a quick way that I am missing?
i did
lapply(a, function(x){replicate(2,x, simplify=FALSE)})
but the indexing seems strange
e.g.
[[1]]
[[1]][[1]]
[[1]][[1]][[1]]
[1] "a" "b" "c" "d"
[[1]][[1]][[2]]
[1] "a" "b" "c" "d"

Here's one option:
lapply(a, function(X) rep(list(X), 2))
# [[1]]
# [[1]][[1]]
# [1] "a" "b" "c" "d"
#
# [[1]][[2]]
# [1] "a" "b" "c" "d"
#
#
# [[2]]
# [[2]][[1]]
# [1] "e" "f"
#
# [[2]][[2]]
# [1] "e" "f"

You can apply replicate to each element in your list. Here we do so with lapply:
lapply(a, replicate, n=2, simplify=F)
n and simplify are arguments forwarded by lapply to replicate (see ?replicate). This produces:
List of 2
$ :List of 2
..$ : chr [1:4] "a" "b" "c" "d"
..$ : chr [1:4] "a" "b" "c" "d"
$ :List of 2
..$ : chr [1:2] "e" "f"
..$ : chr [1:2] "e" "f"
Note we're showing the output of str(...) for clarity, not the actual result.

Related

Creating result groups in R, using each element once (combination without repetition)

I have a dataset of 6 individuals: A,B,C,D,E,F
I want to group these into two groups of three individuals and have done so with the combn function in R:
m <- combn(n, 3)
This gives me all 20 possible groups where individuals occur in multiple groups. From this set of groups I then went to find all possible combinations of results, where each individual can only be used once.
I would like to do this using combinations without repetition:
C(n,r) = n! / r!(n-r)! and would therefore get 10 results that would look like this:
abc + def
abd + cef
abe + cdf
abf + cde
acd + bef
ace + bdf
acf + bde
ade + bcf
adf + bce
aef + bcd
I am not sure how to code this in R, from the list of groups that I have generated.
Edit: to generate the dataset I am using I have used the following code:
individuals <- c("a","b","c","d","e","f")
n <- length(individuals)
x <- 3
comb = function(n, x) {
factorial(n) / factorial(n-x) / factorial(x)
}
comb(n,x)
(m <- combn(n, 3))
numbers <- m
letters <- individuals
for (i in 1:length(numbers)) {
m[i] <- letters[numbers[i]]
}
In base R:
Create combnations of 3 letters and store it in a list (asplit)
Create new combnations of 2 groups (of 3 letters)
Filter the list to only keep combinations where the both parts have no element in common
individuals <- c("a","b","c","d","e","f")
combn(individuals, 3, simplify = FALSE) |>
combn(m = 2, simplify = FALSE) |>
Filter(f = \(x) !any(x[[1]] %in% x[[2]]))
output
[[1]]
[[1]][[1]]
[1] "a" "b" "c"
[[1]][[2]]
[1] "d" "e" "f"
[[2]]
[[2]][[1]]
[1] "a" "b" "d"
[[2]][[2]]
[1] "c" "e" "f"
[[3]]
[[3]][[1]]
[1] "a" "b" "e"
[[3]][[2]]
[1] "c" "d" "f"
[[4]]
[[4]][[1]]
[1] "a" "b" "f"
[[4]][[2]]
[1] "c" "d" "e"
[[5]]
[[5]][[1]]
[1] "a" "c" "d"
[[5]][[2]]
[1] "b" "e" "f"
[[6]]
[[6]][[1]]
[1] "a" "c" "e"
[[6]][[2]]
[1] "b" "d" "f"
[[7]]
[[7]][[1]]
[1] "a" "c" "f"
[[7]][[2]]
[1] "b" "d" "e"
[[8]]
[[8]][[1]]
[1] "a" "d" "e"
[[8]][[2]]
[1] "b" "c" "f"
[[9]]
[[9]][[1]]
[1] "a" "d" "f"
[[9]][[2]]
[1] "b" "c" "e"
[[10]]
[[10]][[1]]
[1] "a" "e" "f"
[[10]][[2]]
[1] "b" "c" "d"

R : Extract elements of same index & depth level of a list

Here is a list :
# Build a toy list
x1=letters[1:3]
x2=letters[4:5]
x3=letters[1:8]
toy_list=list(list(list("ABX",x1),
list("ZHK",x2)),
list(list("CCC",x3)))
[[1]]
[[1]][[1]]
[[1]][[1]][[1]]
[1] "ABX"
[[1]][[1]][[2]]
[1] "a" "b" "c"
[[1]][[2]]
[[1]][[2]][[1]]
[1] "ZHK"
[[1]][[2]][[2]]
[1] "d" "e"
[[2]]
[[2]][[1]]
[[2]][[1]][[1]]
[1] "CCC"
[[2]][[1]][[2]]
[1] "a" "b" "c" "d" "e" "f" "g" "h"
Let's suppose I want to extract all elements, for example, in 2nd position, at a "deep level" of 3. In other way I want to extract elements of index [[1]][[1]][[2]], [[1]][[2]][[2]], [[2]][[1]][[2]]. Which means I want my output to be
[[1]]
[1] "a" "b" "c"
[[2]]
[1] "d" "e"
[[3]]
[1] "a" "b" "c" "d" "e" "f" "g" "h"
How would you do that in a generalize way?
With purrr, you can use at_depth(2, ...) where 2 indicates the depth level, and ... is an extractor (name/integer) or function. Simplifying the structure afterwards,
library(purrr)
toy_list %>% at_depth(2, 2) %>% flatten()
## [[1]]
## [1] "a" "b" "c"
##
## [[2]]
## [1] "d" "e"
##
## [[3]]
## [1] "a" "b" "c" "d" "e" "f" "g" "h"

How to convert frequency into text by using R?

I have dataframe like this (ID, Frequency A B C D E)
ID A B C D E
1 5 3 2 1 0
2 3 2 2 1 0
3 4 2 1 1 1
I want to convert this dataframe into test based document like this (ID and their frequency ABCDE as words in a single column). Then I may use LDA algorithm to identify hot topics for each ID.
ID Text
1 "A" "A" "A" "A" "A" "B" "B" "B" "C" "C" "D"
2 "A" "A" "A" "B" "B" "C" "C" "D"
3 "A" "A" "A" "A" "B" "B" "C" "D" "E"
We can use data.table
library(data.table)
DT <- setDT(df1)[,.(list(rep(names(df1)[-1], unlist(.SD)))) ,ID]
DT$V1
#[[1]]
#[1] "A" "A" "A" "A" "A" "B" "B" "B" "C" "C" "D"
#[[2]]
#[1] "A" "A" "A" "B" "B" "C" "C" "D"
#[[3]]
#[1] "A" "A" "A" "A" "B" "B" "C" "D" "E"
Or a base R option is split
lst <- lapply(split(df1[-1], df1$ID), rep, x=names(df1)[-1])
lst
#$`1`
#[1] "A" "A" "A" "A" "A" "B" "B" "B" "C" "C" "D"
#$`2`
#[1] "A" "A" "A" "B" "B" "C" "C" "D"
#$`3`
#[1] "A" "A" "A" "A" "B" "B" "C" "D" "E"
If we want to write the 'lst' to csv file, one option is convert the list to data.frame by appending NA at the end to make the length equal while converting to data.frame (as data.frame is a list with equal length (columns))
res <- do.call(rbind, lapply(lst, `length<-`, max(lengths(lst))))
Or use a convenient function from stringi
library(stringi)
res <- stri_list2matrix(lst, byrow=TRUE)
and then use the write.csv
write.csv(res, "yourdata.csv", quote=FALSE, row.names = FALSE)
You can use apply and rep like so:
apply(df[-1], 1, function(i) rep(names(df)[-1], i))
For each row, apply feeds the rep function the number of times to repeat each variable name. This returns a list of vectors:
[[1]]
[1] "A" "A" "A" "A" "A" "B" "B" "B" "C" "C" "D"
[[2]]
[1] "A" "A" "A" "B" "B" "C" "C" "D"
[[3]]
[1] "A" "A" "A" "A" "B" "B" "C" "D" "E"
Where each list element is a row of your data.frame.
data
df <- read.table(header=T, text="ID A B C D E
1 5 3 2 1 0
2 3 2 2 1 0
3 4 2 1 1 1")

R: How to add new element to character without changing the data structure of it?

I have the following:
print(strategy_reallocations)
1 13 17
A "B" "C" "D"
print(dimnames(strategy_reallocations))
[[1]]
[1] "A"
[[2]]
[1] "B" "C" "D"
print(is.character(strategy_reallocations))
[1] TRUE
I want to add another element to this character so that it looks like:
0 1 13 17
A "Z" "B" "C" "D"
I could not find the right answer on G. What I have tried so far is,
strategy_reallocations <- c("Z", strategy_reallocations)
But this breaks the datastructure of character.
print(strategy_reallocations)
[1] "Z" "B" "C" "D"
How can I do this?
EDIT:
str(strategy_reallocations)
chr [1, 1:3] "B" "C" "D"
- attr(*, "dimnames")=List of 2
..$ : chr "A"
..$ : chr [1:3] "1" "13" "17"
x <- matrix(c("b", "c", "d"), nrow=1)
colnames(x) <- c(1, 13, 17)
rownames(x) <- "a"
cbind(`0`="z", x)
# 0 1 13 17
#a "z" "b" "c" "d"
The backticks are necessary, because 0 is not a valid variable name.

how to pool all the elements from a list of lists? in R

I have a list of lists (I think), so within each element of the list: res[[i]], I have another list, something like:
[[1]]
[[1]]$a
[[1]]$a$`1`
"aa" "bb" "cc"
[[1]]$a$`2`
"aa" "bb" "cc" "dd"
[[2]]
[[2]]$a
[[2]]$a$`1`
"aa" "bb" "cc"
[[2]]$a$`2`
"aa" "bb" "cc" "dd"
...
I would like to merge all the objects in a new list in which I only have something like:
"aa" "bb" "cc"
"aa" "bb" "cc" "dd"
"aa" "bb" "cc" "cc"
...
any idea???
It looks like you want a "flat" list. For this, you can use unlist with recursive = FALSE, but depending on how deep the list is, that might be tedious. Here's an example:
Your data:
myList <- list(list(a = list("1" = letters[1:3], "2" = letters[1:4])),
list(a = list("1" = letters[1:3], "2" = letters[1:4])))
myList
# [[1]]
# [[1]]$a
# [[1]]$a$`1`
# [1] "a" "b" "c"
#
# [[1]]$a$`2`
# [1] "a" "b" "c" "d"
#
#
#
# [[2]]
# [[2]]$a
# [[2]]$a$`1`
# [1] "a" "b" "c"
#
# [[2]]$a$`2`
# [1] "a" "b" "c" "d"
Using nested unlists:
unlist(unlist(myList, recursive=FALSE), recursive=FALSE)
# $a.1
# [1] "a" "b" "c"
#
# $a.2
# [1] "a" "b" "c" "d"
#
# $a.1
# [1] "a" "b" "c"
#
# $a.2
# [1] "a" "b" "c" "d"
There is also this nifty function called LinearizeNestedList (https://sites.google.com/site/akhilsbehl/geekspace/articles/r/linearize_nested_lists_in_r) that can be downloaded/sourced in R and used as follows (for lists of any depth of nesting):
LinearizeNestedList(myList, NameSep=".")
# $`1.a.1`
# [1] "a" "b" "c"
#
# $`1.a.2`
# [1] "a" "b" "c" "d"
#
# $`2.a.1`
# [1] "a" "b" "c"
#
# $`2.a.2`
# [1] "a" "b" "c" "d"
Edit
It appears this question is a duplicate of How to flatten a list to a list without coercion?
See that question and set of answers for other useful solutions.

Resources