Related
Suppose I have a matrix which looks like this:
[1] a b c
[2] d e f
[3] g h i
[4] j k l
[5] m n o
[6] p q r
Now I want to split this matrix into smaller ones with each 3 rows, starting from the first row, then the second, ..., so it looks like this in the end:
[1] a b c
[2] d e f
[3] g h i
[1] d e f
[2] g h i
[3] j k l
[1] g h i
[2] j k l
[3] m n o
...
I tried the following code, which didn't do it for me:
lapply(split(1:nrow(matrix),(1:nrow(matrix)-1) %/%3+1),
function(i) matrix[i,])
Can someone help me with this?
The split method showed in the OP's post will split into blocks of 3 rows and that will not be mutually exclusive. Whereas if we want to split in a way that each list element starts with each of the rows of the matrix and the next two rows, we can loop through the sequence of rows, get the sequence from that index to the next two and subset the matrix
lapply(head(seq_len(nrow(matrix)), -2), function(i) matrix[i:(i+2),])
#[[1]]
# [,1] [,2] [,3]
#[1,] "a" "b" "c"
#[2,] "d" "e" "f"
#[3,] "g" "h" "i"
#[[2]]
# [,1] [,2] [,3]
#[1,] "d" "e" "f"
#[2,] "g" "h" "i"
#[3,] "h" "k" "l"
#[[3]]
# [,1] [,2] [,3]
#[1,] "g" "h" "i"
#[2,] "h" "k" "l"
#[3,] "m" "n" "o"
[[4]]
[,1] [,2] [,3]
[1,] "h" "k" "l"
[2,] "m" "n" "o"
[3,] "p" "q" "r"
Or as #lmo suggested, another version of the above would be
lapply(seq_len(nrow(matrix) -2L) - 1L, function(x) matrix[x + 1:3,])
or another option is to create the splitting group with rollapply (from zoo) and then do the split
library(zoo)
grp <- rollapply(seq_len(nrow(matrix)), 3, FUN = I)
lapply(split(grp, row(grp)), function(i) matrix[i, ])
NOTE: matrix is a function name. It is better not to name objects with function names or other reserved words
data
matrix <- structure(c("a", "d", "g", "h", "m", "p", "b", "e", "h", "k",
"n", "q", "c", "f", "i", "l", "o", "r"), .Dim = c(6L, 3L))
I have a directed cyclical matrix and need to extract all the simple paths between any i and j.
The following is my ex. matrix:
>M2<-matrix(c(1,1,0,0,0,1,1,1,1,0,0,1,1,1,0,0,1,0,1,1,0,0,0,1,1), 5, byrow=T)
>colnames(M2)<-c("A", "B", "C", "D", "E")
>row.names(M2)=colnames(M2)
>M2
A B C D E
A 1 1 0 0 0
B 1 1 1 1 0
C 0 1 1 1 0
D 0 1 0 1 1
E 0 0 0 1 1
I use igraph to convert the matrix to a graph object using the graph_from_adjency_matrix function.
>graph<-graph_from_adjacency_matrix(M2, mode=c("directed"), weighted=NULL, diag=F, add.colnames=NULL, add.rownames=NA)
>graph
IGRAPH DN-- 5 9 --
+ attr: name (v/c)
+ edges (vertex names):
[1] A->B B->A B->C B->D C->B C->D D->B D->E E->D
And from there I use the all_simple_paths function to get all the simple paths between i and j. And here starts my questions.
1) I can specify the j (argument to has to=V(graph)) to be all possible end vertices. But I can't specify the from argument to calculate the paths looking for all vertices has possible starting points. I have to specify each of my variables at a time. Any solution?
2) The all_simple_path function works well and gives me all the simple paths between i and j, e.g. for simple paths starting in A and ending in any possible j:
>Simple_path_list<-all_simple_paths(graph, from ="A", to=V(graph), mode = c("out"))
>Simple_path_list
[[1]]
+ 2/5 vertices, named:
[1] A B
[[2]]
+ 3/5 vertices, named:
[1] A B C
[[3]]
+ 4/5 vertices, named:
[1] A B C D
[[4]]
+ 5/5 vertices, named:
[1] A B C D E
[[5]]
+ 3/5 vertices, named:
[1] A B D
[[6]]
+ 4/5 vertices, named:
[1] A B D E
My problem is, I need to collect all those paths and put on a list, e.g.:
Paths
A B
A B C
A B C D
A B C D E
A B D
A B D E
I tried to create a list and call for the path names using the normal list<-Simple_path_list[1] or so, but I always retrieve, together with the paths, the information on the number of vertices involved (e.g., + 4/5 vertices, named). Any idea on how can I retrieve solely the paths name and not the other information?
The lapply function on all_simple_paths makes a list of lists (i.e. a list of each vertex's list of paths). Simplify the list of lists to a list using unlist(..., recursive = F) and then use names or igraph's as_ids to extract the vertex ids solo.
library(igraph)
M2<-matrix(c(1,1,0,0,0,1,1,1,1,0,0,1,1,1,0,0,1,0,1,1,0,0,0,1,1), 5, byrow=T)
colnames(M2)<-c("A", "B", "C", "D", "E")
row.names(M2)=colnames(M2)
M2
graph<-graph_from_adjacency_matrix(M2, mode=c("directed"), weighted=NULL, diag=F, add.colnames=NULL, add.rownames=NA)
l <- unlist(lapply(V(graph) , function(x) all_simple_paths(graph, from=x)), recursive = F)
paths <- lapply(1:length(l), function(x) as_ids(l[[x]]))
This produces:
> paths
[[1]]
[1] "A" "B"
[[2]]
[1] "A" "B" "C"
[[3]]
[1] "A" "B" "C" "D"
[[4]]
[1] "A" "B" "C" "D" "E"
[[5]]
[1] "A" "B" "D"
[[6]]
[1] "A" "B" "D" "E"
[[7]]
[1] "B" "A"
[[8]]
[1] "B" "C"
[[9]]
[1] "B" "C" "D"
[[10]]
[1] "B" "C" "D" "E"
[[11]]
[1] "B" "D"
[[12]]
[1] "B" "D" "E"
[[13]]
[1] "C" "B"
[[14]]
[1] "C" "B" "A"
[[15]]
[1] "C" "B" "D"
[[16]]
[1] "C" "B" "D" "E"
[[17]]
[1] "C" "D"
[[18]]
[1] "C" "D" "B"
[[19]]
[1] "C" "D" "B" "A"
[[20]]
[1] "C" "D" "E"
[[21]]
[1] "D" "B"
[[22]]
[1] "D" "B" "A"
[[23]]
[1] "D" "B" "C"
[[24]]
[1] "D" "E"
[[25]]
[1] "E" "D"
[[26]]
[1] "E" "D" "B"
[[27]]
[1] "E" "D" "B" "A"
[[28]]
[1] "E" "D" "B" "C"
Addition
For all_shortest_paths you must subset the list of paths for each node to exclude the geodesic information.
l <- lapply(V(graph), function(x) all_shortest_paths(graph, from = x))
l <- lapply(l, function(x) x[[-2]])
l <- unlist(l, recursive = F)
paths <- lapply(1:length(l), function(x) as_ids(l[[x]]))
I'm asking to how to merge two lists in parallel, not orderly append as below codes.
For example,
A <- list(c(1,2,3), c(3,4,5), c(6,7,8))
B <- list(c("a", "b", "c"), c("d", "e", "f"), c("g", "h", "i"))
As results,
[[1]]
[[1]][[1]]
[1] 1 2 3
[[1]][[2]]
[1] "a" "b" "c"
[[2]]
[[2]][[1]]
[1] 3 4 5
[[2]][[2]]
[1] "d" "e" "f"
[[3]]
[[3]][[1]]
[1] 6 7 8
[[3]][[2]]
[1] "g" "h" "i"
Using Map simply:
Map(list,A,B)
A longer approach (not recursive yet, up to second level merging):
A <- list(c(1,2,3), c(3,4,5), c(6,7,8))
B <- list(c("a", "b", "c"), c("d", "e", "f"), c("g", "h", "i"))
mergepar <- function(x = A, y = B) { # merge two lists in parallel
ln <- max(length(x), length(y)) # max length
newlist <- as.list(rep(NA, ln)) # empty list of max length
for (i in 1:ln) { # for1, across length
# two level subsetting (first with [ and then [[, so no subscript out of bound error) and lapply
newlist[[i]] <- lapply(list(A, B), function(x) "[["("["(x, i), 1))
}
return(newlist)
}
I have a list of letters l
[1] a b c
[2] b c a b
and a vector v of letter too
[1] a
[2] b
My object is to take the letters of the vector v one by one and creating a new list that contains all the letter appearing after that letter.
For example
I take the first letter of v "a" and I create the list of letter appearing after "a" , And I got this :
[1] b c
[2] b
After i take the second letter or v which is "b"
and I add to the list :
[3] c
[4] c a b
So the final result is :
[1] b c
[2] b
[3] c
[4] c a b
I don't know how to do this, it seems complicated.
I have also a list of vector with this format
[[1]]
[1] a
[2] b
[3] c
[[2]]
[1] e
[2] g
A nested lapply:
lapply(v, function(v, l) lapply(l, function(x, v) {
if (!(v %in% x)) return(x) #the case of no match
x[-seq_len(which.max(x == v))]
}, v = v), l = l)
#[[1]]
#[[1]][[1]]
#[1] "b" "c"
#
#[[1]][[2]]
#[1] "b"
#
#
#[[2]]
#[[2]][[1]]
#[1] "c"
#
#[[2]][[2]]
#[1] "c" "a" "b"
Here is one approach using lapply.
dat <- list( c("a", "b", "c"), c("b", "c", "a", "b"))
v <- c("a", "b")
result <- list()
for (l in v) {
result[[l]] <- lapply(dat, function(z) z[(which(z == l)[1] + 1):length(z)])
}
result
I have the data.frame
df<-data.frame("Site.1" = c("A", "B", "C"),
"Site.2" = c("D", "B", "B"),
"Tsim" = c(2, 4, 7),
"Jaccard" = c(5, 7, 1))
# Site.1 Site.2 Tsim Jaccard
# 1 A D 2 5
# 2 B B 4 7
# 3 C B 7 1
I can get the unique levels for each column using
top.x<-unique(df[1:2,c("Site.1")])
top.x
# [1] A B
# Levels: A B C
top.y<-unique(df[1:2,c("Site.2")])
top.y
# [1] D B
# Levels: B D
How do I get the unique levels for both columns and turn them into a vector i.e:
v <- c("A", "B", "D")
v
# [1] "A" "B" "D"
top.xy <- unique(unlist(df[1:2,]))
top.xy
[1] A B D
Levels: A B C D
Try union:
union(top.x, top.y)
# [1] "A" "B" "D"
union(unique(df[1:2, c("Site.1")]),
unique(df[1:2, c("Site.2")]))
# [1] "A" "B" "D"
You can get the unique levels for the firs two collumns:
de<- apply(df[,1:2],2,unique)
de
# $Site.1
# [1] "A" "B" "C"
# $Site.2
# [1] "D" "B"
Then you can take the symmetric difference of the two sets:
union(setdiff(de$Site.1,de$Site.2), setdiff(de$Site.2,de$Site.1))
# [1] "A" "C" "D"
If you're intrested in just two first two rows (as in your example):
de<- apply(df[1:2,1:2],2,unique)
de
# Site.1 Site.2
# [1,] "A" "D"
# [2,] "B" "B"
union(de[,1],de[,2])
# [1] "A" "B" "D"