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

问题描述 投票:0回答:1

我在SO上广泛搜索了一下,但没有找到和我一模一样的问题的答案。

我试图用一个函数来生成一些时间序列条目,这个函数从多变量参数的 inputs 数据框。每个变量集 {x,y,z,...}inputs 生成一个时间序列数据框架;其中的集合需要解列。

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 但我不能让它与我的情况下,下面的工作。

非常感谢任何指导

r apply do.call
1个回答
1
投票

你把问题弄得比它更难。 假设你有一个函数,如 forecast_curve,你可以直接用 mapply. 没有必要。outputs 功能。

在控制台窗口中,输入 ?mapply 来看看帮助 mapply 这样你就可以看到所需的参数。 mapply 将调用为 FUN,传递给 FUN 中每个向量的第一个值。... 参数。 然后,它将再次调用该函数,使用 ... 参数。 以此类推。 如果你设置了 SIMPLIFY = F,结果总是以列表形式返回。

因为 forecast_curve 返回一个tibble,当你 mapplyFUN = forecast_curve,你将得到一个tibbles的列表。 因此,下面的代码将返回一个包含10个tibbles的列表,每一行都有一个tibbles。inputs tibble。

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

如果您想将所有这些 tibbles 合并成一个 tibble,您需要使用 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)
© www.soinside.com 2019 - 2024. All rights reserved.