Кумулятивная мера с использованием R, встроенного в SQL

Простите, что я очень новичок в R, и я просто смотрю варианты, которые в настоящее время находятся в нашей среде SQL 2016.

В настоящее время у нас есть требование предоставить кумулятивную прибыль. Примерный набор данных приведен ниже:

FundID  Date        FundReturn
ABC     1987-10-31  0
ABC     1987-11-30  -9.28669
ABC     1987-12-31  3.08304
ABC     1988-01-31  -3.00125
ABC     1988-02-29  0.61238
ABC     1988-03-31  4.29258
ABC     1988-04-30  0.13697
ABC     1988-05-31  2.57786
ABC     1988-06-30  2.36947
ABC     1988-07-31  0.57114
ABC     1988-08-31  -1.21550
ABC     1988-09-30  7.09027
ABC     1988-10-31  3.45807
ABC     1988-11-30  1.12679

Нам нужно будет взять этот набор данных и применить к нему совокупный показатель возврата производительности, чтобы datset выглядел следующим образом:

FundID  Date        FundReturn      FundReturnCumu100   FundReturnCumu0
ABC     1987-10-31  0               1                   0
ABC     1987-11-30  -9.28669        0.9071331           -0.0928669
ABC     1987-12-31  3.08304         0.935100376         -0.064899624
ABC     1988-01-31  -3.00125        0.907035676         -0.092964324
ABC     1988-02-29  0.61238         0.912590181         -0.087409819
ABC     1988-03-31  4.29258         0.951763845         -0.048236155
ABC     1988-04-30  0.13697         0.953067476         -0.046932524
ABC     1988-05-31  2.57786         0.977636221         -0.022363779
ABC     1988-06-30  2.36947         1.000801018         0.000801018
ABC     1988-07-31  0.57114         1.006516993         0.006516993
ABC     1988-08-31  -1.2155         0.994282779         -0.005717221
ABC     1988-09-30  7.09027         1.064780113         0.064780113
ABC     1988-10-31  3.45807         1.101600954         0.101600954
ABC     1988-11-30  1.12679         1.114013684         0.114013684

Я могу создать это в SQL со следующим кодом:

SELECT
        FundID          
    ,   [Date]          
    ,   FundReturn      

    ,   ISNULL  (
                    EXP(SUM(LOG(ABS(NULLIF((FundReturn+100)/100, 1))))
                        OVER(ORDER BY FundID, [Date] ROWS UNBOUNDED PRECEDING))
                ,1)                                                     AS FundReturnCumu100        

    ,   ISNULL  (
                    EXP(SUM(LOG(ABS(NULLIF((FundReturn+100)/100, 1))))
                        OVER(ORDER BY FundID, [Date] ROWS UNBOUNDED PRECEDING))
                ,1)-1                                                   AS FundReturnCumu0  

FROM #Worktable
ORDER BY [Date]

Я также хочу проверить, возможно ли это, используя функцию R, встроенную в хранимую процедуру SQL, чтобы получить тот же результат? Вышеприведенная математика в основном является результатом возврата производительности в период времени, поэтому есть ли функция продукта, которую я мог бы использовать, чтобы создать тот же результат datset?

Изменить: я до сих пор выполнял следующие действия, которые возвращают основу набора данных, используя sp_execute_external_script:

EXEC sp_execute_external_script
        @language       =   N'R'
    ,   @script         =   N'OutputDataSet<-InputDataSet'
    ,   @input_data_1   =   N'  SELECT * 
                                FROM [InMemory].[dbo].[CumulativePerformanceTest] 
                                ORDER BY [FundID],[Date]'

WITH RESULT SETS    (
                    (
                            [FundID]            NVARCHAR(50)
                        ,   [Date]              DATE
                        ,   [FundReturn]        NVARCHAR(255)
                    )
                    );


GO

Что мне нужно сделать, чтобы изменить приведенное выше, чтобы применить вычисления FundReturnCumu100 и FundReturnCumu0 в R?

Спасибо

Ответ 1

После долгих размышлений в Google мне удалось это решить. В итоге я придумал следующее:

DECLARE @R_Script NVARCHAR(MAX);

SET @R_Script = N'
                OutputDataSet <- InputDataSet;
                OutputDataSet[,6] <- exp(cumsum(log(abs((InputDataSet$FundReturn+100)/100))));
                OutputDataSet[,7] <- exp(cumsum(log(abs((InputDataSet$BenchmarkReturn+100)/100))));
                OutputDataSet[,8] <- exp(cumsum(log(abs((InputDataSet$SectorReturn+100)/100))));
                OutputDataSet[,9] <- (exp(cumsum(log(abs((InputDataSet$FundReturn+100)/100)))))-1;
                OutputDataSet[,10] <- (exp(cumsum(log(abs((InputDataSet$BenchmarkReturn+100)/100)))))-1;
                OutputDataSet[,11] <- (exp(cumsum(log(abs((InputDataSet$SectorReturn+100)/100)))))-1;';

DECLARE @SQL_Script NVARCHAR(MAX)

SET @SQL_Script = N'
                    SELECT 
                            FundID
                        ,   Date
                        ,   CONVERT(DECIMAL(38,6), FundReturn)          AS FundReturn
                        ,   CONVERT(DECIMAL(38,6), BenchmarkReturn)     AS BenchmarkReturn
                        ,   CONVERT(DECIMAL(38,6), SectorReturn)        AS SectorReturn

                    FROM [InMemory].[dbo].[CumulativePerformanceTest] 
                    WHERE FundID = ''F000002D0V''
                    ORDER BY FundID,Date;';

EXEC sp_execute_external_script

@language = N'R',

@script = @R_Script,

@input_data_1 = @SQL_Script

WITH RESULT SETS    (
                    (
                            [FundID]                    NVARCHAR(50)
                        ,   [Date]                      DATE
                        ,   [FundReturn]                DECIMAL(38,6)
                        ,   [BenchmarkReturn]           DECIMAL(38,6)
                        ,   [SectorReturn]              DECIMAL(38,6)
                        ,   [FundReturnCumu100]         DECIMAL(38,6)
                        ,   [BenchmarkReturnCumu100]    DECIMAL(38,6)
                        ,   [SectorReturnCumu100]       DECIMAL(38,6)
                        ,   [FundReturnCumu0]           DECIMAL(38,6)
                        ,   [BenchmarkReturnCumu0]      DECIMAL(38,6)
                        ,   [SectorReturnCumu0]         DECIMAL(38,6)
                    )
                    );

GO

Я знаю, что кодирование потенциально может потребовать немного опрятного, но оно работает :)

Ответ 2

Мы можем преобразовать его в dplyr код с помощью

library(dplyr)
df1 %>% 
   arrange(FundID, Date) %>%
   mutate(FundReturnCumu100 = exp(cumsum(log(abs((FundReturn + 100)/100)))), 
          FundReturnCumu0 = FundReturnCumu100 - 1)
# FundID       Date FundReturn FundReturnCumu100 FundReturnCumu0
#1     ABC 1987-10-31    0.00000         1.0000000    0.0000000000
#2     ABC 1987-11-30   -9.28669         0.9071331   -0.0928669000
#3     ABC 1987-12-31    3.08304         0.9351004   -0.0648996237
#4     ABC 1988-01-31   -3.00125         0.9070357   -0.0929643237
#5     ABC 1988-02-29    0.61238         0.9125902   -0.0874098186
#6     ABC 1988-03-31    4.29258         0.9517638   -0.0482361550
#7     ABC 1988-04-30    0.13697         0.9530675   -0.0469325241
#8     ABC 1988-05-31    2.57786         0.9776362   -0.0223637789
#9     ABC 1988-06-30    2.36947         1.0008010    0.0008010181
#10    ABC 1988-07-31    0.57114         1.0065170    0.0065169930
#11    ABC 1988-08-31   -1.21550         0.9942828   -0.0057172210
#12    ABC 1988-09-30    7.09027         1.0647801    0.0647801126
#13    ABC 1988-10-31    3.45807         1.1016010    0.1016009542
#14    ABC 1988-11-30    1.12679         1.1140137    0.1140136836