I got a list of matrices X rows by 2 columns, called list_of_matrices_by2
list_of_matrices_by2[1:3]
[[1]]
[,1] [,2]
[1,] "7204" "d"
[2,] "7204" "a"
[[2]]
[,1] [,2]
[1,] "2032" "b"
[2,] "2032" "e"
[3,] "2032" "a"
[[3]]
[,1] [,2]
[1,] "802" "d"
[2,] "802" "b"
I want to stack all my matrices in a all_pairs matrix, so I did this
all_pairs=do.call(rbind,list_of_matrices_by2)
all_pairs[1:10]
[,1] [,2]
[1,] "7204" "d"
[2,] "7204" "a"
[3,] "2032" "b"
[4,] "2032" "e"
[5,] "2032" "a"
[6,] "802" "d"
[7,] "802" "b"
[8,] "4674" "c"
[9,] "4674" "a"
[10,] "3886" "b"
class(all_pairs)
[1] "matrix"
For some reason, I need the rows of this matrix to be of class matrix. But it shouldn't be a problem since rows of matrix are matrix in R, right. But no!
all_pairs[1,]
[[1]]
[1] "7204"
[[2]]
[1] "d
So here are my questions :
1) Why this? How come a row of a matrix can possibly be a list?
2) What would you do to make it work, i.e. each row of my matrix has to be a matrix?
I am sure that your list_of_matrices_by2 is like:
x <- list(matrix(list("7204","7204","d","a"), ncol = 2),
matrix(list("2032","2032","2032","b","e","a"), ncol = 2),
matrix(list("802","802","d","b"), ncol = 2))
#[[1]]
# [,1] [,2]
#[1,] "7204" "d"
#[2,] "7204" "a"
#[[2]]
# [,1] [,2]
#[1,] "2032" "b"
#[2,] "2032" "e"
#[3,] "2032" "a"
#[[3]]
# [,1] [,2]
#[1,] "802" "d"
#[2,] "802" "b"
unlist(lapply(x, class))
# [1] "matrix" "matrix" "matrix"
unlist(lapply(x, mode))
# [1] "list" "list" "list"
So you do have a matrix, but it is not a matrix of list instead of numeric. You can perform rbind as usual:
y <- do.call(rbind, x)
# [,1] [,2]
#[1,] "7204" "d"
#[2,] "7204" "a"
#[3,] "2032" "b"
#[4,] "2032" "e"
#[5,] "2032" "a"
#[6,] "802" "d"
#[7,] "802" "b"
It has class "matrix", but still with mode "list". That is why when you extract the first row you get a list:
y[1, ]
#[[1]]
#[1] "7204"
#[[2]]
#[1] "d"
I don't know how you obtain those matrices. If you can control the generation process, it would be good that you end up with matrices of numeric. If you can not control it, you need convert them manually as below:
x <- lapply(x, function (u) matrix(unlist(u), ncol = 2))
unlist(lapply(x, mode))
# [1] "character" "character" "character"
Then you can do
do.call(rbind, x)
Related:
Why is this matrix not numeric?
How to create a matrix of lists?
Ok guys, I finally found a solution.
Reminder
all_pairs=do.call(rbind,list_of_matrices_by2)
Extraction of all values of my matrix into a vector
extracted_values=unlist(as.vector(t(all_pairs)))
Build the new matrix
all_pairs_new=t(matrix(data = extracted_values,nrow = 2,ncol = 10000))
Related
I am a programming newbie attempting to compare two matrices. In case an element from first column in mat1 matches any element from first column in mat2, then I want that matching element in mat1 to be replaced with the neighboor (same row different column) to the match in mat2.
INPUT:
mat1<-matrix(letters[1:5])
mat2<-cbind(letters[4:8],1:5)
> mat1
[,1]
[1,] "a"
[2,] "b"
[3,] "c"
[4,] "d"
[5,] "e"
> mat2
[,1] [,2]
[1,] "d" "1"
[2,] "e" "2"
[3,] "f" "3"
[4,] "g" "4"
[5,] "h" "5"
wished OUTPUT:
> mat3
[,1]
[1,] "a"
[2,] "b"
[3,] "c"
[4,] "1"
[5,] "2"
I have attempted the following without succeeding:
> for(x in mat1){mat3<-ifelse(x==mat2,mat2[which(x==mat2),2],mat1)}
> mat3
[,1] [,2]
[1,] "a" "a"
[2,] "2" "b"
[3,] "c" "c"
[4,] "d" "d"
[5,] "e" "e"
Any advice will be very appreciated. Have spent a whole day without making it work. It doesn't matter to me if the elements are in a matrix or a data frame.
Thanks.
ifelse is vectorized so, we can use it on the whole column. Create the test logical condition in ifelse by checking whether the first column values of 'mat1' is %in% the first column of 'mat2', then , get the index of the corresponding values with match, extract the values of the second column with that index, or else return the first column of 'mat1'
mat3 <- matrix(ifelse(mat1[,1] %in% mat2[,1],
mat2[,2][match(mat1[,1], mat2[,1])], mat1[,1]))
mat3
# [,1]
#[1,] "a"
#[2,] "b"
#[3,] "c"
#[4,] "1"
#[5,] "2"
Here is another base R solution
v <- `names<-`(mat2[,2],mat2[,1])
mat3 <- matrix(unname(ifelse(is.na(v[mat1]),mat1,v[mat1])))
which gives
> mat3
[,1]
[1,] "a"
[2,] "b"
[3,] "c"
[4,] "1"
[5,] "2"
An option just using logical operation rather than a function
mat3 <- mat1
mat3[mat1[,1] %in% mat2[,1], 1] <- mat2[mat2[,1] %in% mat1[,1], 2]
Subsetting the values to find those that occur in both and replacing them where they do
Assume we have the following permutations of the letters, "a", "b", and "c":
library(combinat)
do.call(rbind, permn(letters[1:3]))
# [,1] [,2] [,3]
# [1,] "a" "b" "c"
# [2,] "a" "c" "b"
# [3,] "c" "a" "b"
# [4,] "c" "b" "a"
# [5,] "b" "c" "a"
# [6,] "b" "a" "c"
Is it possible to perform some function on a given permutation "on-the-fly" (i.e., a particular row) without storing the result?
That is, if the row == "a" "c" "b" or row == "b" "c" "a", do not store the result. The desired result in this case would be:
# [,1] [,2] [,3]
# [1,] "a" "b" "c"
# [2,] "c" "a" "b"
# [3,] "c" "b" "a"
# [4,] "b" "a" "c"
I know I can apply a function to all the permutations on the fly within combinat::permn with the fun argument such as:
permn(letters[1:3], fun = function(x) {
res <- paste0(x, collapse = "")
if (res == "acb" | res == "bca") {
return(NA)
} else {
return(res)
}
})
But this stills stores an NA and the returned list has 6 elements instead of the desired 4 elements:
# [[1]]
# [1] "abc"
#
# [[2]]
# [1] NA
#
# [[3]]
# [1] "cab"
#
# [[4]]
# [1] "cba"
#
# [[5]]
# [1] NA
#
# [[6]]
# [1] "bac"
Note, I am not interested in subsequently removing the NA values; I am specifically interested in not appending to the result list "on-the-fly" for a given permutation.
We could use a magrittr pipeline where we rbind the input matrix to the Rows to be checked and omit the duplicate rows.
library(combinat)
library(magrittr)
Rows <- rbind(c("a", "c", "b"), c("b", "c", "a"))
do.call(rbind, permn(letters[1:3])) %>%
subset(tail(!duplicated(rbind(Rows, .)), -nrow(Rows)))
giving:
[,1] [,2] [,3]
[1,] "a" "b" "c"
[2,] "c" "a" "b"
[3,] "c" "b" "a"
[4,] "b" "a" "c"
You can return NULL for the particular condition that you want to ignore and rbind the result which will ignore the NULL elements and bind only the combinations that you need.
do.call(rbind, combinat::permn(letters[1:3], function(x)
if(!all(x == c("a", "c", "b") | x == c("b", "c", "a")))
return(x)
))
# [,1] [,2] [,3]
#[1,] "a" "b" "c"
#[2,] "c" "a" "b"
#[3,] "c" "b" "a"
#[4,] "b" "a" "c"
Similarly,
do.call(rbind, permn(letters[1:3],function(x) {
res <- paste0(x, collapse = "")
if (!res %in% c("acb","bca"))
return(res)
}))
# [,1]
#[1,] "abc"
#[2,] "cab"
#[3,] "cba"
#[4,] "bac"
This question already has answers here:
How to generate permutations or combinations of object in R?
(3 answers)
Closed 4 years ago.
Is there a way to generate all the unique sets of the following permutations, where I am able to change N and R easily.
library(gtools)
x <- c("A","B","C","D")
x <- permutations(n=4,r=2,v=x)
x
[,1] [,2]
[1,] "A" "B"
[2,] "A" "C"
[3,] "A" "D"
[4,] "B" "A"
[5,] "B" "C"
[6,] "B" "D"
[7,] "C" "A"
[8,] "C" "B"
[9,] "C" "D"
[10,] "D" "A"
[11,] "D" "B"
[12,] "D" "C"
For example sets 1 and 4 are not unique, AB and BA contain the same characters.
The following list is unique, and this is what I want.
[,1] [,2]
[1,] "A" "B"
[2,] "A" "C"
[3,] "A" "D"
[4,] "B" "C"
[5,] "B" "D"
[6,] "C" "D"
conbn would give you what you need:
#combn gives you the combinations, t is only used to transpose the matrix
t(combn(x, 2))
# [,1] [,2]
#[1,] "A" "B"
#[2,] "A" "C"
#[3,] "A" "D"
#[4,] "B" "C"
#[5,] "B" "D"
#[6,] "C" "D"
I have following input data:
# [,1] [,2]
#[1,] "A" "B"
#[2,] "A" "C"
#[3,] "A" "D"
#[4,] "B" "C"
#[5,] "B" "D"
#[6,] "C" "D"
Next I want to exclude rows where first or second element has been previously for N times. For example if N = 2 then need to exclude following rows:
#[3,] "A" "D" - element "A" has been 2 times
#[5,] "B" "D" - element "B" has been 2 times
#[6,] "C" "D" - element "C" has been 2 times
Note: Need to take into account excluding results immediately. For example if element has met 5 times and after removing it met only 1 times then need to leave next row with this element. Because now it meets 2 times.
Example (N=2):
Input data:
[,1] [,2]
[1,] "A" "B"
[2,] "A" "C"
[3,] "A" "D"
[4,] "A" "E"
[5,] "B" "C"
[6,] "B" "D"
[7,] "B" "E"
[8,] "C" "D"
[9,] "C" "E"
[10,] "D" "E"
Output data:
[,1] [,2]
[1,] "A" "B"
[2,] "A" "C"
[5,] "B" "C"
[10,] "D" "E"
There are possibly more elegant solutions... but this seems to work:
v <- c("A", "B", "C", "D", "E")
cmb <- t(combn(v, 2))
n <- 2
# Go through each letter
for (l in v)
{
# Find the combinations using that letter
rows <- apply(cmb, 1, function(x){l %in% x})
rows.2 <- which(rows==T)
if (length(rows.2)>n)
rows.2 <- rows.2[1:n]
# Take the first n rows containing the letter,
# then append all the ones not containing it
cmb <- rbind(cmb[rows.2,], cmb[rows==F,])
}
cmb
which outputs:
[,1] [,2]
[1,] "D" "E"
[2,] "B" "C"
[3,] "A" "C"
[4,] "A" "B"
I would like to add the individual list name to the last column, respectively. what is the best way to do that efficiently.
lst <- list(a=matrix(runif(10), nrow=5, ncol=2), b=matrix(runif(6), nrow=3, ncol=2))
$a
[,1] [,2]
[1,] 0.5257330 0.52673079
[2,] 0.2103107 0.23357179
[3,] 0.3745236 0.03687697
[4,] 0.9731074 0.15569480
[5,] 0.2248541 0.60258915
$b
[,1] [,2]
[1,] 0.9901820 0.3648310
[2,] 0.8922225 0.4285105
[3,] 0.6963518 0.5795353
I would like this one: it means the individual list name should be added in the last column, respectively.
$a
[,1] [,2] [,3]
[1,] "0.52573303761892" "0.526730791199952" "a"
[2,] "0.210310699883848" "0.233571790158749" "a"
[3,] "0.374523550504819" "0.0368769748602062" "a"
[4,] "0.973107369150966" "0.155694802291691" "a"
[5,] "0.224854125175625" "0.602589153219014" "a"
$b
[,1] [,2] [,3]
[1,] "0.990182007197291" "0.36483103595674" "b"
[2,] "0.892222490161657" "0.42851050500758" "b"
[3,] "0.696351842954755" "0.579535307129845" "b"
Any help will be appreciated.
Kevin
A solution that keeps the names from the original list:
mapply(function(x, y) cbind(x, y), lst, names(lst))
Here's a solution that gives you exactly what you asked for. Based on your expected output, it seems like you're aware that by doing so, you're coercing the numbers in the matrix to characters.
lapply(names(lst), function(x) {
`colnames<-`(cbind(lst[[x]], x), NULL)
} )
# [[1]]
# [,1] [,2] [,3]
# [1,] "0.497699242085218" "0.934705231105909" "a"
# [2,] "0.717618508264422" "0.212142521282658" "a"
# [3,] "0.991906094830483" "0.651673766085878" "a"
# [4,] "0.380035179434344" "0.125555095961317" "a"
# [5,] "0.777445221319795" "0.267220668727532" "a"
#
# [[2]]
# [,1] [,2] [,3]
# [1,] "0.386114092543721" "0.86969084572047" "b"
# [2,] "0.0133903331588954" "0.34034899668768" "b"
# [3,] "0.382387957070023" "0.482080115471035" "b"