【问题标题】:How to iterate through parameters in for loop如何遍历for循环中的参数
【发布时间】:2020-10-31 02:29:01
【问题描述】:

我有一个编写为 for 循环的模型,其中包含我指定的许多参数:

## functions needed to run the model
learn <- function(prior, sensi, speci, e){
  out <- ifelse(e == 1, (sensi*prior) / ((sensi*prior) + (1-speci)*(1-prior)),
                ((1-sensi)*prior) / (((1-sensi)*prior) + (speci*(1-prior))))
  out
}

feed <- function(vec){
  prior <- 0.5
  for (i in vec){
    res <- learn(prior, sensi, speci, i)
    prior <- res
  }
  return(prior)
}

## specify parameters
iterations <- 100
N <- 10
BR <- 0.66
sensi <- 0.75
speci <- 0.45

## initialize results object
res <- NULL

## loop for number of iterations
for (j in 1:iterations){
  
  X <- as.numeric(rbinom(1, 1, BR))
  
  if (X == 1){ # if X is 1...
    agents <- c(1:N) 
    evidence <- vector("list", length(agents)) 
    for (i in agents) {
      n <- sample(10, 1, replace = TRUE) 
      evidence[[i]] <- rbinom(n, 1, sensi) 
    }
  } else { # if X is 0... 
    agents <- c(1:N)
    evidence <- vector("list", length(agents)) 
    for (i in agents) {
      n <- sample(10, 1, replace = TRUE) 
      evidence[[i]] <- rbinom(n, 1, sensi) 
      evidence[[i]] <- ifelse(evidence[[i]]==1, 0, 1) # flip evidence 
    }
  }
  
  # feed vectors of evidence through learn function
  t0 <- sapply(evidence, feed)
  
  # save dataframe 
  df <- data.frame("i" = j, 
                   "ID" = c(1:N), 
                   "E" = t0, 
                   "X" = X,
                   "N" = N, 
                   "BR" = BR,
                   "sensi" = sensi,
                   "speci" = speci)

  res <- rbind(res, df)
  
}

这适用于单个参数化,但我现在想自动化指定不同参数值和重新运行模型的过程。因此,我没有将每个参数定义为单个值,而是将它们定义为值向量,并将所有可能的参数化存储在数据框 (paramspace) 中,每一行都保存我想要运行的单个参数化的值:

## set up for multiple parameterizations 
iterations <- 100
N_vec <- c(10, 50)
BR_vec <- c(0.25, 0.50, 0.75) 
sensi_vec <- c(0.45, 0.75)
speci_vec <- c(0.45, 0.75)

paramspace <- expand.grid(iterations = iterations, N = N_vec, BR = BR_vec, sensi = sensi_vec, speci = speci_vec)

> paramspace
   iterations  N   BR sensi speci
1         100 10 0.25  0.45  0.45
2         100 50 0.25  0.45  0.45
3         100 10 0.50  0.45  0.45
4         100 50 0.50  0.45  0.45
5         100 10 0.75  0.45  0.45
6         100 50 0.75  0.45  0.45
7         100 10 0.25  0.75  0.45
8         100 50 0.25  0.75  0.45
9         100 10 0.50  0.75  0.45
10        100 50 0.50  0.75  0.45
11        100 10 0.75  0.75  0.45
12        100 50 0.75  0.75  0.45
13        100 10 0.25  0.45  0.75
14        100 50 0.25  0.45  0.75
15        100 10 0.50  0.45  0.75
16        100 50 0.50  0.45  0.75
17        100 10 0.75  0.45  0.75
18        100 50 0.75  0.45  0.75
19        100 10 0.25  0.75  0.75
20        100 50 0.25  0.75  0.75
21        100 10 0.50  0.75  0.75
22        100 50 0.50  0.75  0.75
23        100 10 0.75  0.75  0.75
24        100 50 0.75  0.75  0.75

如何将每行参数值传递给我的模型并自动运行paramspace 中所述的所有参数化?

【问题讨论】:

  • 你可以把你的代码变成一个函数,然后使用apply(paramspace,1, my_function)paramspace逐行传递给你的函数。

标签: r for-loop iteration parameter-passing


【解决方案1】:

按照 cmets 的建议,您可以创建一个函数,然后使用 apply 循环参数组合:


## functions needed to run the model
learn <- function(prior, sensi, speci, e){
  out <- ifelse(e == 1, (sensi*prior) / ((sensi*prior) + (1-speci)*(1-prior)),
                ((1-sensi)*prior) / (((1-sensi)*prior) + (speci*(1-prior))))
  out
}

feed <- function(vec,sensi,speci){
  prior <- 0.5
  for (i in vec){
    res <- learn(prior, sensi, speci, i)
    prior <- res
  }
  return(prior)
}

runModel <- function(iterations = 100,
                     N = 10,
                     BR = 0.66,
                     sensi = 0.75,
                     speci = 0.45 ) {
  ## initialize results object
  res <- NULL
  
  ## loop for number of iterations
  for (j in 1:iterations){
    
    X <- as.numeric(rbinom(1, 1, BR))
    
    if (X == 1){ # if X is 1...
      agents <- c(1:N) 
      evidence <- vector("list", length(agents)) 
      for (i in agents) {
        n <- sample(10, 1, replace = TRUE) 
        evidence[[i]] <- rbinom(n, 1, sensi) 
      }
    } else { # if X is 0... 
      agents <- c(1:N)
      evidence <- vector("list", length(agents)) 
      for (i in agents) {
        n <- sample(10, 1, replace = TRUE) 
        evidence[[i]] <- rbinom(n, 1, sensi) 
        evidence[[i]] <- ifelse(evidence[[i]]==1, 0, 1) # flip evidence 
      }
    }
    
    # feed vectors of evidence through learn function
    #t0 <- sapply(evidence, feed)
    t0 <- sapply(evidence,function(e){feed(e,sensi,speci)})
    
    # save dataframe 
    df <- list("i" = iterations, 
               "ID" = c(1:N), 
               "E" = t0, 
               "X" = X,
               "N" = N, 
               "BR" = BR,
               "sensi" = sensi,
               "speci" = speci)
    
    res <- rbind(res, df)
    
  }
  res
}

# Define parameter space
iterations <- 100
N_vec <- c(10, 50)
BR_vec <- c(0.25, 0.50, 0.75) 
sensi_vec <- c(0.45, 0.75)
speci_vec <- c(0.45, 0.75)

paramspace <- expand.grid(iterations = iterations, N = N_vec, BR = BR_vec, sensi = sensi_vec, speci = speci_vec)

# Loop over parameter space :
res <- apply(paramspace,1,function(paramset) {
  iterations = paramset[1]
  N = paramset[2]
  BR = paramset[3]
  sensi = paramset[4]
  speci = paramset[5]
  runModel(iterations = iterations, N = N, BR = BR , sensi = sensi, speci = speci )
})

【讨论】:

  • 您提供的代码我遇到了一些问题。请参阅我在原帖中添加的回复。
  • 我猜这是因为t0 &lt;- sapply(evidence, feed) 没有得到更新的参数。几分钟后更正。
  • 就是这样:我更新了 feed 函数以传递给它特定/敏感参数。仍然有一些警告,但不是当您单独运行RunModel() 时,即使用初始参数集。我猜一些参数组合会产生这些警告。
  • 模型循环正常运行,警告来自数据帧调用以保存结果:df
  • 我的意图是在结果中标记迭代。也许我的变量在路上的某个地方混淆了。我可以调查一下。
【解决方案2】:

您还可以使用foreach 包,它与适当的后端一起使用提供并行化功能,以防您的任务变得更加密集。这里有一个简单的例子来理解它是如何工作的。

foreach(a=1:3, b=4:6) %do% (a + b)

然后我尝试将您的代码嵌入到foreach


require(foreach)

## functions needed to run the model
learn <- function(prior, sensi, speci, e){
  out <- ifelse(e == 1, (sensi*prior) / ((sensi*prior) + (1-speci)*(1-prior)),
                ((1-sensi)*prior) / (((1-sensi)*prior) + (speci*(1-prior))))
  out
}

feed <- function(vec){
  prior <- 0.5
  for (i in vec){
    res <- learn(prior, sensi, speci, i)
    prior <- res
  }
  return(prior)
}


## set up for multiple parameterizations 
iterations <- 100
N_vec <- c(10, 50)
BR_vec <- c(0.25, 0.50, 0.75) 
sensi_vec <- c(0.45, 0.75)
speci_vec <- c(0.45, 0.75)

paramspace <- expand.grid(iterations = iterations, N = N_vec, BR = BR_vec, sensi = sensi_vec, speci = speci_vec)

res <- foreach(iterations = paramspace$iterations, 
               N = paramspace$N, 
               BR = paramspace$BR, 
               sensi = paramspace$sensi, 
               speci = paramspace$speci) %do% {
                 
                 ## initialize results object
                 res <- NULL
                 
                 ## loop for number of iterations
                 for (j in 1:iterations){
                   
                   X <- as.numeric(rbinom(1, 1, BR))
                   
                   if (X == 1){ # if X is 1...
                     agents <- c(1:N) 
                     evidence <- vector("list", length(agents)) 
                     for (i in agents) {
                       n <- sample(10, 1, replace = TRUE) 
                       evidence[[i]] <- rbinom(n, 1, sensi) 
                     }
                   } else { # if X is 0... 
                     agents <- c(1:N)
                     evidence <- vector("list", length(agents)) 
                     for (i in agents) {
                       n <- sample(10, 1, replace = TRUE) 
                       evidence[[i]] <- rbinom(n, 1, sensi) 
                       evidence[[i]] <- ifelse(evidence[[i]]==1, 0, 1) # flip evidence 
                     }
                   }
                   
                   # feed vectors of evidence through learn function
                   t0 <- sapply(evidence, feed)
                   
                   # save dataframe 
                   df <- data.frame("i" = j, 
                                    "ID" = c(1:N), 
                                    "E" = t0, 
                                    "X" = X,
                                    "N" = N, 
                                    "BR" = BR,
                                    "sensi" = sensi,
                                    "speci" = speci)
                   
                   res <- rbind(res, df)
                   
                 }
                 
                 res
                 
               }

【讨论】:

    【解决方案3】:

    另一种方法是创建一个函数并使用Map(...)Map 的优点是您的 paramspace 不会被强制转换为矩阵,这将使所有内容都具有相同的类型(即数字、字符等)。

    为了让 R 为我们做会计,我还做了一些其他的改变。主要是:

    1. X 现在是合乎逻辑的,因此我们可以简化我们的 if 语句。此外,分配是一次性完成的,而不是循环的。
    2. 我们将feed() 函数更改为也生成evidence。这使我们能够...
    3. 使用replicate 重复循环。
    learn2 <- function(prior, sensi, speci, e){
        out <- ifelse(e, (sensi*prior) / ((sensi*prior) + (1-speci)*(1-prior)),
                      ((1-sensi)*prior) / (((1-sensi)*prior) + (speci*(1-prior))))
        out
    }
    
    
    feed2  = function(x, N, samp_n = 10L, sensi, speci) {
        evidence = rbinom(sample(samp_n, 1L, replace = TRUE), 
                          1,
                          if (x) sensi else 1 - sensi)
        
        prior = 0.5
        for (i in evidence) {
            res = learn2(prior, sensi, speci, i)
            prior = res
        }
        return(prior)
    }
    
    runModel2 <- function(iterations = 2,
                         N = 10,
                         BR = 0.66,
                         sensi = 0.75,
                         speci = 0.45 ) {
        
        X = sample(c(TRUE, FALSE), N, BR)
        
        ## this is done now so that the columns will be ordered nicer
        ans = list(ID = 1:N,
                    N = N,
                   BR = BR,
                   sensi = sensi,
                   speci = speci,
                   X = X)
        
        t0s = replicate(iterations,
                        vapply(X, feed2, FUN.VALUE = 0, N, 10L, sensi, speci, USE.NAMES = FALSE), 
                        simplify = FALSE)
        
        names(t0s) = paste0("E_", 1:iterations)
        
        return(as.data.frame(c(ans, t0s)))
    }
    
    runModel2()
    #>    ID  N   BR sensi speci     X        E_1         E_2
    #> 1   1 10 0.66  0.75  0.45  TRUE 0.82967106 0.657648599
    #> 2   2 10 0.66  0.75  0.45 FALSE 0.43103448 0.006827641
    #> 3   3 10 0.66  0.75  0.45  TRUE 0.43103448 0.775671866
    #> 4   4 10 0.66  0.75  0.45  TRUE 0.71716957 0.431034483
    #> 5   5 10 0.66  0.75  0.45 FALSE 0.24176079 0.016593958
    #> 6   6 10 0.66  0.75  0.45 FALSE 0.30303324 0.008992838
    #> 7   7 10 0.66  0.75  0.45  TRUE 0.82967106 0.865405260
    #> 8   8 10 0.66  0.75  0.45 FALSE 0.43103448 0.439027817
    #> 9   9 10 0.66  0.75  0.45 FALSE 0.57692308 0.050262167
    #> 10 10 10 0.66  0.75  0.45 FALSE 0.02178833 0.296208531
    

    这个输出比你原来的方法宽一点。我们总是可以重塑 E_# 列,但这可能最终会更适合您的实际用例。

    最后,Map() 在行动:

    iterations <- 100
    N_vec <- c(10, 50)
    BR_vec <- c(0.25, 0.50, 0.75) 
    sensi_vec <- c(0.45, 0.75)
    speci_vec <- c(0.45, 0.75)
    
    paramspace <- expand.grid(iterations = iterations, N = N_vec, BR = BR_vec, sensi = sensi_vec, speci = speci_vec)
    
    res = Map(runModel2, paramspace$iterations, paramspace$N, paramspace$BR, paramspace$sensi, paramspace$speci)
    
    res[[24L]][1:10, 1:8] ## only first 10 rows for demonstration
    ##   ID  N   BR sensi speci     X         E_1         E_2
    ##1   1 50 0.75  0.75  0.75  TRUE 0.500000000 0.500000000
    ##2   2 50 0.75  0.75  0.75 FALSE 0.001369863 0.035714286
    ##3   3 50 0.75  0.75  0.75 FALSE 0.250000000 0.900000000
    ##4   4 50 0.75  0.75  0.75  TRUE 0.750000000 0.250000000
    ##5   5 50 0.75  0.75  0.75  TRUE 0.987804878 0.500000000
    ##6   6 50 0.75  0.75  0.75  TRUE 0.964285714 0.250000000
    ##7   7 50 0.75  0.75  0.75  TRUE 0.750000000 0.750000000
    ##8   8 50 0.75  0.75  0.75 FALSE 0.012195122 0.035714286
    ##9   9 50 0.75  0.75  0.75  TRUE 0.750000000 0.500000000
    ##10 10 50 0.75  0.75  0.75 FALSE 0.250000000 0.001369863
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-11-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-10-05
      • 1970-01-01
      • 2016-03-03
      • 1970-01-01
      相关资源
      最近更新 更多