在数据框中逐行应用向量化多变量函数
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 是一个小标题,当您 mapply
和 FUN = 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)
我在 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 是一个小标题,当您 mapply
和 FUN = 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)