3-мерный IRR в Matlab 2019 - PullRequest
       28

3-мерный IRR в Matlab 2019

7 голосов
/ 04 июня 2019

Я пытаюсь рассчитать IRR с несколькими измерениями в Matlab 2019a.Моя формула работает теоретически (на данный момент игнорируется предупреждение «множественные нормы доходности»), но проблема в том, что для больших матриц, то есть noScenarios> 5 или около того, код становится очень медленным.Каковы альтернативы программирования для этого?Я пробовал также fsolve, но я думаю, что он тоже не быстрый.

Обратите внимание, что, поскольку я не математик, простого ключевого слова, такого как "метод Брента", мне не достаточно (например, как в Каков наиболее эффективный способ расчета внутренней нормы доходности IRR? ).Я должен был бы знать а) как реализовать это в Matlab, и б) если это довольно идиотское доказательство, чтобы ничего не пошло не так?Спасибо!

clc
clear
close all

noScenarios = 50;

CF = ones(300,noScenarios,noScenarios,noScenarios);
CF = [repmat(-300, 1,noScenarios,noScenarios,noScenarios); CF];

for scenarios1 = 1:noScenarios
    for scenarios2 = 1:noScenarios
        for scenarios3 = 1:noScenarios
            IRR3dimensional(scenarios1,scenarios2,scenarios3) = irr(CF(:,scenarios1,scenarios2,scenarios3));
        end
    end
end

1 Ответ

2 голосов
/ 18 июня 2019

Чтобы рассчитать IRR, вам нужно решить полиномиальное уравнение.Это должно быть сделано для каждого вектора денежного потока отдельно.Следовательно, применение irr к многомерной матрице не улучшает время выполнения.Я подозреваю, что Matlab все еще использует цикл для внутреннего использования.

Возможно, вам удастся набрать некоторую скорость, играя с опциями оптимизации fsolve, но значительное улучшение маловероятно.Предположительно, разработчики Matlab уже выбрали достаточно хороший подход.

Таким образом, ваша единственная альтернатива - распараллеливание.Если у вас есть доступ к серверу или ваш ноутбук / настольный компьютер имеет несколько процессоров, вы можете сократить время выполнения, запустив функции irr параллельно.(Вам также, вероятно, понадобится Parallel Computing Toolbox.)

Я немного изменил ваш пример, чтобы использовать случайные значения денежных потоков, чтобы упростить проверку.Однако я уменьшил количество сценариев и временных точек, чтобы функция timeit могла выполнять несколько симуляций за разумное время.(Также имейте в виду, что время выполнения кажется экспоненциальным по количеству временных точек.)

t = 150;
noScenarios = 10;
noThreads = 4;

CF = rand(t,noScenarios,noScenarios,noScenarios);
CF = [-rand(1,noScenarios,noScenarios,noScenarios); CF];

h1 = @() f1(CF, noScenarios);
fprintf("%0.4f : single thread, loop\n", timeit(h1))

h2 = @() f2(CF, noScenarios);
fprintf("%0.4f : single thread, vectorized\n", timeit(h2))

poolObj = parpool('local', noThreads);
h3 = @() f3(CF, noScenarios);
fprintf("%0.4f : parallelized outer loop\n", timeit(h3))
delete(poolObj);

poolObj = parpool('local', noThreads);
h4 = @() f4(CF, noScenarios);
fprintf("%0.4f : parallelized inner loop\n", timeit(h4))
delete(poolObj);

function res = f1(CF, noScenarios)
    res = zeros(noScenarios, noScenarios, noScenarios);
    for scenarios1 = 1:noScenarios
        for scenarios2 = 1:noScenarios
            for scenarios3 = 1:noScenarios
                res(scenarios1,scenarios2,scenarios3) = irr(CF(:,scenarios1,scenarios2,scenarios3));
            end
        end
    end
end

function res = f2(CF, noScenarios)
    res = reshape(irr(CF), noScenarios, noScenarios, noScenarios);
end

function res = f3(CF, noScenarios)
    res = zeros(noScenarios, noScenarios, noScenarios);
    parfor scenarios1 = 1:noScenarios
        for scenarios2 = 1:noScenarios
            for scenarios3 = 1:noScenarios
                res(scenarios1,scenarios2,scenarios3) = irr(CF(:,scenarios1,scenarios2,scenarios3));
            end
        end
    end
end

function res = f4(CF, noScenarios)
    res = zeros(noScenarios, noScenarios, noScenarios);
    for scenarios1 = 1:noScenarios
        for scenarios2 = 1:noScenarios
            parfor scenarios3 = 1:noScenarios
                res(scenarios1,scenarios2,scenarios3) = irr(CF(:,scenarios1,scenarios2,scenarios3));
            end
        end
    end
end

Когда я запускал этот код на сервере с 4 ЦП и 16 ГБ памяти, яполучил следующие результаты.

19.9357 : single thread, loop
20.4318 : single thread, vectorized
...
5.6346 : parallelized outer loop
...
12.4640 : parallelized inner loop

Как видите, векторизованная версия irr не дает никаких преимуществ по сравнению с циклом.В этом случае это немного медленнее.В других моих тестах это иногда было немного быстрее.

Однако вы можете значительно сократить время выполнения, распараллеливая внешний цикл с функцией parfor.Это лучше, чем распараллеливание самого внутреннего цикла, поскольку каждый пакет имеет определенные накладные расходы на выполнение.Таким образом, небольшое количество больших пакетов имеет меньшие накладные расходы, чем большое количество меньших пакетов.

Вот как работает распараллеливание.Сначала вы создаете пул локальных рабочих потоков с помощью команды ниже.Убедитесь, что вы не превышаете количество процессоров, которые у вас есть.parpool может ждать до тех пор, пока все локальные работники не будут созданы, и он может создавать только локального работника, если доступен ЦП.

poolObj = parpool('local', noThreads);

Создание пула может занять несколько секунд.Именно поэтому я переместил это вне функции, которую я рассчитал.Для больших заданий время создания пула незначительно по сравнению с общим временем выполнения.

Здесь я сохраняю объект пула в переменной и впоследствии удаляю его.Тем не менее, это необязательно.По умолчанию пул уничтожается через 30 минут бездействия или после завершения работы Matlab.

После этого вы заменяете цикл for, который хотите распараллелить, на вызов parfor, т.е. for scenarios1 = 1:noScenarios становится parfor scenarios1 = 1:noScenarios.По умолчанию parfor будет использовать всех доступных работников, но вы также можете указать максимальное количество работников, которое ему разрешено использовать с parfor (scenarios1 = 1:noScenarios, maxWorkers).Обратите внимание, однако, что порядок выполнения не гарантируется, то есть пятая итерация может быть выполнена до третьей итерации.

...