How to replace non diagonal elements of matrix by row? - r

I would like to replace non diagonal elements of matrix with a
sequence of numbers.
I managed to write this:
mat[outer(1:nrows(mat), 1:nrows(mat), function(i,j) j!=i)] <- seq(1:182)
But it fills the number by column. I would not like to use the
transpose function as I have specific row name which I would like to
keep.
Example
So if I have a matrix m
m <- matrix(NA, nrow=5, ncol=5, dimnames=list(letters[1:5], NULL))
m
# [,1] [,2] [,3] [,4] [,5]
# a NA NA NA NA NA
# b NA NA NA NA NA
# c NA NA NA NA NA
# d NA NA NA NA NA
# e NA NA NA NA NA
How can I add a sequence to the non-diagonals while keeping the rownames of the original matrix: expected output
# [,1] [,2] [,3] [,4] [,5]
# a NA 1 2 3 4
# b 5 NA 6 7 8
# c 9 10 NA 11 12
# d 13 14 15 NA 16
# e 17 18 19 20 NA

We can try
mat[lower.tri(mat, diag=FALSE)|upper.tri(mat, diag=FALSE)] <- 1:182
Or
mat[!diag(ncol(mat))] <- 1:182
Using a small example in OP's post
m[!diag(ncol(m))] <- 1:20
out <- t(m)
dimnames(out) <- rev(dimnames(out))
Used rev from #user20650's comments

Related

Multiplication of matrices with NA values

If I have 2 square Matrices with random NA values, for example:
Matrix A:
1 2 3
1 5 NA 7
2 NA 3 8
3 NA 4 5
Matrix B:
1 2 3
1 NA 8 NA
2 2 5 9
3 NA 4 3
What is the best way to multiply them? Would changing NA values to 0 give a different result of the dot product?
NAs will be ignored:
## Dummy matrices
mat1 <- matrix(sample(1:9, 9), 3, 3)
mat2 <- matrix(sample(1:9, 9), 3, 3)
## Adding NAs
mat1[sample(1:9, 4)] <- NA
mat2[sample(1:9, 4)] <- NA
mat1
# [,1] [,2] [,3]
#[1,] 9 NA 3
#[2,] 2 NA NA
#[3,] NA 1 8
mat2
# [,1] [,2] [,3]
#[1,] NA NA 4
#[2,] NA 9 3
#[3,] NA 7 1
mat1 * mat2
# [,1] [,2] [,3]
#[1,] NA NA 12
#[2,] NA NA NA
#[3,] NA 7 8
mat1 %*% mat2
# [,1] [,2] [,3]
#[1,] NA NA NA
#[2,] NA NA NA
#[3,] NA NA NA
In this case the dot product results in only NAs because there are no operations that does not involve an NA. Different matrices can lead to different results.

Transforming NA to specific arrays of a matrix in R

I have a matrix of the form,
mat <- matrix(1:25, 5,5)
that looks like the following:
Now, I need to transform this matrix in the form as shown below:
That is, I want to keep all elements of row 2 and 4 as well as column 2 and 4 and replace all other values with NA. This a just a simple example to explain the problem. My actual matrix size is about 2000 X 2000. Any help would be much appreciated.
Your first and second matrices are a different in that the first one is filled as R would fill a matrix (i.e. column-major order) and the second is row-major.
Assuming that you meant to have identical matrices, your task can be addressed with simple matrix operations:
mat <- matrix(1:25, 5,5)
mat2 <- matrix(NA, 5,5)
mat2[c(2,4),] <- 1
mat2[,c(2,4)] <- 1
mat * mat2
[,1] [,2] [,3] [,4] [,5]
[1,] NA 6 NA 16 NA
[2,] 2 7 12 17 22
[3,] NA 8 NA 18 NA
[4,] 4 9 14 19 24
[5,] NA 10 NA 20 NA
If not, just transpose your initial matrix with t(mat) and follow the same approach as above.
mat = t(mat)
replace(x = mat, which((matrix(row(mat) %in% c(2, 4), NROW(mat), NCOL(mat)) |
matrix(col(mat) %in% c(2, 4), NROW(mat), NCOL(mat))) == FALSE,
arr.ind = TRUE), NA)
# [,1] [,2] [,3] [,4] [,5]
#[1,] NA 2 NA 4 NA
#[2,] 6 7 8 9 10
#[3,] NA 12 NA 14 NA
#[4,] 16 17 18 19 20
#[5,] NA 22 NA 24 NA

Produce a triangular matrix of integers increasing by 1

I am trying to produce a matrix of variable dimensions of the form below (i.e. integers increasing by 1 at a time, with a lower triangle of NAs)
NA 1 2 3 4
NA NA 5 6 7
NA NA NA 8 9
NA NA NA NA 10
NA NA NA NA 11
I have used the below code
sample_vector <- c(1:(total_nodes^2))
sample_matrix <- matrix(sample_vector, nrow=total_nodes, byrow=FALSE)
sample_matrix[lower.tri(sample_matrix, diag = TRUE)] <- NA
However the matrix I get with this method is of the form:
NA 2 3 4 5
NA NA 8 9 10
NA NA NA 14 15
NA NA NA NA 20
NA NA NA NA 25
How about this
total_nodes <- 5
sample_matrix <- matrix(NA, nrow=total_nodes, ncol=total_nodes)
sample_matrix[lower.tri(sample_matrix)]<-1:sum(lower.tri(sample_matrix))
sample_matrix <- t(sample_matrix)
sample_matrix
# [,1] [,2] [,3] [,4] [,5]
# [1,] NA 1 2 3 4
# [2,] NA NA 5 6 7
# [3,] NA NA NA 8 9
# [4,] NA NA NA NA 10
# [5,] NA NA NA NA NA
I'm using the diag function to construct a matrix and upper.tri to turn it into a "target" aas well as a logical indexing tool:
upr5 <- upper.tri(diag(5))
upr5
upr5[upr5] <- 1:sum(upr5)
upr5[upr5==0] <- NA # would otherwise have been zeroes
upr5
[,1] [,2] [,3] [,4] [,5]
[1,] NA 1 2 4 7
[2,] NA NA 3 5 8
[3,] NA NA NA 6 9
[4,] NA NA NA NA 10
[5,] NA NA NA NA NA

R: Error: new columns would leave holes after existing columns

When running this code, I get the following error:
Error in `[<-.data.frame`(`*tmp*`, , i, value = list(x = 0.0654882985934691, :
new columns would leave holes after existing columns
I am trying to populate a data.frame with i number of columns, which with the output of the posted for loop should look like something like this (Excel example for convenience only):
The aim is to store the output of the loop in such a way that I can get the average of each column at a later stage.
What can be done to achieve this?
library(plyr)
library(forecast)
library(vars)
x <- rnorm(70)
y <- rnorm(70)
dx <- cbind(x,y)
dx <- as.ts(dx)
# Forecast Accuracy
j = 12 #Forecast horizon
k = nrow(dx)-j #length of minimum training set
prediction <- data.frame()
for (i in 1:j) {
trainingset <- window(dx, end = k+i-1)
testset <- window(dx, start = k+i, end = k+j)
fit <- VAR(trainingset, p = 2)
fcast <- forecast(fit, h = j-i+1)
fcastmean <- do.call('cbind', fcast[['mean']])
fcastmean <- as.data.frame(fcastmean)
prediction[,i] <- rbind(fcastmean[,1])
}
Edit
As per the comment below, I have edited the above code to specify the first variable of fcastmean.
The error I get has however changed as a result, now being:
Error in `[<-.data.frame`(`*tmp*`, , i, value = c(-0.316529962287372, :
replacement has 1 row, data has 0
Edit 2
Below is the minimum replicable version without any packages as requested in the comments. I believe that should be equivalent in terms of the question posed.
x <- rnorm(70)
y <- rnorm(70)
dx <- cbind(x,y)
dx <- as.ts(dx)
j = 12
k = nrow(dx)-j
prediction <- matrix(NA,j,j)
for (i in 1:j) {
fcast <- as.matrix(1:(j-i+1))
fcastmean <- fcast
prediction[,i] <- (fcastmean)
}
For your new example, try
sapply(1:j, function(i) `length<-`(1:(j-i+1), j))
The result is
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] [,12]
[1,] 1 1 1 1 1 1 1 1 1 1 1 1
[2,] 2 2 2 2 2 2 2 2 2 2 2 NA
[3,] 3 3 3 3 3 3 3 3 3 3 NA NA
[4,] 4 4 4 4 4 4 4 4 4 NA NA NA
[5,] 5 5 5 5 5 5 5 5 NA NA NA NA
[6,] 6 6 6 6 6 6 6 NA NA NA NA NA
[7,] 7 7 7 7 7 7 NA NA NA NA NA NA
[8,] 8 8 8 8 8 NA NA NA NA NA NA NA
[9,] 9 9 9 9 NA NA NA NA NA NA NA NA
[10,] 10 10 10 NA NA NA NA NA NA NA NA NA
[11,] 11 11 NA NA NA NA NA NA NA NA NA NA
[12,] 12 NA NA NA NA NA NA NA NA NA NA NA
`length<-`(x, j) pads x with NA until it reaches a length of j.
You can replace 1:(j-i+1) with whatever function of i you want. In the OP's original example, I am guessing something like this will work (untested):
sapply(1:j, function(i){
trainingset <- window(dx, end = k+i-1)
# testset <- window(dx, start = k+i, end = k+j)
# ^ this isn't actually used...
fit <- VAR(trainingset, p = 2)
fcast <- forecast(fit, h = j-i+1)
`length<-`(fcast$mean, j)
})
function(i){...} is called an anonymous function and can be written like any other.

Add new columns to every matrices in a list of matrices in R

I have a list of matrices with 61 matrices. Below is an example of one of the 61 matrices.
list_matrix_Tanzania_Mod500
[[60]]
LU_2000
[1,] 12
[2,] 12
[3,] 12
[4,] 12
[5,] 12
[6,] 12
[7,] 12
[8,] 12
[9,] 12
[10,] 11
[11,] 11
[12,] 12
[13,] 11
[14,] 12
[15,] 12
I want to add 10 new colums to every matrices of the list of matrices. Once I have added these new columns, I want to give a header name to each columns with a value NA: "ID", "LU_1990", "CHLU_90_00", "LU_2005", "CHLU_00_05", "Tile", "UNIQ_ID", "AREA", "Sour_90_00", "Sour_00_05"
I now want to fill in the list of matrices list_matrix_Tanzania_Modis with several matrices: LU_Mod2000, LU_Mod2005 and list_matrix_Tanzania. I tried this but the column are not updated well. Fot instance, when I run the Mapcode line for the LU_Mod2005, the values of LU_2000 are erased from the matrices.
columnsToTransfer1 <- 'LU_2000'
columnsToTransfer2 <- 'LU_2005'
columnsToTransfer3<- ('ID', 'Tile', 'UNIQ_ID')
Map(function(x,y,z) {x[,z] <- y[,z];x},
list_matrix_Tanzania_Modis, LU_Mod2000, columnsToTransfer1)
Map(function(x,y,z) {x[,z] <- y[,z];x},
list_matrix_Tanzania_Modis, LU_Mod2005, columnsToTransfer2)
Map(function(x,y,z) {x[,z] <- y[,z];x},
list_matrix_Tanzania_Modis, list_matrix_Tanzania, columnsToTransfer3)
This trick is working but I would like to keep the name of the list of matrices as list_matrix_Tanzania_Modis
list_matrix_Tanzania_Modis1<- Map(function(x,y,z) {x[,z] <- y[,z];x},
list_matrix_Tanzania_Modis, LU_Mod2000, columnsToTransfer1)
list_matrix_Tanzania_Modis2<-Map(function(x,y,z) {x[,z] <- y[,z];x},
list_matrix_Tanzania_Modis1, LU_Mod2005, columnsToTransfer2)
If I understand correctly, a simple cbind should work after creating an empty matrix of the correct dimensions:
Sample input:
L <- list(matrix(1:3, ncol = 1, dimnames = list(NULL, "a")),
matrix(1:5, ncol = 1, dimnames = list(NULL, "b")))
L
# [[1]]
# a
# [1,] 1
# [2,] 2
# [3,] 3
#
# [[2]]
# b
# [1,] 1
# [2,] 2
# [3,] 3
# [4,] 4
# [5,] 5
The new columns you want to add:
newcols <- c("ID", "LU_1990", "CHLU_90_00", "LU_2005", "CHLU_00_05",
"Tile", "UNIQ_ID", "AREA", "Sour_90_00", "Sour_00_05")
Use lapply to cycle through the list, adding the relevant empty columns to each list item.
myNewList <- lapply(L, function(x) {
M <- matrix(NA, nrow = nrow(x), ncol = 10, dimnames = list(NULL, newcols))
cbind(x, M)
})
myNewList
# [[1]]
# a ID LU_1990 CHLU_90_00 LU_2005 CHLU_00_05 Tile UNIQ_ID AREA Sour_90_00 Sour_00_05
# [1,] 1 NA NA NA NA NA NA NA NA NA NA
# [2,] 2 NA NA NA NA NA NA NA NA NA NA
# [3,] 3 NA NA NA NA NA NA NA NA NA NA
#
# [[2]]
# b ID LU_1990 CHLU_90_00 LU_2005 CHLU_00_05 Tile UNIQ_ID AREA Sour_90_00 Sour_00_05
# [1,] 1 NA NA NA NA NA NA NA NA NA NA
# [2,] 2 NA NA NA NA NA NA NA NA NA NA
# [3,] 3 NA NA NA NA NA NA NA NA NA NA
# [4,] 4 NA NA NA NA NA NA NA NA NA NA
# [5,] 5 NA NA NA NA NA NA NA NA NA NA

Resources