Dividing matrices with unequal dimensions in r
I have a data set that I had filtered into a single month. I also have a list of matrices (l1
) that is the same length as the list of data frames (int1
). The matrices in the list have different dimensions (e.g.,3x3, 2x2).
Setting the data and list:
library(lubridate)
library(tidyverse)
library(purrr)
date <- rep_len(seq(dmy("26-12-2010"), dmy("13-07-2011"), by = "days"), 200)
ID <- rep(c("A","B"), 100)
df <- data.frame(date = date,
x = runif(length(date), min = 60000, max = 80000),
y = runif(length(date), min = 800000, max = 900000),
ID)
df$jDate <- julian(as.Date(df$date), origin = as.Date('1970-01-01'))
df$Month <- month(df$date)
# First 10-day interval for `A`
t1 <- c(100,150,200)
# Second 10-day interval for `A`
t2 <- c(200,250,350)
# Third 10-day interval for `A`
t3 <- c(300,350, 400)
mat <- cbind(t1,t2, t3)
# First 10-day interval for `B`
t1 <- c(150,150)
# Second 10-day interval for `B`
t2 <- c(250,250)
mat2 <- cbind(t1,t2)
l1 <- list(mat, mat2)
int1 <- df %>%
# arrange(ID) %>% # skipped for readability of result
mutate(new = floor_date(date, '10 day')) %>%
mutate(new = if_else(day(new) == 31, new - days(10), new)) %>%
group_by(ID, new) %>%
filter(Month == "3") %>%
group_split()
The code below attempts to divide lstMat
from l1
. The problem that I am running into is that matrices in lstMat
do not have the same dimensions as the matrices in l1
. Due this discrepency, when I try and divide one from the other I receive the error message: Error in .x/.y : non-conformable arrays
g1 <- as.integer(gl(length(int1), 3, length(int1)))
f2 <- function(.int1, .int2) {
t(outer(seq_along(.int1), seq_along(.int2),
FUN = Vectorize(function(i, j) min(.int1[[i]]$jDate) -
min(.int2[[j]]$jDate))))
}
lstMat <- map2(split(int1, g1), split(int1, g1), f2)
map2(l1, lstMat[1:2], `/`)
Any thoughts on how I can modify this code to allow for differences in matrices with the list?
Problem:
I have matrices with different dimensions that I have been trying to divide. Let say I run a custom function and end with l1
. The matrices in l1
correspond to the 10-day intervals in int1
, but we didn't get an output for the third 10-day interval for ID
B
hence a 2x2 matrix.
Rules:
In this case, I would like to remove the third column from lstMat[[2]]
because that is the one missing from l1[[2]]
. This wouldn't always be the case, for example if the second 10-day interval was missing from l1[[2]]
, then I would want to remove the second column in lsMat[[2]]
.
I would like to link lstMat
and l1
through the use of int1
based on the specific intervals that end up getting removed from lstMat
.
I hope I didn't make this more confusing. I apologize if I did.
Thank you for your time.
Solution 1:
Here the 'g1' needs to be dynamic based on the number of rows/dimensions of each of the elements in 'lstMat'. This can be done with rep
library(purrr)
g1 <- rep(seq_along(lstMat), sapply(lstMat, nrow))
lstMat <- map2(split(int1, g1), split(int1, g1), f2)
map2(l1, lstMat[1:2], `/`)
[[1]]
t1 t2 t3
[1,] Inf 20 15
[2,] -15 Inf 35
[3,] -10 -35 Inf
[[2]]
t1 t2
[1,] Inf 25
[2,] -15 Inf
Some values are Inf
only because we have some values in the 'lstMat' as '0'
lstMat[1:2]
$`1`
[,1] [,2] [,3]
[1,] 0 10 20
[2,] -10 0 10
[3,] -20 -10 0
$`2`
[,1] [,2]
[1,] 0 10
[2,] -10 0
Thus any value divided by 0 returns Inf