不丢失 xts 属性的矩阵乘法
matrix multiplication without losing xts properties
我有一个 xts
对象,我希望创建列的加权和(并且这样做 LOT)。到目前为止,最简单的方法是矩阵乘法,但结果失去了很好的 xts
品质。
通过创建一个新的 xts
对象很容易将它们添加回去 -- 但它既缓慢又乏味。
例如:
dd <- xts(matrix(rnorm(200), ncol=2), Sys.Date() + 1:100)
w_sum <- dd %*% c(-1, 1)
...问题是:
> tail(w_sum)
[,1]
[95,] 0.1758262
[96,] -0.3310975
[97,] -0.1204836
[98,] -1.2242001
[99,] -1.7333222
[100,] 1.1216603
修复方法是:
w_sumx <- xts(dd %*% c(-1, 1), index(dd))
但这不仅麻烦,而且速度很慢。另外,我感兴趣地注意到 xts
的减法速度非常快。有没有一种方法可以利用 xts
的快速内部机制来做到这一点?
f1 <- function() xts(dd %*% c(-1, 1), index(dd))
f2 <- function() dd[,2] - dd[,1]
> microbenchmark::microbenchmark(f1(), f2(), times = 1000)
Unit: microseconds
expr min lq mean median uq max neval cld
f1() 83.7 97.3 114.1294 104.65 115.00 6688.4 1000 b
f2() 26.3 34.0 40.6202 38.85 45.15 155.4 1000 a
存在一些简单的替代方案。显然,您可以按照建议重写 Rcpp
中的方法,但更简单的替代方法是在执行矩阵正则乘法后覆盖属性。
dd_new <- dd %*% c(-1, 1)
att <- attributes(dd)
att$dim <- dim(dd_new)
attributes(dd_new) <- att
这不如纯矩阵乘法快,但比时间序列本身的子集快 10 - 13 倍。
microbenchmark::microbenchmark(xts = dd[, 1] - dd[, 2],
matmult = dd %*% c(1, -1),
xtsmatmult = xts(dd %*% c(1, -1), index(dd)),
"%.%" = dd %.% c(1, -1),
"%-%" = dd %-% c(1, -1),
times = 1e5)
Unit: milliseconds
expr min lq mean median uq max neval
xts 0.0396 0.0685 0.11200 0.0998 0.1170 15.40 1e+05
matmult 0.0008 0.0021 0.00352 0.0028 0.0040 7.71 1e+05
xtsmatmult 0.0853 0.1380 0.22900 0.2100 0.2300 117.00 1e+05
%.% 0.0025 0.0055 0.00905 0.0076 0.0099 8.97 1e+05
%-% 0.0096 0.0183 0.03030 0.0268 0.0318 101.00 1e+05
上面的 %.%
是一个准系统函数,只留下矩阵乘法和覆盖属性,而 %-%
添加了一些简单的输入检查,以确保维度是可接受的,并使用S3
class 风格,为了简化概括。
函数:
请注意,compiler::cmpfun
函数已用于对函数进行字节编译(类似于包函数)。在这种情况下影响是微不足道的。
`%.%` <- compiler::cmpfun(function(x, z){
x2 <- x %*% z
att <- attributes(x)
att$dim <- dim(x2)
attributes(x2) <- att
x2
})
`%-%` <- function(x, z)
UseMethod('%-%')
`%-%.xts` <- compiler::cmpfun(function(x, z){
##
if(!is.xts(x))
stop('x must be an xts object')
if(!is.numeric(z) || !(n <- length(z)) == ncol(x) || n == 0)
stop('z must be an index vector')
x2 <- x %*% z
att <- attributes(x)
att$dim <- dim(x2)
attributes(x2) <- att
x2
})
我有一个 xts
对象,我希望创建列的加权和(并且这样做 LOT)。到目前为止,最简单的方法是矩阵乘法,但结果失去了很好的 xts
品质。
通过创建一个新的 xts
对象很容易将它们添加回去 -- 但它既缓慢又乏味。
例如:
dd <- xts(matrix(rnorm(200), ncol=2), Sys.Date() + 1:100)
w_sum <- dd %*% c(-1, 1)
...问题是:
> tail(w_sum)
[,1]
[95,] 0.1758262
[96,] -0.3310975
[97,] -0.1204836
[98,] -1.2242001
[99,] -1.7333222
[100,] 1.1216603
修复方法是:
w_sumx <- xts(dd %*% c(-1, 1), index(dd))
但这不仅麻烦,而且速度很慢。另外,我感兴趣地注意到 xts
的减法速度非常快。有没有一种方法可以利用 xts
的快速内部机制来做到这一点?
f1 <- function() xts(dd %*% c(-1, 1), index(dd))
f2 <- function() dd[,2] - dd[,1]
> microbenchmark::microbenchmark(f1(), f2(), times = 1000)
Unit: microseconds
expr min lq mean median uq max neval cld
f1() 83.7 97.3 114.1294 104.65 115.00 6688.4 1000 b
f2() 26.3 34.0 40.6202 38.85 45.15 155.4 1000 a
存在一些简单的替代方案。显然,您可以按照建议重写 Rcpp
中的方法,但更简单的替代方法是在执行矩阵正则乘法后覆盖属性。
dd_new <- dd %*% c(-1, 1)
att <- attributes(dd)
att$dim <- dim(dd_new)
attributes(dd_new) <- att
这不如纯矩阵乘法快,但比时间序列本身的子集快 10 - 13 倍。
microbenchmark::microbenchmark(xts = dd[, 1] - dd[, 2],
matmult = dd %*% c(1, -1),
xtsmatmult = xts(dd %*% c(1, -1), index(dd)),
"%.%" = dd %.% c(1, -1),
"%-%" = dd %-% c(1, -1),
times = 1e5)
Unit: milliseconds
expr min lq mean median uq max neval
xts 0.0396 0.0685 0.11200 0.0998 0.1170 15.40 1e+05
matmult 0.0008 0.0021 0.00352 0.0028 0.0040 7.71 1e+05
xtsmatmult 0.0853 0.1380 0.22900 0.2100 0.2300 117.00 1e+05
%.% 0.0025 0.0055 0.00905 0.0076 0.0099 8.97 1e+05
%-% 0.0096 0.0183 0.03030 0.0268 0.0318 101.00 1e+05
上面的 %.%
是一个准系统函数,只留下矩阵乘法和覆盖属性,而 %-%
添加了一些简单的输入检查,以确保维度是可接受的,并使用S3
class 风格,为了简化概括。
函数:
请注意,compiler::cmpfun
函数已用于对函数进行字节编译(类似于包函数)。在这种情况下影响是微不足道的。
`%.%` <- compiler::cmpfun(function(x, z){
x2 <- x %*% z
att <- attributes(x)
att$dim <- dim(x2)
attributes(x2) <- att
x2
})
`%-%` <- function(x, z)
UseMethod('%-%')
`%-%.xts` <- compiler::cmpfun(function(x, z){
##
if(!is.xts(x))
stop('x must be an xts object')
if(!is.numeric(z) || !(n <- length(z)) == ncol(x) || n == 0)
stop('z must be an index vector')
x2 <- x %*% z
att <- attributes(x)
att$dim <- dim(x2)
attributes(x2) <- att
x2
})