Могу ли я применить функцию XIRR из библиотеки tvm для каждой строки в моей таблице, где денежные потоки уже находятся в этой строке?
Это мой первый вопрос, поэтому я заранее прошу прощения, если это не совсем заданный вопрос. Я уже искал по всему переполнению стека (& Google), но не смог найти то, что я ищу. Кроме того, я новичок в R и изучаю его сам по себе.
Мои проблемы заключаются в следующем: я пытаюсь вычислить внутреннюю норму прибыли для каждой строки в моей таблице, используя функцию XIRR из tvm. Мне удалось заставить 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)
В моем конкретном сценарии у меня есть таблица с периодическими денежными потоками и датами, заполненными в каждой строке для каждого идентификатора. Денежные потоки находятся в столбцах 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.
Это возможно, или я должен искать какую-то другую функцию? Спасибо!
РЕДАКТИРОВАТЬ - Дополнительные детали и ответ на вопрос, почему ответ "сверстников" не работал
Мои фактические данные содержат денежные потоки и даты в виде длинных таблиц с более чем 5,5 миллионами строк. Причина, по которой я преобразовал их в "устаревшую" таблицу, заключается в том, что в конечном итоге я пытаюсь создать скользящий ежемесячный расчет IRR. Я подумал, что если бы я построил потоки "Дата" и "Денежный поток" в каждой строке, то я мог бы избежать циклического применения XIRR непосредственно к каждой строке. Создание длинной таблицы, включающей каждую итерацию идентификатора / даты, не будет реалистичным для такого количества данных (я не думаю).
С помощью предложенного кода денежные потоки и даты объединяются для одного и того же идентификатора, поэтому он не учитывает скользящие периоды. Я знаю, что это не объяснялось в моем первоначальном вопросе.
Кроме того, у меня есть периоды с отсутствующими денежными потоками, которые показывают NA (так как они видоизменяются как.numeric). Мне нужен XIRR, чтобы справиться с этим, не выполняя вычисления, когда есть какие-либо NA. Я думаю, что это можно сделать с помощью 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+ часов), но дает правильные результаты. Есть ли способ переписать это, используя параллельную обработку или без строки, что я предполагаю, что это операция цикла и медленная.
1 ответ
Прежде всего, tbl_df
кажется устаревшим, используйте as_tibble
или же as.tibble
вместо.
Я также изменил пример данных, так как получаю ошибку при применении данных с идентификатором "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)))