简体   繁体   中英

Subtract every column from each other in an xts object

I am a newbie learning to code and have an xts object of 1000 rows and 10 columns. I need to subtract every column from each other creating a new xts object keeping the date column. I've tried to use combn but could not get it to create BA result since it did AB. What I'm looking for is below.

 DATA                                           RESULT
            A  B   C     --->               A-B   A-C  B-A  B-C  C-A  C-B
2010-01-01  1  3   5           2010-01-01   -2    -4    2    -2    4    2 
2010-01-02  2  4   6           2010-01-02   -2    -4    2    -2    4    2
2010-01-03  3  5   2           2010-01-03   -2     1    2     3   -1   -3 

We could use outer to get pairwise combinations of the column names, subset the dataset 'xt1' based on the column names, get the difference in a list .

f1 <- Vectorize(function(x,y) list(setNames(xt1[,x]-xt1[,y],
                                         paste(x,y, sep='_'))))
lst <- outer(colnames(xt1), colnames(xt1), FUN = f1)

We Filter out the list elements that have sum=0 ie the difference between columns AA , BB , and CC , and cbind to get the expected output.

 res <- do.call(cbind,Filter(sum, lst))
 res[,order(colnames(res))]
 #            A_B A_C B_A B_C C_A C_B
 #2010-01-01  -2  -4   2  -2   4   2
 #2010-01-02  -2  -4   2  -2   4   2
 #2010-01-03  -2   1   2   3  -1  -3

data

 d1 <- data.frame(A=1:3, B=3:5, C=c(5,6,2))
 library(xts)
  xt1 <- xts(d1, order.by=as.Date(c('2010-01-01', '2010-01-02', '2010-01-03')))

I built the data using:

x <- zoo::zoo(
    data.frame(
        A = c(1, 2, 3), 
        B = c(3, 4, 5), 
        C = c(5, 6, 2)), 
    order.by = as.Date(c("2010-01-01", "2010-01-02", "2010-01-03")))

Then I defined a function for creating all possible pairs of two sets:

cross <- function(x, y = x) {

    result <- list()

    for (a in unique(x)) {

        for (b in unique(y)) {

            result <- append(result, list(list(left = a, right = b)))
        }
    }

    result
}

To answer your question:

# Build a list of column combinations
combinations <- cross(names(x), setdiff(names(x), names(x)[1]))

# Remove any entries where the left equals the right
combinations <- combinations[vapply(combinations, function(x) { x$left != x$right }, logical(1))]

# Build a user friendly list of names
names(combinations) <- vapply(combinations, function(x) { paste0(x$left, "-", x$right) }, character(1))

# Do the actual computation and combine the results into one object 
do.call(cbind, lapply(combinations, function(x, data) { data[, x$left, drop = T] - data[, x$right, drop = T] }, data = x))

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM