Search code examples
rmathmatrixfinancequantitative-finance

turning a vector into a matrix of the pair permutations


I have a time series of n columns, where n >=2. For each row I am trying to generate a matrix by applying a function to each permutation of the n elements. for example:

perm <- function(x, y) x-y
row = c(1, 2, 3)
sapply(row,function(x) sapply(row, function(y) perm(x,y)))

> sapply(row,function(x) sapply(row, function(y) perm(x,y)))
     [,1] [,2] [,3]
[1,]    0    1    2
[2,]   -1    0    1
[3,]   -2   -1    0

This approach works. But I know that it is not right. I just have this feeling that there is a better way to do this using the matrix math functions and I am not quite figuring it out. The apply approach is ~fine, but I know I can do better. In this case, reproducing the output for a simple subtraction like the one illustrated would be a fine answer but ideally it would come with some pointers to where to look in the docs for other types of operations. For what its worth, if anyone cares, the actual data is a list of interest rates of various tenors and the final output is going to be a matrix of forward-rates, so only the upper triangular matters, the diagonal and lower triangular won't have any information.


Solution

  • There is no way to eliminate the loops entirely in this case (that I know of). In all cases you will have to calculate the function for each element pair. R does have a function specifically built for this however outer

    outer(row, row, perm)
         [,1] [,2] [,3]
    [1,]    0   -1   -2
    [2,]    1    0   -1
    [3,]    2    1    0
    

    It is not necessarily faster to use outer compared to a normal loop, but it is a builtin method designed for the purpose.

    Edit: Vectorized functions

    There is a method one could use however, if the function is vectorized (like perm). Generating all permutations and then adding dimensions afterwards

    n <- length(row)
    perm1 <- row[rep(1:n, n)]
    perm2 <- row[rep(1:n, each = n)]
    res <- perm(perm1, perm2)
    dim(res) <- c(n, n) #change to a 2 dimensional array (matrix)
    res
         [,1] [,2] [,3]
    [1,]    0   -1   -2
    [2,]    1    0   -1
    [3,]    2    1    0
    

    Which will be much faster (but more memory intensive) if the function is optimized for vectorization