首页 > 解决方案 > 我可以将 tvm 库中的 XIRR 函数应用于表中的每一行,其中现金流已经在该行上?

问题描述

这是我的第一个问题,所以如果这不是一个完美的问题,我提前道歉。我已经在 Stack Overflow (& Google) 上进行了搜索,但找不到我要找的东西。另外,我是 R 的新手,我正在自己学习它。

我的问题是:我正在尝试使用 tvm 的 XIRR 函数计算表中每一行的内部收益率。我能够让 XIRR 为单一现金流工作。这是我能够开始工作的一个例子。

# This is a sample that works
install.packages("tvm")
library(tvm)

x_CF <- c(-7500, 3000, 5000, 1200, 4000)
x_d <- as.Date(c("2016-01-01", "2016-02-01", "2016-04-15", "2016-08-01", "2017-03-26"))
xirr <- xirr(x_CF, x_d)

在我的特定场景中,我有一个表格,其中包含每个 ID 的每行填充的定期现金流和日期。现金流在列 cf1, cf2, cf3, cf(n)... 日期在列 date1, date2, date3, date(n)... 目前现金流和日期的数量为 14 (n =14),但可能有所不同(即 36、60 等)。这是一个从我更大的表中填充 2 行的代码。

# This is just 2 rows of my data table where I manually write the values (the real table is much larger and is dynamically created with code)    

sample_data <-
    matrix(
        c(
            "A",
            "2016-01-31", "2016-02-29", "2016-03-31","2016-04-30","2016-05-31",
            1000, 10, 20, -50, -1025,
            "B",
            "2016-01-31", "2016-02-29", "2016-03-31","2016-04-30", "2016-05-31",
            1000, -50, 20, 10, -1025),
        ncol = 11, byrow = TRUE)

colnames(sample_data) <-
    c("SecId",
      "date1", "date2", "date3", "date4", "date5",
      "cf1", "cf2", "cf3", "cf4", "cf5")

sample_data <- tbl_df(sample_data)

sample_data <-
    sample_data %>% mutate_at(vars(starts_with("cf")),
                              funs(as.integer))
sample_data <-
    sample_data %>% mutate_at(vars(starts_with("date")),
                              funs(as.Date))

我想使用 XIRR 函数来读取 cf1:n 和 date1:n。结果应该是插入的另一列 (XIRR),计算值为 A = 0.1412532 和 B = 0.1458380。

这可能吗,还是我应该研究其他功能?谢谢!

编辑 - 附加详细信息和对“同行”答案为何不起作用的回应

我的实际数据包含超过 550 万行的长表格式的现金流和日期。我将它们转换为“已弃用”表的原因是因为我最终要做的是创建一个滚动的每月 IRR 计算。我想如果我在每一行上建立日期和现金流,那么我可以避免循环将 XIRR 直接应用于每一行。创建包含 ID/Date 每次迭代的长表对于这么多数据是不现实的(我不认为)。

使用建议的代码,现金流和日期合并为相同的 ID,因此它不考虑滚动期。我知道这在我原来的问题中没有解释。

此外,我有一段时间缺少显示 NA 的现金流(因为它们被变异为.numeric)。我需要 XIRR 在有任何 NA 时不执行计算来处理这个问题。我认为这可以通过 summarise 命令中的 is.na = TRUE 来处理。

编辑#2:找到部分解决方案

在玩弄这个之后,我能够让 XIRR 函数为上面的示例数据工作。这是有效的代码,但我的实际数据需要很长时间。

calc_xirr <- sample_data %>% rowwise() %>%
do(data.frame(., xirr = tryCatch(xirr(unlist(.[7:11]), unlist(.[2:6]),lower=0,upper=1),
                                 error = function(e) {NA}))) %>%
select(SecId, xirr)

我收到一条警告消息“警告消息:在 bind_rows_(x, .id) 中:不相等的因子级别:强制转换为字符”,但计算是准确的。

我仍然遇到的问题是这对于我的实际数据集来说有多慢。它运行了很长时间(6 小时以上),但确实产生了正确的结果。有没有办法使用并行处理或不按行来重写它,我假设这是一个循环操作并且很慢。

标签: rxirr

解决方案


首先,tbl_df似乎已弃用,使用as_tibbleas.tibble代替。

我还更改了您的示例数据,因为在应用来自 ID“A”的数据时出现错误。我将样本数据定义如下。

sample_data <-
  matrix(
    c(
      "A",
      "2016-01-01",
      "2016-02-01",
      "2016-04-15",
      "2016-08-01",
      "2017-03-26",
      -7500,
      3000,
      5000,
      1200,
      4000,
      "B",
      "2016-01-01",
      "2016-02-01",
      "2016-04-15",
      "2016-08-01",
      "2017-03-26",
      -7500,
      3000,
      5000,
      1200,
      4000
    ),
    ncol = 11,
    byrow = TRUE
  )

colnames(sample_data) <-
  c("ID",
    "date1",
    "date2",
    "date3",
    "date4",
    "date5",
    "cf1",
    "cf2",
    "cf3",
    "cf4",
    "cf5")

我将我的代码分成两部分。第一部分是整理数据,第二部分是创建所需的值。

sample_data <- tbl_df(sample_data)

sample_data <-
  sample_data %>% mutate_at(vars(starts_with("cf")),
                            funs(as.numeric),
                            vars(starts_with("date")),
                            funs(as.Date))
sample_data_dates <-
  sample_data %>% select(starts_with("date"), ID) %>% gather(key, date, -ID) %>% mutate(index = gsub("date", "", key))
sample_data_cashflows <-
  sample_data %>% select(starts_with("cf"), ID) %>% gather(key, cashflow,-ID) %>% mutate(index = gsub("cf", "", key))

sample_data <-
  inner_join(
    sample_data_dates %>% select(-key),
    sample_data_cashflows %>% select(-key),
    by = c("ID", "index")
  ) %>% select(-index)

在此之后,您将拥有一个包含列名 ID、日期和现金流量的表。然后,您可以通过以下代码简单地计算函数 xirr 的结果:

sample_data %>% group_by(ID) %>% summarise(xirr(cashflow,as.Date(date)))

推荐阅读