Создайте несколько функций с изменением имен в цикле for в R - PullRequest
1 голос
/ 23 октября 2019

У меня есть датафрейм "data", и я хочу вычислить около 30 функций f (CS). Цель состоит в том, чтобы найти CS для каждой функции f (CS) с uniroot. Я ищу цикл, который генерирует функции f (CS) и результаты функций (то есть CS).

Вопросы, связанные с данной: R - Наименование нескольких функций в цикле for и Несколько функций в цикле for

Функции должны иметь разные имена (function_1, function_2, function_3 и т. д.), и каждая функция использует значения из разных строк из фрейма данных «data». Я изо всех сил старался создать минимально воспроизводимый пример:

data <- data.frame(A=c(154,154,154,154,110154,102500,0,0,0,0,205200,0,0,0,0), 
                   B=c(-0.647, -0.738, -0.749, -0.691, -0.600, 2.455, 2.358, 2.289, 2.264, 2.267, 2.455, 2.358, 2.289, 2.264, 2.267))

function_1 <- function(CS){
          sum(data$A[1:5]/(1+data$B[1:5]/100+CS/10000)^(1:5) - 100000)
      }

function_2 <- function(CS){
      sum(data$A[6:10]/(1+data$B[6:10]/100+CS/10000)^(1:5) - 100000)
  }

function_3 <- function(CS){
      sum(data$A[11:15]/(1+data$B[11:15]/100+CS/10000)^(1:5) - 200000)
  }

Обратите внимание, что константа в function_3 (200000) не является опечаткой. Как я уже говорил, я вычисляю корни с помощью uniroot:

uniroot(function_1, c(-1000,1000))$root #267.3119
uniroot(function_2, c(-1000,1000))$root #4.500001
uniroot(function_3, c(-1000,1000))$root #14.5

Я попытался использовать два цикла for, как показано ниже:

for (i in seq(from = 1, to = nrow(data)/5)){
noquote(paste0("function_",i,"")) <- function(CS){
           sum(data$A[1:5]/(1+data$B[1:5]/100+CS/10000)^(1:5))
   }
 }

for (i in seq(from = 1, to = nrow(data)/5)){
    uniroot(noquote(paste0("function_",i,")), c(-1000,1000))$root
  }

Я не знаю, как реализовать изменяющуюся константуи изменение имени функции, так как noquote(paste0()), похоже, не работает. Пожалуйста, дайте мне знать, если вам нужна дополнительная информация. Заранее спасибо.

1 Ответ

1 голос
/ 23 октября 2019

Вы близки, но это не совсем то, для чего noquote. Вместо этого используйте комбинацию assign и get, например:

for (i in seq(from = 1, to = nrow(data)/5)){
   assign(paste0("function_",i)), function(CS){
           sum(data$A[1:5]/(1+data$B[1:5]/100+CS/10000)^(1:5))
   }
 }

for (i in seq(from = 1, to = nrow(data)/5)){
    uniroot(get(paste0("function_",i)), c(-1000,1000))$root
}

Однако я не уверен, что первый цикл в вашем примере фактически воссоздает нужные функции, которые вы вручную перечислили впервый кусок кода в вашем вопросе. Разве индексирование data тоже не должно измениться? Как это?

for (i in seq(from = 1, to = nrow(data)/5)){
   indices <- (1+(i-1)*5):(5+(i-1)*5)
   assign(paste0("function_",i,"")), function(CS){
           sum(data$A[indices ]/(1+data$B[indices]/100+CS/10000)^(1:5))
   }
 }

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

flexibleFunction <- function(CS, indices){
      sum(data$A[indices]/(1+data$B[indices]/100+CS/10000)^(1:5) - 100000)
  }

uniroot(flexibleFunction , c(-1000,1000), 1:5)$root
uniroot(flexibleFunction , c(-1000,1000), 6:10)$root
...