Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sum a series in R

Tags:

dataframe

r

I have a dataframe that looks as follows:

id  amount  number  discount
 1  400     10      0.7
 2  500     5       0.7
 3  600     10      0.6
df <- structure(list(id = 1:3, amount = c(400L, 500L, 600L), number = c(10L, 
5L, 10L), discount = c(0.7, 0.7, 0.6)), class = "data.frame", row.names = c(NA, 
-3L))

I have a formula, where N is the number column in the dataframe

enter image description here

So for the first row I would be summing:

400/(1+0.7)^0 + 400/(1+0.7)^1 + 400/(1+0.7)^2 +.... + 400/(1+0.7)^9

How could I do this for each row?

like image 546
Niam45 Avatar asked Dec 09 '22 23:12

Niam45


2 Answers

Is this matches your desired output?

BaseR approach

mapply(function(x, y, z) sum(Reduce(function(.x, .y) {.x/y }, seq_len(z -1), x, accumulate = T)), 
       df$amount, 1 + df$discount, df$number)
[1]  966.610 1128.764 1585.448

tidyverse approach

df <- structure(list(id = 1:3, amount = c(400L, 500L, 600L), number = c(10L, 
                                                                        5L, 10L), discount = c(0.7, 0.7, 0.6)), class = "data.frame", row.names = c(NA, 
                                                                                                                                                    -3L))
library(tidyverse)
df %>% rowwise() %>%
  mutate(calc = sum(accumulate(seq_len(number-1), .init = amount, ~ .x/(1 + discount))))
#> # A tibble: 3 x 5
#> # Rowwise: 
#>      id amount number discount  calc
#>   <int>  <int>  <int>    <dbl> <dbl>
#> 1     1    400     10      0.7  967.
#> 2     2    500      5      0.7 1129.
#> 3     3    600     10      0.6 1585.

Created on 2021-05-24 by the reprex package (v2.0.0)

accumulate creates a geometrical series as output

accumulate(1:9, .init = 400, ~.x/(1 + 0.7))

[1] 400.000000 235.294118 138.408304  81.416650  47.892147  28.171851  16.571677   9.748045   5.734144   3.373026

Using rowwise and sum will SUM the geometrical series, as finally desired

sum(accumulate(1:9, .init = 400, ~.x/(1 + 0.7)))
[1] 966.61
like image 120
AnilGoyal Avatar answered Dec 29 '22 14:12

AnilGoyal


You can use any of the apply command in base R -

mapply(function(x, y, z) sum(x/(y ^ 0:z)), df$amount, 1 + df$discount, df$number)

OR with dplyr -

  
library(dplyr)

df %>%
  rowwise() %>%
  mutate(res = sum(amount/((1 + discount) ^ 0:number))) %>%
  ungroup

#   id amount number discount   res
#  <int>  <int>  <int>    <dbl> <dbl>
#1     1    400     10      0.7 1172.
#2     2    500      5      0.7 1142.
#3     3    600     10      0.6 1757.
like image 33
Ronak Shah Avatar answered Dec 29 '22 14:12

Ronak Shah