Sam Weisenthal
Sam Weisenthal

Reputation: 2951

Using Deriv package for derivative wrt vector

I am exploring autodiff, and I would like to use Deriv for computing a derivative of a function wrt to a vector. I write

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))

Does anyone have a good way to do this?

From help(Deriv), it seems like one should be able to let the argument be a vector

here is a side effect with vector length. E.g. in Deriv(~a+bx, c("a", "b")) the result is c(a = 1, b = x). To avoid the difference in lengths of a and b components (when x is a vector), one can use an optional parameter combine Deriv(~a+bx, c("a", "b"), combine="cbind") which gives cbind(a = 1, b = x) producing a two column matrix which is probably the desired result here.

I would like to avoid making each of the vector components a different argument to the function.

For example numDeriv above lets us easily take a derivative wrt vector x

Upvotes: 2

Views: 526

Answers (3)

jblood94
jblood94

Reputation: 17011

This feels really kludgy:

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

The evaluation time for Deriv seems to increase roughly quadratically with the number of parameters:

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

Upvotes: 1

Sam Weisenthal
Sam Weisenthal

Reputation: 2951

Here is a solution using not Deriv but madness, a really neat package.

We basically create an object that is the thing we would like to take the derivative with respect to (in this case x), and then as we apply functions to that object, the derivatives are collected.

We get the evaluated derivative using this function, as we do with grad in 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

Upvotes: 1

Mossa
Mossa

Reputation: 1718

This is an answer; The to packages handles multiple dimensions differently.


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))

Upvotes: 2

Related Questions