在数据框中逐行应用向量化多变量函数

Applying vectorized multivariable function row by row in dataframe

我在 SO 上进行了广泛的搜索,但找不到与我完全一样的问题的答案..

我正在尝试使用从 inputs 数据帧读取多变量参数的函数生成一些时间序列条目。 inputs 中的每组变量 {x,y,z,...} 生成一个时间序列数据帧;需要不公开的合集

inputs 数据框本身是混合类型(字符和双精度),所以我一直在使用 apply 函数时遇到问题,据我所知,该函数在内部转换为矩阵对象,因此失败了。 mapply 似乎是理想的候选者(过程 运行 但结果无效,因为时间序列生成函数本身在生成正态分布时被矢量化)

我的以下代码运行但给出了错误的结果

library(dplyr)
library(truncnorm)

forecast_curve <- function(case_id,
                           wal,
                           wal_sd,
                           amt,
                           n_qrtr) {

  result <- 
    tibble(case_id = case_id, 
           quarter = seq(1, n_qrtr, 1)
    ) %>%
    mutate(
      amt_qrtr = amt * 
        dtruncnorm(seq(1, n_qrtr, 1),a = 1,b = n_qrtr,mean = wal, sd = wal_sd)
    )
  return(result)
}

#Generate inputs
inputs <- 
  tibble(
    case_id = letters[1:10],
    wal = seq(5,14,1),
    wal_sd = rep(4,10),
    total_amt_FC = c(10,9,8,7,6,5,4,3,2,1),            
    n_qrtr = rep(12,10)
  )

#outputs function
outputs <- function(){
  tmp <-
      mapply(
        forecast_curve,
        inputs$case_id,
        inputs$wal,
        inputs$wal_sd,
        inputs$total_amt_FC,
        inputs$n_qrtr
      )

  tmp <-
    as.data.frame(apply(tmp, 1, unlist)) %>% 
    tibble() %>% 
    mutate(
      quarter = as.numeric(quarter),
      amt_qrtr = as.numeric(amt_qrtr)
    ) %>% 
    arrange(case_id,quarter)

  return(tmp)
}

如果仔细观察 case_id == a 的结果,那么结果看起来像这样

print(outputs() %>% filter (case_id == 'a'), n= 30)

   case_id quarter amt_qrtr
   <fct>     <dbl>    <dbl>
 1 a             1       80
 2 a             2       65
 3 a             3       52
 4 a             4       39
 5 a             5       89
 6 a             6       94
 7 a             7       95
 8 a             8       96
 9 a             9       95
10 a            10       94
11 a            11       89
12 a            12       80

然而,相同参数(与 inputs 中的第一行匹配)的正确结果是

#Correct example output
forecast_curve('a',5,4,10,12)
   case_id quarter amt_qrtr
   <chr>     <dbl>    <dbl>
 1 a             1    0.755
 2 a             2    0.940
 3 a             3    1.10 
 4 a             4    1.21 
 5 a             5    1.24 
 6 a             6    1.21 
 7 a             7    1.10 
 8 a             8    0.940
 9 a             9    0.755
10 a            10    0.570
11 a            11    0.404
12 a            12    0.269

从 SO 上的类似问题看来,解决方案是 do.call,但我无法在下面的案例中使用它。

非常感谢您的指导

你让问题变得更难了。假设你有一个像forecast_curve这样的函数,你可以直接用mapply调用这个函数。不需要 outputs 函数。

在您的控制台 window 中,键入 ?mapply 查看 mapply 的帮助,以便您可以看到所需的参数。 mapply 将调用为 FUN 指定的函数,将 ... 参数中每个向量的第一个值传递给 FUN。然后它将使用 ... 参数中每个向量的第二个值再次调用该函数。等等。如果您设置 SIMPLIFY = F,结果将始终在列表中 returned。

由于 forecast_curve return 是一个小标题,当您 mapplyFUN = forecast_curve 时,您将得到一个小标题列表。因此,以下代码将 return 包含 10 个小标题的列表,inputs 小标题的每一行一个。

listOfTibbles = 
  mapply(
    forecast_curve,
    inputs$case_id,
    inputs$wal,
    inputs$wal_sd,
    inputs$total_amt_FC, 
    inputs$n_qrtr,
    SIMPLIFY = F
  )

如果您想将所有这些小标题合并为一个小标题,您需要使用 rbind,而不是 unlist。你可以这样做:

singleTibble = rbind(listOfTibbles[[1]], listOfTibbles[[2]], listOfTibbles[[3]], listOfTibbles[[4]], listOfTibbles[[5]], listOfTibbles[[6]], listOfTibbles[[7]], listOfTibbles[[8]], listOfTibbles[[9]], listOfTibbles[[10]])

但是 do.call 提供了一种更简单的方法。 do.call 使用列表中的值作为函数的参数调用函数(在本例中为 rbind)。所以你得到相同的结果使用:

singleTibble = do.call(rbind, listOfTibbles)