4

我有一个大数据集(大约 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 }

你可以这样做

rate = Irr(c(amt,rep(pmt,times=n)))

问题是当您尝试计算大量付款的费率时。因为 uniroot 没有向量化,并且 rep 花费了惊人的时间,所以最终计算速度很慢。如果您进行一些数学运算并确定您正在寻找以下等式的根,则可以使其更快

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

然后将其用作 uniroot 的输入。对于我的 200k 数据库,这在我的电脑中运行大约需要 20 秒。

问题是我正在尝试做一些优化,这是优化的一个步骤,所以我试图加快速度。

我已经尝试过矢量化,但是因为 uniroot 没有矢量化,所以我不能走得更远。是否有任何矢量化的求根方法?

谢谢

4

1 回答 1

7

您可以使用线性插值器,而不是使用根查找器。您必须为n(剩余付款次数)的每个值创建一个插值器。每个插值器将映射(1-1/(1+r)^n)/rr. 当然,您必须构建一个足够精细的网格,这样它才能恢复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)

请注意,我使用了 1/100 百分比 (1bp) 的精度。

然后我们创建一些假数据:

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)

最后,我们解决r

library(plyr)
system.time(ddply(loans, "n", transform, r = interpolators[[n[1]]](amt / pmt)))
#    user  system elapsed 
#   2.684   0.423   3.084

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

于 2012-12-13T22:51:24.557 回答