2

我正在探索 autodiff,我想用它Deriv来计算函数 wrt 对向量的导数。我写的

library(numDeriv)
library(Deriv)
h = function(x) c(1,2)%*%x
grad(h,c(1,2)) #ok
#[1] 1 2
dh=Deriv(h,x='x')
#Error in c(1, 2) %*% 1 : non-conformable arguments
dh(c(1,2))

有没有人有这样做的好方法?

help(Deriv),似乎应该能够让参数成为一个向量

这是向量长度的副作用。例如,在 Deriv(~a+b x, c("a", "b")) 中,结果是 c(a = 1, b = x)。为了避免 a 和 b 分量的长度不同(当 x 是向量时),可以使用可选参数 combine Deriv(~a+b x, c("a", "b"), combine="cbind" ) 这使得 cbind(a = 1, b = x) 产生一个两列矩阵,这可能是这里想要的结果。

我想避免使每个向量分量成为函数的不同参数。

例如numDeriv上面的例子让我们很容易得到一个导数 wrt 向量x

4

3 回答 3

2

这是一个答案;to 包以不同的方式处理多个维度。


library(numDeriv)
library(Deriv)
h = function(x,y) c(1,2) %*% c(x,y)
grad(\(x) h(x[1], x[2]),c(1,2))
dh = Deriv(h)
dh(c(1,2))

于 2021-11-07T20:55:44.187 回答
1

这感觉真的很笨拙:

library(Deriv)

sz <- 100
f.vec <- function(x) 1:sz%*%x
xs <- paste0("x", 1:sz, collapse = ",")
h <- eval(parse(text = paste0("h <- function(", xs, ") f.vec(c(", xs, "))")))
dh <- Deriv(h)
dh(1:sz)
#>   x1   x2   x3   x4   x5   x6   x7   x8   x9  x10  x11  x12  x13  x14  x15  x16 
#>    1    2    3    4    5    6    7    8    9   10   11   12   13   14   15   16 
#>  x17  x18  x19  x20  x21  x22  x23  x24  x25  x26  x27  x28  x29  x30  x31  x32 
#>   17   18   19   20   21   22   23   24   25   26   27   28   29   30   31   32 
#>  x33  x34  x35  x36  x37  x38  x39  x40  x41  x42  x43  x44  x45  x46  x47  x48 
#>   33   34   35   36   37   38   39   40   41   42   43   44   45   46   47   48 
#>  x49  x50  x51  x52  x53  x54  x55  x56  x57  x58  x59  x60  x61  x62  x63  x64 
#>   49   50   51   52   53   54   55   56   57   58   59   60   61   62   63   64 
#>  x65  x66  x67  x68  x69  x70  x71  x72  x73  x74  x75  x76  x77  x78  x79  x80 
#>   65   66   67   68   69   70   71   72   73   74   75   76   77   78   79   80 
#>  x81  x82  x83  x84  x85  x86  x87  x88  x89  x90  x91  x92  x93  x94  x95  x96 
#>   81   82   83   84   85   86   87   88   89   90   91   92   93   94   95   96 
#>  x97  x98  x99 x100 
#>   97   98   99  100

的评估时间Deriv似乎随着参数的数量大致呈二次方增加:

varDeriv <- function(sz) {
  system.time({
    f.vec <- function(x) 1:sz%*%x
    xs <- paste0("x", 1:sz, collapse = ",")
    h <- eval(parse(text = paste0("h <- function(", xs, ") f.vec(c(", xs, "))")))
    dh <- Deriv(h)
    dh(1:sz)
  })
}

Vectorize(varDeriv)(seq(100, 500, by = 100))
#>             [,1]  [,2]  [,3]   [,4]   [,5]
#> user.self  0.712 2.700 6.498 11.782 20.854
#> sys.self   0.015 0.011 0.020  0.055  0.068
#> elapsed    0.727 2.710 6.518 11.839 20.922
#> user.child 0.000 0.000 0.000  0.000  0.000
#> sys.child  0.000 0.000 0.000  0.000  0.000
于 2021-11-09T22:29:45.067 回答
1

这是一个使用非常简洁的包的解决Deriv方案madness,

我们基本上创建了一个对象,该对象是我们想要对其进行导数的对象(在这种情况下x),然后当我们将函数应用于该对象时,会收集导数。

我们使用这个函数得到评估的导数,就像我们在 in 中所做的grad那样numDeriv

library(madness)

h = function(x){t(x)%*%matrix(c(2,1),nrow=2,ncol=1)}
x=matrix(c(1,1),nrow=2,ncol=1)

gd=function(h,x){
x=madness(val=x)
z=h(x)
attr(z,"dvdx")
}
gd(h,x)
#     [,1] [,2]
#[1,]    2    1
于 2021-11-08T02:03:35.697 回答