How can you generate multiple vectors of different length in R? - r

I would like to use a for loop to generate multiple vectors and save their values for later use. The end result ideally would be:
vector_1 = c(1)
vector_2 = c(1,2,3)
vector_3 = c(1,2,3,4,5,6)
.
.
.
vector_i = c(1,2,3,...,n) #for some n generated during the loop. This n does not always have an upper bound.
This is so that I can use each vector later on to plot multiple lines on the same graph with the axis of the graph scaled correctly.
The following code is the best example I can come up with to try and describe the idea but obviously using 'vector_i' for each loop is not going to work.
for (i in 1:n){
length = sample(1:i^2,1)
vector_i = seq(1,length)
}

You could use the following function:
make_vectors <- function(n) lapply(seq(n), function(i) seq(sample(i^2, 1)))
Which allows:
vector <- make_vectors(5)
vector
#> [[1]]
#> [1] 1
#>
#> [[2]]
#> [1] 1 2 3 4
#>
#> [[3]]
#> [1] 1 2 3 4
#>
#> [[4]]
#> [1] 1 2 3 4 5 6
#>
#> [[5]]
#> [1] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
And you can access each one like this:
vector[[5]]
#> [1] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
This keeps your global environment tidy and allows you to iterate through your vectors more easily than writing them all as independent entities.

We could use sequence
v1 <- sequence(c(1, 3, 6))
v1
#[1] 1 1 2 3 1 2 3 4 5 6
If we need it in a list
split(v1, cumsum(v1 == 1))
#$`1`
#[1] 1
#$`2`
#[1] 1 2 3
#$`3`
#[1] 1 2 3 4 5 6

Related

Automate input for new vector

I was wondering if you had any idea what R code I could use to automate my process.
I would like to repeat "chunks" of an initial vector (Vec1). I divide the vector in groups of 4 values and repeat each group 5 times. Currently, with my bad technique, each time I add a new experiment to the analysis I have to manually create a vector to indicate which chunk I would like to repeat next. In the end I put the vector corresponding to each experiment together to get my desired output.
Vec1 <- A simple numeric vector that grows in size for each new experiment. Each new experiment extends the vector by 4 additional values.
Exp1 <- rep(Vec1 [1:4], times=5)
Exp2 <- rep(Vec1 [5:8], times=5)
Exp3 <- rep(Vec1 [9:12], times=5)
NewVector<- c(Exp1, Exp2, Exp3)
Could I use a trick to automate it?
Many thanks for the help,
Best regards,
Edouard M.
I don't know about "automate". You could write a function that takes the values 1:4 and adds multiples of 4 to it.
add_exp <- function(values = 1:4, n = 0) {
rep(values, 5) + 4 * n
}
Then add_exp() gives:
[1] 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4
And add_exp(n = 1) gives:
[1] 5 6 7 8 5 6 7 8 5 6 7 8 5 6 7 8 5 6 7 8
So you could get NewVector using:
NewVector<- c(add_exp(), add_exp(n = 1), add_exp(n = 2))
Or if you wanted to use lapply to supply the values of n:
NewVector <- unlist(lapply(0:2, function(x) add_exp(n = x)))
Using sequence:
n <- 3L # number of experiments
v <- 4L # length of vector added for each experiment
r <- 5L # number of replications
sequence(rep(v, n*r), rep(seq(1, n*v, v), each = r))
#> [1] 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 5 6 7 8 5
#> [26] 6 7 8 5 6 7 8 5 6 7 8 5 6 7 8 9 10 11 12 9 10 11 12 9 10
#> [51] 11 12 9 10 11 12 9 10 11 12

am trying to generating grouping of numbers using sequences of numbers and slicing using for loop in R language. help me how to generate?

I am trying to generating grouping of numbers using sequences of numbers and slicing using a for-loop. My input is
s1 = seq(1,285, 5)
s2 = seq(5, 285, 5)
for (k in 1:57))
{
print(s1:s2)
}
But I am getting this output
[1] 1 2 3 4 5
[1] 1 2 3 4 5
[1] 1 2 3 4 5
[1] 1 2 3 4 5
instead of my expected
[1] 1 2 3 4 5
[1] 6 7 8 9 10
[1] 11 12 13 14 15
[1] 16 17 18 19 20
you shoud use k in for body
for (k in 1:57){
print(s1[k]:s2[k])
}

Adding lists together with a loop

I'm trying to add lists together using a loop. Here is some example data.
df <- data.frame(var1 = c(1,1,2,2,2,2,3,3,3,3,3), var2= 1:11)
> df
var1 var2
1 1 1
2 1 2
3 2 3
4 2 4
5 2 5
6 2 6
7 3 7
8 3 8
9 3 9
10 3 10
11 3 11
I've run this loop code, and would like the items to be stored in a file that contains 3 lists
list_container <- list()
for (i in unique(df$var1) ) {
templist <- df[ df$var1==i , "var2"]
list_container <- list(list_container, templist)
}
it doesn't work, and ends up looking like this
> list_container
[[1]]
[[1]][[1]]
[[1]][[1]][[1]]
list()
[[1]][[1]][[2]]
[1] 1 2
[[1]][[2]]
[1] 3 4 5 6
[[2]]
[1] 7 8 9 10 11
I want the 3 sets of list to sit separately, it should end up like this
list_result <- list(1:2, 3:6, 7:11)
> list_result
[[1]]
[1] 1 2
[[2]]
[1] 3 4 5 6
[[3]]
[1] 7 8 9 10 11
Is there anyway I can modify my code to get the desired result? Any help greatly appreciated. Thanks
split would be more direct and faster
with(df, unname(split(var2, var1)))
-output
[[1]]
[1] 1 2
[[2]]
[1] 3 4 5 6
[[3]]
[1] 7 8 9 10 11
If we want to use the == with unique elements, initialize with a NULL list of length same as the length of unique elements of 'var1' column. Loop over the sequence of unique elements, and assign the subset of 'var2' to the ith element of 'list_container'
un1 <- unique(df$var1)
list_container <- vector('list', length(un1))
for(i in seq_along(un1))
list_container[[i]] <- df$var2[df$var1 == un1[i]]
-output
list_container
[[1]]
[1] 1 2
[[2]]
[1] 3 4 5 6
[[3]]
[1] 7 8 9 10 11
Another base R option using tapply
> with(df, tapply(var2, var1, c))
$`1`
[1] 1 2
$`2`
[1] 3 4 5 6
$`3`
[1] 7 8 9 10 11
or aggregate
> aggregate(var2 ~ ., df, c)$var2
[[1]]
[1] 1 2
[[2]]
[1] 3 4 5 6
[[3]]
[1] 7 8 9 10 11
You could also use unstack:
unstack(df, var2~var1)
$`1`
[1] 1 2
$`2`
[1] 3 4 5 6
$`3`
[1] 7 8 9 10 11
if you do not want the names, you can get rid of them:
unname(unstack(df, var2~var1))
[[1]]
[1] 1 2
[[2]]
[1] 3 4 5 6
[[3]]
[1] 7 8 9 10 11

How can I make this iterative combinaiton loop code work with more than x per combination?

I found this life-saving code created by #QuantIbex. It creates combinations of variables iteratively to be used in a loop without generating them in advance or storing them.
First answer here
## Function definition
gen.next.cbn <- function(cbn, n){
## Generates the combination that follows the one provided as input
cbn.bin <- rep(0, n)
cbn.bin[cbn] <- 1
if (tail(cbn.bin, 1) == 0){
ind <- tail(which(cbn.bin == 1), 1)
cbn.bin[c(ind, ind+1)] <- c(0, 1)
}else{
ind <- 1 + tail(which(diff(cbn.bin) == -1), 1)
nb <- sum(cbn.bin[-c(1:ind)] == 1)
cbn.bin[c(ind-1, (n-nb+1):n)] <- 0
cbn.bin[ind:(ind+nb)] <- 1
}
cbn <- which(cbn.bin == 1)
}
## Example parameters
n <- 6
k <- 3
## Iteration example
for (i in 1:choose(n, k)){
if (i == 1){
cbn <- 1:k
}else{
cbn <- gen.next.cbn(cbn, n)
}
print(cbn)
}
# [1] 1 2 3
# [1] 1 2 4
# [1] 1 2 5
# [1] 1 2 6
# [1] 1 3 4
# [1] 1 3 5
# [1] 1 3 6
# [1] 1 4 5
# [1] 1 4 6
# [1] 1 5 6
# [1] 2 3 4
# [1] 2 3 5
# [1] 2 3 6
# [1] 2 4 5
# [1] 2 4 6
# [1] 2 5 6
# [1] 3 4 5
# [1] 3 4 6
# [1] 3 5 6
# [1] 4 5 6
The code itself is beyond my own technical capabilities in R. I have been able to adapt it for my use, and insert my analyses in the loop and it works very well. One of the things I have not been able to figure out is how to make it go through more than x number of variables per combination at a time.
In the code above n = the number of variables to be used to generate the combinations. k = the number of variables per combination. In the example, k=3. I can change k to anything I want, but is there a way for k to a equal a range such as k = 3:10?
I set the values:
n <- 31
k <- 3:10
It stops once done with combinations of 3 and gives me this:
Warning messages:
1: In 1:choose(n, k) :
numerical expression has 8 elements: only the first used
2: In 1:k : numerical expression has 8 elements: only the first used
I know a lot of people warn of how slow loops are, and will probably warn me that combinations of 10 will take forever, but these are things I accept.
Since you don't mind loops, why not just iterate over the elements of k?
## Example parameters
n <- 6
k <- 1:3
for(j in seq_along(k))
{
## Iteration example
for (i in 1:choose(n, k[j])){
if (i == 1){
cbn <- 1:k[j]
}else{
cbn <- gen.next.cbn(cbn, n)
}
print(cbn)
}
}
Output:
#> [1] 1
#> [1] 2
#> [1] 3
#> [1] 4
#> [1] 5
#> [1] 6
#> [1] 1 2
#> [1] 1 3
#> [1] 1 4
#> [1] 1 5
#> [1] 1 6
#> [1] 2 3
#> [1] 2 4
#> [1] 2 5
#> [1] 2 6
#> [1] 3 4
#> [1] 3 5
#> [1] 3 6
#> [1] 4 5
#> [1] 4 6
#> [1] 5 6
#> [1] 1 2 3
#> [1] 1 2 4
#> [1] 1 2 5
#> [1] 1 2 6
#> [1] 1 3 4
#> [1] 1 3 5
#> [1] 1 3 6
#> [1] 1 4 5
#> [1] 1 4 6
#> [1] 1 5 6
#> [1] 2 3 4
#> [1] 2 3 5
#> [1] 2 3 6
#> [1] 2 4 5
#> [1] 2 4 6
#> [1] 2 5 6
#> [1] 3 4 5
#> [1] 3 4 6
#> [1] 3 5 6
#> [1] 4 5 6
This will work when k is a vector but will keep the same functionalty you had before using a single integer.
As a footnote, choosing a set of 10 from 20 elements using this method (without my addition) takes my computer about a minute, which I would live with if I only had to run it now and again.
I believe
one way to accomplish what you want to start using combn;
But I noticed you are avoiding repeating the elements in the
combinations. So you will need to exclude repetitions... I include example code for a function for it.
Afterwards, you can substitute the loop for lapply for efficiency and use the function.
n<-31
combnWoRepl<-function(n,k){
abc<-combn(1:n,k)
abc<-t(abc)
abc<-data.frame(abc)
colnames(abc)<-c("a","b","c")
abc[!abc$a==abc$b,]
}
ResultList<-lapply(3:10,function(x){
combnWoRepl(n,x)
})

Calculating cohesive blocks cohesion igraph 0.5.4

Is there a more or less direct way to estimate the cohesion for each cohesive block (i.e. the result of cohesive.blocks()) in igraph 0.5.4?
In the actual version (0.6) there is a function called cohesion(), but in version 0.5.x there is not. Is there an easier way to calculate it or should I just do it individually for each block (by hand!!)?
This is actually in the documentation, even in the example:
g <- graph.disjoint.union(graph.full(4), graph.empty(2,directed=FALSE))
g <- add.edges(g,c(3,4,4,5,4,2))
g <- graph.disjoint.union(g,g,g)
g <- add.edges(g,c(0,6,1,7,0,12,4,0,4,1))
## Find cohesive blocks:
gBlocks <- cohesive.blocks(g)
## Examine block membership and cohesion:
gBlocks$blocks
# [[1]]
# [1] 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
# [[2]]
# [1] 12 13 14 15 16
# [[3]]
# [1] 0 1 2 3 4 6 7 8 9 10
# [[4]]
# [1] 12 13 14 15
# [[5]]
# [1] 0 1 2 3 4
# [[6]]
# [1] 6 7 8 9
gBlocks$block.cohesion
# [1] 1 2 2 3 4 3

Resources