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
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.
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
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
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.
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