Hi I'm pretty much stumped on on trying to figure this out and could use a little help. Basically, I have a n x n matrix where the diagonal is set to a value k and every other value is 0.
1 2 3 4 5
1 k 0 0 0 0
2 0 k 0 0 0
3 0 0 k 0 0
4 0 0 0 k 0
5 0 0 0 0 k
Basically, I need to be able to make two other diagonals in this matrix with the value of 1 so it ends up looking like this:
1 2 3 4 5
1 k 1 0 0 0
2 1 k 1 0 0
3 0 1 k 1 0
4 0 0 1 k 1
5 0 0 0 1 k
So far all I have for code is being able to make the diagonal matrix
m=diag(k,n,n) but I have no idea on how to add the two other diagonals. Would I use apply() and cbind() or rbind()?
You can use col and row to create and index to subset and assign the upper and lower diagonals.
k=3
m <- k* diag(6)
m[abs(row(m) - col(m)) == 1] <- 1
m
# [,1] [,2] [,3] [,4] [,5] [,6]
#[1,] 3 1 0 0 0 0
#[2,] 1 3 1 0 0 0
#[3,] 0 1 3 1 0 0
#[4,] 0 0 1 3 1 0
#[5,] 0 0 0 1 3 1
#[6,] 0 0 0 0 1 3
If you wanted reverse diagonals you could use col(m) - row(m)
Try this function, it will make a matrix of dimensions row X col and diagonal of the numeric n.
matfun <- function(diag=n, row=4,col=4){
x = diag(1,row,col)
diag*x+rbind(as.vector(rep(0,col)),x[1:(row-1),])+cbind(as.vector(rep(0,row)),x[,1:(col-1)])
}
HTH
Related
How can I create dummy variables from a numeric variable in R?
I want to create N dummy variables. In such a way the numeric variable means how many zeros will come, counting from the first column. Imagine N=6. Like this:
x
a 5
b 2
c 4
d 1
e 9
It must become:
1 2 3 4 5 6
a 0 0 0 0 0 1
b 0 0 1 1 1 1
c 0 0 0 0 1 1
d 0 1 1 1 1 1
e 0 0 0 0 0 0
Thank you!
Here's a hacky solution for you
x = c(5,2,4,1,9)
N = 6
out = matrix(1, length(x), N)
for (i in 1:length(x))
out[i,1:min(x[i], N)] = 0
> out
[,1] [,2] [,3] [,4] [,5] [,6]
[1,] 0 0 0 0 0 1
[2,] 0 0 1 1 1 1
[3,] 0 0 0 0 1 1
[4,] 0 1 1 1 1 1
[5,] 0 0 0 0 0 0
We could do this in a vectorized manner by creating row/column index and assigning an already created matrix of 1s to 0 based on the index
m1 <- matrix(1, ncol = N, nrow = length(x),
dimnames = list(letters[seq_along(x)], seq_len(N)))
x1 <- pmin(x, ncol(m1))
m1[cbind(rep(seq_len(nrow(m1)), x1), sequence(x1))] <- 0
m1
# 1 2 3 4 5 6
#a 0 0 0 0 0 1
#b 0 0 1 1 1 1
#c 0 0 0 0 1 1
#d 0 1 1 1 1 1
#e 0 0 0 0 0 0
data
x <- c(5,2,4,1,9)
N <- 6
I would like to create the following vector sequence.
0 1 0 0 2 0 0 0 3 0 0 0 0 4
My thought was to create 0 first with rep() but not sure how to add the 1:4.
Create a diagonal matrix, take the upper triangle, and remove the first element:
d <- diag(0:4)
d[upper.tri(d, TRUE)][-1L]
# [1] 0 1 0 0 2 0 0 0 3 0 0 0 0 4
If you prefer a one-liner that makes no global assignments, wrap it up in a function:
(function() { d <- diag(0:4); d[upper.tri(d, TRUE)][-1L] })()
# [1] 0 1 0 0 2 0 0 0 3 0 0 0 0 4
And for code golf purposes, here's another variation using d from above:
d[!lower.tri(d)][-1L]
# [1] 0 1 0 0 2 0 0 0 3 0 0 0 0 4
rep and rbind up to their old tricks:
rep(rbind(0,1:4),rbind(1:4,1))
#[1] 0 1 0 0 2 0 0 0 3 0 0 0 0 4
This essentially creates 2 matrices, one for the value, and one for how many times the value is repeated. rep does not care if an input is a matrix, as it will just flatten it back to a vector going down each column in order.
rbind(0,1:4)
# [,1] [,2] [,3] [,4]
#[1,] 0 0 0 0
#[2,] 1 2 3 4
rbind(1:4,1)
# [,1] [,2] [,3] [,4]
#[1,] 1 2 3 4
#[2,] 1 1 1 1
You can use rep() to create a sequence that has n + 1 of each value:
n <- 4
myseq <- rep(seq_len(n), seq_len(n) + 1)
# [1] 1 1 2 2 2 3 3 3 3 4 4 4 4 4
Then you can use diff() to find the elements you want. You need to append a 1 to the end of the diff() output, since you always want the last value.
c(diff(myseq), 1)
# [1] 0 1 0 0 1 0 0 0 1 0 0 0 0 1
Then you just need to multiply the original sequence with the diff() output.
myseq <- myseq * c(diff(myseq), 1)
myseq
# [1] 0 1 0 0 2 0 0 0 3 0 0 0 0 4
unlist(lapply(1:4, function(i) c(rep(0,i),i)))
# the sequence
s = 1:4
# create zeros vector
vec = rep(0, sum(s+1))
# assign the sequence to the corresponding position in the zeros vector
vec[cumsum(s+1)] <- s
vec
# [1] 0 1 0 0 2 0 0 0 3 0 0 0 0 4
Or to be more succinct, use replace:
replace(rep(0, sum(s+1)), cumsum(s+1), s)
# [1] 0 1 0 0 2 0 0 0 3 0 0 0 0 4
I have a column as below. Only for non-null elements, I want to get a matrix
such as below. 6th column represent the actual value.
1 0 0 0 0 1
0 1 0 0 0 2
0 0 0 1 0 5
Any hint what is the efficient way to do this? which commands should I use? I am thinking of writing a if loop within for loop, but don't think it will be very efficient :(
abc=c('1','2','null','5','null')
Assuming there is an error in your example, this is just a dummy variable coding essentially:
abc <- c('1','2','null','5','null')
abc <- factor(abc,levels=1:5)
cbind(model.matrix(~abc+0),orig=na.omit(abc))
# abc1 abc2 abc3 abc4 abc5 orig
#1 1 0 0 0 0 1
#2 0 1 0 0 0 2
#4 0 0 0 0 1 5
If you want to automatically calculate the range of possible factors, try:
abc <- c('1','2','null','5','null')
rng <- range(as.numeric(abc),na.rm=TRUE)
abc <- factor(abc,levels=seq(rng[1],rng[2]))
cbind(model.matrix(~abc+0),orig=na.omit(abc))
# abc1 abc2 abc3 abc4 abc5 orig
#1 1 0 0 0 0 1
#2 0 1 0 0 0 2
#4 0 0 0 0 1 5
It's not clear why that matrix is six elements wide but if it is length(abc)+1 then just substitute that expression for my use of 6.
> abcn <- as.numeric(abc)
> zero <- matrix(0,nrow=length(abcn[!is.na(abcn)]), ncol=6)
> zero[ cbind(1:3, which( !is.na(abcn)) ) ] <- 1
> zero[ , 6] <- abcn[!is.na(abcn)]
> zero
[,1] [,2] [,3] [,4] [,5] [,6]
[1,] 1 0 0 0 0 1
[2,] 0 1 0 0 0 2
[3,] 0 0 0 1 0 5
You can index teh [<- function for matrices with a two coulmn matrix and that's what I'm doing in the third line. The rest of it is ordinary matrix indexing.
I have an R Question. I have an algorithm in mind which does this, but was wondering if there are neater ways of doing the following:
Say you have the following matrix:
[,1] [,2] [,3] [,4] [,5]
[A,] 0 0 0 0 1
[B,] 0 0 0 1 1
[C,] 0 0 1 1 1
[D,] 0 0 1 1 0
[E,] 1 0 0 0 0
[F,] 1 1 1 0 0
Now I want to create another matrix of the differences of each row to another row (i.e., matrix of distances) something like (although I have it half filled, it is just mirror to get top part):
[,A] [,B] [,C] [,D] [,E] [,F]
[A,] 0
[B,] 1 0
[C,] 2 1 0
[D,] 3 2 1 0
[E,] 2 3 4 3 0
[F,] 4 5 4 3 2 0
My method is to use a loop comparing each row's columns with corresponding columns of rows below, but with large matrices its not efficient. Any ideas on how to do this better?
thx
As said in the comment using dist with manhattan method:
dt <- read.table(text=' [,1] [,2] [,3] [,4] [,5]
[A,] 0 0 0 0 1
[B,] 0 0 0 1 1
[C,] 0 0 1 1 1
[D,] 0 0 1 1 0
[E,] 1 0 0 0 0
[F,] 1 1 1 0 0')
mm <- as.matrix(dt)
dist(mm,method='manhattan' ,diag=TRUE)
[A,] [B,] [C,] [D,] [E,] [F,]
[A,] 0
[B,] 1 0
[C,] 2 1 0
[D,] 3 2 1 0
[E,] 2 3 4 3 0
[F,] 4 5 4 3 2 0
I am working on educational assignment to produce an Incidence matrix from a BIB design using R language software.
I found a web page http://wiki.math.yorku.ca/index.php/R:_Incidence_matrix related to problem. But it produces Data matrix instead of Incidence matrix. can anyone please help me out with R language code. the codes for obtaining the BIB design matrix is:
b=4 # Number of Blocks
t=8 # Number of Column
z=c(1,2,3) # Shift
m=NULL
y=c(0)
w=c(y,cumsum(z) %%t) # cumsum() is for the running totals
p=seq(from=0, to=t-1, by=1)
l=NULL
for(i in 1:b)
{
for(j in 1:t)
{
l=c(l,rep((w[i]+p[j]+t)%% t))
}
}
#"BIB design" it has 4 rows (blocks b) and 8 column (treatments t)
x= matrix(c(l),nrow=b,ncol=t,byrow = TRUE)
print (x)
0 1 2 3 4 5 6 7
1 2 3 4 5 6 7 0
3 4 5 6 7 0 1 2
6 7 0 1 2 3 4 5
(it can be generated at any t-treatments and b-blocks size generally)
using above design matrix x (4*8). i need the following Incidence matrix (8*8)
1 1 0 1 0 0 1 0
0 1 1 0 1 0 0 1
1 0 1 1 0 1 0 0
0 1 0 1 1 0 1 0
0 0 1 0 1 1 0 1
0 1 0 0 1 0 1 1
1 0 1 0 0 1 0 1
Consider Design Matrix Column wise and generate Incidence Matrix Row wise. For example the 1st column of x is
0
1
6
3
Now see the 1st row of the required Incidence Matrix (IM).
1 1 0 1 0 0 1 0
At 1st place of x is 0 so put 1 in 1st place of IM.
At 2nd place of x is 1 so put also 1 at the 2nd place of IM.
Here 2 is missing in the column of x so put 0 at 3rd place of IM.
x contains 3 so put 1 at 4th place, 4 and 5 is missing put two 0's in a row consecutively.
X has 6 put 1 at 7th place and 7 is missing put 0 at 8th place of IM.
Take 2nd column of x and similarly filled 2nd row of IM. If the particular number (0 to 7) is present put one otherwise zero.
I hope, i make it clear for every one now.
Making the x matrix different to have two identical entries in one column I get this logic to work:
x[4,1] <- 1
t( apply(x, 2, function(z){ ret <- numeric(8)
for( i in seq_along(z) ){ret[z[i]+1] <- ret[z[i]+1]+ 1}
ret}) )
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8]
[1,] 1 2 0 1 0 0 0 0
[2,] 0 1 1 0 1 0 0 1
[3,] 1 0 1 1 0 1 0 0
[4,] 0 1 0 1 1 0 1 0
[5,] 0 0 1 0 1 1 0 1
[6,] 1 0 0 1 0 1 1 0
[7,] 0 1 0 0 1 0 1 1
[8,] 1 0 1 0 0 1 0 1
I'm not exactly sure how you are going by getting your intended output. However, the reason you are getting a much longer output than you anticipated is possibly due to the [ as.factor(vec),] part of your code .
as.factor(vec) is taking your 4x4 matrix and turning it into a single vector of 16 elements. (Well, technically, vec is already a vector, but let's not confuse things).
as.factor(vec)
[1] 0 1 3 2 1 2 0 3 2 3 1 0 3 0 2 1
Levels: 0 1 2 3
You are then using that as an index, which is repeating values of A.
** By the way, are you sure you should get a matrix of all 1's? And not perhaps just 1's on the diagonal?
contrasts( as.factor(vec), contrasts =FALSE)
# 0 1 2 3
# 0 1 0 0 0
# 1 0 1 0 0
# 2 0 0 1 0
# 3 0 0 0 1