R Матрица Гессе

Матрица Гессе

Мне нужно создать матрицу Гессе функции, заданной как:

func <- expression(sin(x+y)+cos(x-y))
vars <- c("x", "y")

Мне тоже нужны производные второго порядка как выражения, и мне нужно много раз их оценивать, поэтому я составил список производных первого порядка и список списка производных второго порядка.

funcD <- lapply(vars, function(v) D(func, v))
funcDD <- list(); for (i in 1:length(vars)) funcDD[[i]] <- lapply(vars, function(v) D(funcD[[i]], v))

Пока это работает.

> funcDD
[[1]]
[[1]][[1]]
-(sin(x + y) + cos(x - y))

[[1]][[2]]
-(sin(x + y) - cos(x - y))


[[2]]
[[2]][[1]]
cos(x - y) - sin(x + y)

[[2]][[2]]
-(cos(x - y) + sin(x + y))

Теперь вопросы: Как мне создать матрицу, содержащую значения оцениваемых выражений? Пробовал внешний, не работает.

> h <- outer(c(1:length(vars)), c(1:length(vars)), function(r, c) eval(funcDD[[r]][[c]], envir = list(x = 1, y = 2)))
Error in funcDD[[r]] : subscript out of bounds

Другой вопрос: есть ли более элегантный способ хранения производных выражений второго порядка? Например, можно ли хранить выражения в матрице вместо списков списков?

Третий вопрос: можно ли получить вектор переменных выражения? Выше я использовал vars ‹- c(x, y), которые я ввел в качестве входных данных вручную, это необходимо или есть метод, подобный get_variables?


person David Angyal    schedule 30.11.2013    source источник
comment
Решение для вашего третьего вопроса следующее: all.vars(my_expr), что в вашем примере вернет >[1] "x" "y"   -  person bschneidr    schedule 19.08.2019


Ответы (4)


Ответ на второй вопрос: «в основном да», и он предлагает почти немедленный ответ на ваш вопрос:

funcD <- sapply(vars, function(v) D(func, v))
funcDD <- matrix(list(), 2,2)
for (i in 1:length(vars)) 
        funcDD[,i] <- sapply(vars, function(v) D(funcD[[i]], v))
funcDD
#---------
     [,1]       [,2]      
[1,] Expression Expression
[2,] Expression Expression
> funcDD[1,1]
[[1]]
-(sin(x + y) + cos(x - y))

Квалификация «в основном» заключается в том, что нужно использовать «список», а не «выражение» в качестве типа объекта, который содержит матрица. Выражения на самом деле не квалифицируются как атомарные объекты, и вы можете легко извлечь значение и использовать его в качестве вызова, что может быть даже удобнее, чем иметь его в виде выражения:

> is.expression(funcDD[1,1])
[1] FALSE
> funcDD[1,1][[1]]
-(sin(x + y) + cos(x - y))
> class(funcDD[1,1][[1]])
[1] "call"

Оказывается, нужна была одна и та же структура, поэтому каждый элемент матрицы вызывается с тем же конкретным вектором, что и среда оценки, и возвращает их все в виде матрицы.:

matrix(sapply(funcDD, eval, env=list(x=0, y=pi)), length(vars))
#---------
     [,1] [,2]
[1,]    1   -1
[2,]   -1    1
person IRTFM    schedule 30.11.2013
comment
Когда мне нужно eval() все элементы в матрице, есть ли более элегантный способ, чем использование двойного цикла for? - person David Angyal; 30.11.2013
comment
Я бы попробовал что-то вроде: eval(funcDD[1,1][[1]], env=list(x=0, y=pi) ). О, еще раз подумав, возможно, вы не это имели в виду. Возможно, вам следует представить более полный вариант использования. - person IRTFM; 30.11.2013
comment
Возможно: sapply(funcDD, eval, env=list(x=0, y=pi) ) #[1] 1 -1 -1 1? - person IRTFM; 30.11.2013
comment
matrix(sapply(funcDD, eval, env=list(x=0, y=pi)), length(vars)) Спасибо! - person David Angyal; 30.11.2013

Вот функция, которая может возвращать гессиан выражения в нескольких различных форматах. Код находится внизу этого ответа, ему предшествуют примеры его использования.

Примеры использования

my_fn <- expression((x^2)*(y^2))
# Get the symbolic Hessian as a character matrix

get_hessian(my_fn, as_matrix = TRUE)
#>      [x]              [y]             
#> [x] "2 * (y^2)"       "2 * x * (2 * y)"
#> [y] "2 * x * (2 * y)" "(x^2) * 2"

# Get the symbolic Hessian as a nested list of expressions
get_hessian(my_fn, as_matrix = FALSE)
#> $x
#> $x$x
#> 2 * (y^2)
#> 
#> $x$y
#> 2 * x * (2 * y)
#> 
#> 
#> $y
#> $y$x
#> 2 * x * (2 * y)
#> 
#> $y$y
#> (x^2) * 2
# Get the numeric Hessian from evaluating at a particular point
get_hessian(my_fn, eval_at = list(x = 2, y = 2))
#>      [x] [y]
#> [x]    8   16
#> [y]   16    8

Код для функции

get_hessian <- function(f, as_matrix = FALSE, eval_at = NULL) {

  fn_inputs <- all.vars(f); names(fn_inputs) <- fn_inputs
  n_inputs <- length(fn_inputs)

  # Obtain the symbolic Hessian as a nested list

  result <- lapply(fn_inputs, function(x) lapply(fn_inputs, function(x) NULL))

  for (i in seq_len(n_inputs)) {

    first_deriv <- D(f, fn_inputs[i])

    for (j in seq_len(n_inputs)) {

      second_partial_deriv <- D(first_deriv, fn_inputs[j])

      result[[i]][[j]] <- second_partial_deriv

    }
  }

  # Convert the symbolic Hessian to a character matrix
  if (is.null(eval_at)) {
    if (as_matrix) {
      matrix_result <- matrix(as.character(diag(n_inputs)), nrow = n_inputs, ncol = n_inputs)

      for (i in seq_len(n_inputs)) {
        for (j in seq_len(n_inputs)) {
          matrix_result[i, j] <- gsub("expression", "", format(result[[i]][[j]]), fixed = TRUE)
        }
      }

      dimnames(matrix_result) <- list(fn_inputs, fn_inputs)

      return(matrix_result)

    } else {

      return(result)

    }
  }

  # Evaluate the Hessian at a set point if a named list is provided

  if (!is.null(eval_at)) {
    result_vals <- diag(n_inputs)

    for (i in seq_len(n_inputs)) {
      for (j in seq_len(n_inputs)) {

        result_vals[i, j] <- eval(result[[i]][[j]], envir = eval_at)

      }
    }

    dimnames(matrix_result) <- list(fn_inputs, fn_inputs)

    return(result_vals)
  }
}
person bschneidr    schedule 19.08.2019

Вы можете использовать функцию hessian() из пакета calculus.

library(calculus)

# Create an expression with the function of interest
  func <- expression(sin(x+y)+cos(x-y))
  vars <- c("x", "y")

# Get the symbolic hessian
  hessian(f = func, var = vars)

# Get the hessian evaluated at a specific point
  hessian(f = func, var = c('x' = 0, 'y' = 1))
person bschneidr    schedule 08.01.2020

Я думаю, было бы намного проще написать цикл, который вычисляет каждую производную и помещает ее значение непосредственно в матрицу. Таким образом,

hess<-matrix(nrow=N,ncol=N)  #for x1 thru xN
for(j in 1:N) {
    for(k in 1:N) {
        hess[i,j]<- Dfunc(func,vars[i,j])
        }
    }

Где вам нужно будет настроить переменные x1,x2,...xN в матрице vars

person Carl Witthoft    schedule 30.11.2013