R 快速计算大量贷款的贷款利率

R 快速计算大量贷款的贷款利率,r,finance,R,Finance,我有一个大数据集(大约20万行),其中每一行都是贷款。我有贷款金额、付款数量和贷款付款。 我正在设法得到贷款利率。 R没有计算这个的函数(至少base R没有,我找不到)。 编写npv和irr函数并不难 Npv <- function(i, cf, t=seq(from=0,by=1,along.with=cf)) sum(cf/(1+i)^t) Irr <- function(cf) { uniroot(npv, c(0,100000), cf=cf)$root } 问题是当你试

我有一个大数据集(大约20万行),其中每一行都是贷款。我有贷款金额、付款数量和贷款付款。 我正在设法得到贷款利率。 R没有计算这个的函数(至少base R没有,我找不到)。 编写npv和irr函数并不难

Npv <- function(i, cf, t=seq(from=0,by=1,along.with=cf)) sum(cf/(1+i)^t)
Irr <- function(cf) { uniroot(npv, c(0,100000), cf=cf)$root }
问题是当你试图计算大量付款的利率时。因为uniroot没有矢量化,而且rep需要惊人的时间,所以最终的计算速度很慢。如果你做一些数学运算,找出你在寻找下面等式的根,你可以使它更快

zerome <- function(r) amt/pmt-(1-1/(1+r)^n)/r

zerome您可以使用线性插值器,而不是使用根查找器。您必须为
n
的每个值(剩余付款数)创建一个插值器。每个插值器将
(1-1/(1+r)^n)/r
映射到
r
。当然,您必须构建足够精细的网格,以便它将
r
返回到可接受的精度水平。这种方法的好处在于线性插值器速度快且矢量化:您可以在对相应插值器的一次调用中找到剩余付款数相同(
n
)的所有贷款的利率

现在,一些代码证明它是一个可行的解决方案:

首先,我们创建插值器,为
n
的每个可能值创建一个插值器:

n.max <- 360L  # 30 years

one.interpolator <- function(n) {
    r <- seq(from = 0.0001, to = 0.1500, by = 0.0001)
    y <- (1-1/(1+r)^n)/r
    approxfun(y, r)
}

interpolators <- lapply(seq_len(n.max), one.interpolator)

很快。请注意,一些输出速率是
NA
,但这是因为我的随机输入没有意义,返回的速率超出了我选择的[0~15%]网格。你的真实数据不会有这个问题。

首先,我会把对rep的呼叫放在对Irr的呼叫之外,因为每次似乎都是一样的。第二,如果我没记错的话,只需稍加努力,就可以将计算转换为对polyroot的调用,而不是对uniroot的调用(我不保证这会更快,但我猜可能会更快)。第三,很容易对函数进行矢量化,尤其是通过矢量化。第四,良好的起点会有所帮助。任何这些都可能加快速度。@Glen_b 1-问题不是每次uniroot迭代时rep都会运行,而是每次计算贷款时rep都会运行,而且每个贷款都有不同的付款金额。2-polyroot返回所有根,而不仅仅是第一个根(在这种情况下,只有一个根,但如果有更多根,可能会更慢)3-我尝试了矢量化,但uniroot不可矢量化,这已经讨论了很多次了4-uniroot使用的是起始间隔,而不是点。我同意这一点,但在这种情况下,有一些奇怪的贷款与野生利率,和原因,我不能把一个狭窄的间隔特里尼斯!!我同意1bps就足够了(我用它)。这可能比矢量化根查找器更快。至于真实数据,遗憾的是,它有一些异常值,因此我需要一个更大的网格,但我不认为这会成为操作时间的问题
n.max <- 360L  # 30 years

one.interpolator <- function(n) {
    r <- seq(from = 0.0001, to = 0.1500, by = 0.0001)
    y <- (1-1/(1+r)^n)/r
    approxfun(y, r)
}

interpolators <- lapply(seq_len(n.max), one.interpolator)
n.loans <- 200000L
n     <- sample(n.max, n.loans, replace = TRUE)
amt   <- 1000 * sample(100:500, n.loans, replace = TRUE)
pmt   <- amt / (n * (1 - runif(n.loans)))
loans <- data.frame(n, amt, pmt)
library(plyr)
system.time(ddply(loans, "n", transform, r = interpolators[[n[1]]](amt / pmt)))
#    user  system elapsed 
#   2.684   0.423   3.084