I am trying to come up with every possible combination of a set number of 1's and 0's in a list, without any overlap. I want the list to contain a series of matrices.
I have come up with the following code, which accomplishes that goal, for example if you want 2 values of 1 and 2 of 0 in a 2x2 matrix:
z<-0
for(i in 1:(4-1)){
for(j in (i+1):(4)){
x<-rep(0,4)
x[c(i,j)]<-1
x<-matrix(x,nrow=2,byrow=TRUE)
z<-z+1
k[[z]]<-x
}}
This is fine, but I would like to be able to create lists involving a larger number of 0's and 1's.
The only way I know how to do this is to nest more and more for loops
For example, in order to print every non-repetitive combination of 3 1's in 9 total spaces in a 3x3 matrix:
for(i in 1:(9-2)){
for(j in (i+1):(9-1)){
for(k in (j+1):9){
x<-rep(0,9)
x[c(i,j,k)]<-1
x<-matrix(x,nrow=3,byrow=TRUE)
print(x)
}}}
I feel like there must be a more elegant and quicker solution(especially when dealing with larger numbers of digits). Even if a simple solution could just give me vectors, it'd be easy enough to make them a list of matrices. I would like variable amounts of 1's and 0's enumerated in a list so that I can use them for further manipulation.
Thank you for your help!
Here's a function to do it. The first argument is the size of the sides of the matrix, the second is the number of ones wanted:
makematrix <- function(n, k){
z <- as.data.frame(t(expand.grid(rep(list(c(0,1)), n * n))))
z <- z[ ,colSums(z) == k]
lapply(z, function(x){matrix(x, nrow = n)})
}
First we make all the combinations of 0 and 1 in a data frame using expand.grid, subset by the ones with the correct number of 1s, then we rearrange them into a list of matrices using lapply.
makematrix(2, 2)
$V4
[,1] [,2]
[1,] 1 0
[2,] 1 0
$V6
[,1] [,2]
[1,] 1 1
[2,] 0 0
$V7
[,1] [,2]
[1,] 0 1
[2,] 1 0
$V10
[,1] [,2]
[1,] 1 0
[2,] 0 1
$V11
[,1] [,2]
[1,] 0 0
[2,] 1 1
$V13
[,1] [,2]
[1,] 0 1
[2,] 0 1
You can also directly use library combinat, which permn function giving a direct list:
library(combinat)
unique(permn(c(1,1,0,0),function(x) matrix(x,nrow=sqrt(length(x)))))
#[[1]]
# [,1] [,2]
#[1,] 1 0
#[2,] 1 0
#[[2]]
# [,1] [,2]
#[1,] 1 1
#[2,] 0 0
#[[3]]
# [,1] [,2]
#[1,] 0 1
#[2,] 1 0
#[[4]]
# [,1] [,2]
#[1,] 0 0
#[2,] 1 1
#[[5]]
# [,1] [,2]
#[1,] 1 0
#[2,] 0 1
#[[6]]
# [,1] [,2]
#[1,] 0 1
#[2,] 0 1
Related
I have seen similar questions to this in my research on this site, but not this exact question (most answers involve creating a sparse matrix from a list).
I have a list of adjacent polygons, but wish to convert it to a full matrix. I can do this rather clunkily with nested for loops, but I am trying to improve my coding by relying less on these. So in essence, what I would like is to get from this:
my_list <- list("1" = c(2, 3),
"2" = 1,
"3" = 1)
to something that looks like this:
# [,1] [,2] [,3]
#[1,] 0 1 1
#[2,] 1 0 0
#[3,] 1 0 0
without resorting to this:
for(i in 1:3{
for(j in 1:3{
[look to list to see if there is a value corresponding to (i, j),
if so insert 1, if not, zero]
}
}
Thank you very much for your time.
You can try sapply and tabulate
nbins <- max(unlist(my_list)) # 3
sapply(my_list, function(x) tabulate(x, nbins = nbins))
# [,1] [,2] [,3]
#[1,] 0 1 1
#[2,] 1 0 0
#[3,] 1 0 0
Could be written without the anonymous function, and with a safety check as
vapply(my_list, tabulate, nbins = nbins, FUN.VALUE = integer(nbins))
You can use sapply :
n <- 1:max(unlist(my_list))
sapply(my_list, function(x) +(n %in% x))
# [,1] [,2] [,3]
#[1,] 0 1 1
#[2,] 1 0 0
#[3,] 1 0 0
I have a matrix and I would like to perform a calculation on each number in the matrix so that I get another matrix with the same dimensions only with the results of the calculation. This should be easy except that part of the equation is dependent on which column I am accessing because I will need to have an internal reference to the number at row [3,] within that column.
The equation I would like to apply is:
output matrix value = input_matrix value at a given position + (1- (matrix value at [3,] and in the same column as the input matrix value))
For example, For (1,1) in the matrix the calculation would be 1+(1-3)
For position (1,2) in the matrix, the calculation would be 5+(1-7)
input_matrix<- matrix(1:12, nrow = 4, ncol = 3)
[,1] [,2] [,3]
[1,] 1 5 9
[2,] 2 6 10
[3,] 3 7 11
[4,] 4 8 12
The output matrix should end up looking like this:
[,1] [,2] [,3]
[1,] -1 -1 -1
[2,] 0 0 0
[3,] 1 1 1
[4,] 2 2 2
I have tried doing something like this:
output_matrix<-apply(input_matrix,c(1,2), function(x) x+(1-(input_matrix[3,])))
but that gives me three matrices with the wrong dimensions as the output.
I am thinking that perhaps I can perhaps just modify the function in the above calculation to get this to work, or alternatively write something that iterates over each column of the matrix but I am not sure exactly how to do this in a way that gives me the output matrix that I want.
Any help would be greatly appreciated.
I think this should work for you:
apply(input_matrix, margin = 2, function(x) x + (1 - x[3]))
[,1] [,2] [,3]
[1,] -1 -1 -1
[2,] 0 0 0
[3,] 1 1 1
[4,] 2 2 2
We could also do this in a vectorized way
input_matrix + (1 - input_matrix[3,][col(input_matrix)])
# [,1] [,2] [,3]
#[1,] -1 -1 -1
#[2,] 0 0 0
#[3,] 1 1 1
#[4,] 2 2 2
I have a 2x2x10 array of identity matrices, created with
arr = array(diag(2), dim=c(2,2,10))
I'm looking to multiply each 2x2 matrix within that array by a scalar c(1:10)
z = arr[,,1:10] * c(1:10)
However, I'm getting unexpected results. The first three 2x2 matrices of z shown below
, , 1
[,1] [,2]
[1,] 1 0
[2,] 0 4
, , 2
[,1] [,2]
[1,] 5 0
[2,] 0 8
, , 3
[,1] [,2]
[1,] 9 0
[2,] 0 2
Am I missing something?
We need to replicate to make the lengths same
arr[,,1:10] * rep(1:10, each = length(arr[,, 1]))
or else 1 gets multiplied by the first element of arr[, , 1] 2 with the second element of arr[,, 1] and due to recycling the elements of shorter vector is recycled until the length of arr[, , 1:10]
sweep() is designed for this:
sweep(arr, 3, 1:10, `*`)
, , 1
[,1] [,2]
[1,] 1 0
[2,] 0 1
, , 2
[,1] [,2]
[1,] 2 0
[2,] 0 2
, , 3
[,1] [,2]
[1,] 3 0
[2,] 0 3
...
I am trying to fill some rows of a (500,2) matrix with the row vector (1,0) using this code, last line is to verify the result:
data<-matrix(ncol=2,nrow=500)
data[41:150,]<-matrix(c(1,0),nrow=1,ncol=2,byrow=TRUE)
data[41:45,]
But the result is
> data[41:45,]
[,1] [,2]
[1,] 1 1
[2,] 0 0
[3,] 1 1
[4,] 0 0
[5,] 1 1
instead of
> data[41:45,]
[,1] [,2]
[1,] 1 0
[2,] 1 0
[3,] 1 0
[4,] 1 0
[5,] 1 0
(1) What am I doing wrong?
(2) Why aren't the row indices in the result 41, 42, 43, 44 and 45?
You're trying to fill a part of the matrix, so the block you're trying to drop in there should be of the right size:
data[41:150,]<-matrix(c(1,0),nrow=110,ncol=2,byrow=TRUE)
# nrow = 110, instead of 1 !!!!
Otherwise your piece-to-be-added will be reverted to vector and added columnwise. Try, for example, this:
data[41:150,] <- matrix(c(1,2,3,4,5), nrow=5, ncol=2, byrow=TRUE)
data[41:45,]
[,1] [,2]
[1,] 1 1
[2,] 3 3
[3,] 5 5
[4,] 2 2
[5,] 4 4
Can one complain? Yes, and now. No, because R behaves as documented (matrices are vectors with dimension attributes, and recycling works on vectors). Yes, because although recycling can be convenient, it may create false expectations.
Why aren't row indices 41,42,43,... ? I don't know, that's just the way matrices and vectors behave.
> (1:10)[5:6]
[1] 5 6
(Notice there's [1] in the output, not [5].)
Data frames behave differently, so you would see the original line numbers for slices:
as.data.frame(data)[45:50,]
It will be cleaner to just do this column-wise:
data[41:150, 1L] = 1
data[41:150, 2L] = 0
You could also accomplish this in one line with matrix indexing like so:
data[cbind(rep(41:150, each = 2L), 1:2)] = 1:0
You could use rep.
data[41:150,] <- rep(1:0, each=150-41+1)
#> data[41:45,]
# [,1] [,2]
#[1,] 1 0
#[2,] 1 0
#[3,] 1 0
#[4,] 1 0
#[5,] 1 0
I think MichaelChirico approach is the cleanest/savest to use.
This question already has answers here:
How to replace non-diagonal elements in a matrix?
(6 answers)
Closed 9 years ago.
Okay, I asked this question earlier but I got bashed (deservedly) for not specifying anything and showing no sign of previous attempt. So let me try again..
I'm using R, and I have a 463✕463 matrix. What I would like to do is to replace all elements other than the diagonal ones (X11, X22, X33,...,Xjj) with zero.
E.g. I want:
[1 4 5
2 3 5
3 9 8]
to be:
[1 0 0
0 3 0
0 0 8]
When I use the diag() function, it simply gives me a column vector of the diagonal values. I imagine I can use the replace() function somehow combined with a "if not diagonal" logic...but I am lost.
And yes, as some here have guessed, I am probably much younger than many people here and am completely new at this...so please put me in the right direction. Really appreciate all your help!
In R, the diag method has two functions.
It returns the diagonal of a matrix. I.e.
m <- matrix(1:9, ncol=3)
m
# [,1] [,2] [,3]
# [1,] 1 4 7
# [2,] 2 5 8
# [3,] 3 6 9
diag(m)
# [1] 1 5 9
It can construct a diagonal matrix.
diag(1:3)
# [,1] [,2] [,3]
# [1,] 1 0 0
# [2,] 0 2 0
# [3,] 0 0 3
So in your case, extract the diagonal from your existing matrix and supply it to diag:
diag(diag(m))
# [,1] [,2] [,3]
# [1,] 1 0 0
# [2,] 0 5 0
# [3,] 0 0 9
using outer
You can use the following to compute a logical matrix which describes the non-diagonal entries of a n×n matrix:
outer(1:n, 1:n, function(i,j) i!=j)
Applied to your example:
> m <- matrix(c(1,2,3,4,3,9,5,5,8),ncol=3)
> m
[,1] [,2] [,3]
[1,] 1 4 5
[2,] 2 3 5
[3,] 3 9 8
> m[outer(1:3, 1:3, function(i,j) i!=j)] <- 0
> m
[,1] [,2] [,3]
[1,] 1 0 0
[2,] 0 3 0
[3,] 0 0 8
using triangles
A possible alternative would be combining the two triangles on either side of the diagonal. In this case, you use the matrix m itself as input to determine the size.
upper.tri(m) | lower.tri(m)
Applied to your use case:
> m[upper.tri(m) | lower.tri(m)] <- 0
It seems you already got this answer in response to your original post…
m[ col(m)==row(m) ] <- 0
> m <- matrix(1:9, 3)
> m[ col(m)==row(m) ]
[1] 1 5 9
> m[ col(m)!=row(m) ] <- 0
> m
[,1] [,2] [,3]
[1,] 1 0 0
[2,] 0 5 0
[3,] 0 0 9