【问题标题】:Using Deriv package for derivative wrt vector将 Deriv 包用于衍生 wrt 向量
【发布时间】:2021-11-07 20:45:48
【问题描述】:

我正在探索 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),似乎应该能够让参数成为一个向量

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

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

例如上面的numDeriv 让我们可以轻松地得到一个导数 wrt 向量x

【问题讨论】:

  • 问题不在于 Deriv,它不能将单个数字向量传递给矩阵乘法。即 h(1) 会给你你看到的错误,但 h(c(1,4)) 不会。
  • madness 包对您有用吗...?
  • @BenBolker - 谢谢 - 我已经研究了一下,但我想先检查 Deriv 是否支持 autodiff wrt 向量,以及我是否只是犯了一个错误。也许我会朝那个方向走
  • @HenryHolm 谢谢 - 你能提供一个使用 Deriv 的例子吗?

标签: r autodiff deriv


【解决方案1】:

这是一个答案; 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))

【讨论】:

  • 谢谢 - 我曾想避免让组件分开 args,因为如果我有一个 100 维向量,则需要 100 个输入
  • 也许我遗漏了一些关于通过 args 的信息 .. 例如,有没有像 ... 这样的运算符可以用来避免这种情况..
  • 如果 Deriv 可以采用向量参数,这似乎还是很理想的
  • 也许你提到的Vectorize 函数可以让我避免这种情况..
  • 我想不通。可能是不可能的。对不起
【解决方案2】:

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

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

我们使用这个函数得到求值的导数,就像我们在numDeriv 中处理grad 一样。

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

【讨论】:

    【解决方案3】:

    这感觉真的很笨拙:

    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
    

    【讨论】:

      猜你喜欢
      • 2017-03-20
      • 1970-01-01
      • 2021-04-10
      • 2012-07-13
      • 1970-01-01
      • 1970-01-01
      • 2021-02-21
      • 1970-01-01
      • 2020-10-09
      相关资源
      最近更新 更多