简体   繁体   中英

Calculating real dollar values based on nominal values in R

I have a dataset that contains a few variables

Plan <- c("A","A","A","B","B","B","B")    
Plan_Period <- c(1,2,3,1,2,3,4)
Plan_Elapsed_time <- c(0.5,1,0.25,1,0.5,0.3,0.25)
year <- c(2016,2017,2018,2015,2016,2017,2018)
Inflation <- c(1.014,1.012,1.012,1.013,1.012, 1.080,1.020)
Cost <- c(10,20,30,40,40,50,60)

data <- data.frame(Plan, Plan_Period, Plan_Elapsed_time, year, Inflation, Cost)

The formula for converting a dollar value from nominal to real for plan A is as below:

  • real value for period 1: 10*(1.014^0.5)*(1.012^1)*(1.012^0.25)

  • real value for period 2: 20*(1.012^1)*(1.012^0.25)

  • real value for period 3: 30*(1.012^0.25)

I want to use other functions to do this on a dataset with more than 1000 different plans instead of writing a for loop, .

I appreciate your help!

Using Base R: we can use tidyverse too

data=data.frame(Plan,Plan_Period ,Plan_Elapsed_time,year, Inflation,Cost

transform(data,m=Cost*ave(Inflation^Plan_Elapsed_time,Plan,
                 FUN=function(x)rev(cumprod(rev((x))))))
  Plan Plan_Period Plan_Elapsed_time year Inflation Cost        m
1    A           1              0.50 2016     1.014   10 10.22103
2    A           2              1.00 2017     1.012   20 20.30045
3    A           3              0.25 2018     1.012   30 30.08960
4    B           1              1.00 2015     1.013   40 41.92150
5    B           2              0.50 2016     1.012   40 41.38352
6    B           3              0.30 2017     1.080   50 51.42179
7    B           4              0.25 2018     1.020   60 60.29778

 library(tidyverse)
 data%>%
   group_by(Plan)%>%
   mutate(m=Cost*rev(cumprod(rev(Inflation^Plan_Elapsed_time))))
# A tibble: 7 x 7
# Groups:   Plan [2]
  Plan  Plan_Period Plan_Elapsed_time  year Inflation  Cost     m
  <fct>       <dbl>             <dbl> <dbl>     <dbl> <dbl> <dbl>
1 A            1.00             0.500  2016      1.01  10.0  10.2
2 A            2.00             1.00   2017      1.01  20.0  20.3
3 A            3.00             0.250  2018      1.01  30.0  30.1
4 B            1.00             1.00   2015      1.01  40.0  41.9
5 B            2.00             0.500  2016      1.01  40.0  41.4
6 B            3.00             0.300  2017      1.08  50.0  51.4
7 B            4.00             0.250  2018      1.02  60.0  60.3

library(data.table)
setDT(data)[,m:=(Cost*rev(cumprod(rev(Inflation^Plan_Elapsed_time)))),by=Plan][]
   Plan Plan_Period Plan_Elapsed_time year Inflation Cost        m
1:    A           1              0.50 2016     1.014   10 10.22103
2:    A           2              1.00 2017     1.012   20 20.30045
3:    A           3              0.25 2018     1.012   30 30.08960
4:    B           1              1.00 2015     1.013   40 41.92150
5:    B           2              0.50 2016     1.012   40 41.38352
6:    B           3              0.30 2017     1.080   50 51.42179
7:    B           4              0.25 2018     1.020   60 60.29778

There is no need for loops. Using the data.table package you can calculate the cumulated inflation by group and multiply the result with the cost:

data <- data.frame(
  Plan = c("A","A","A","B","B","B","B"),    
  Plan_Period=c(1,2,3,1,2,3,4),
  Plan_Elapsed_time=c(0.5,1,0.25,1,0.5,0.3,0.25),
  year=c(2016,2017,2018,2015,2016,2017,2018),
  Inflation= c(1.014,1.012,1.012,1.013,1.012, 1.080,1.020),
  Cost= c(10,20,30,40,40,50,60)
)

library(data.table)
setDT(data)
data <- data[order(Plan, -Plan_Period)][, Cum_Inflation := cumprod(Inflation^Plan_Elapsed_time), by = Plan][, Real_Cost := Cost * Cum_Inflation]
print(data)
#>    Plan Plan_Period Plan_Elapsed_time year Inflation Cost Cum_Inflation Real_Cost
#> 1:    A           3              0.25 2018     1.012   30      1.002987  30.08960
#> 2:    A           2              1.00 2017     1.012   20      1.015022  20.30045
#> 3:    A           1              0.50 2016     1.014   10      1.022103  10.22103
#> 4:    B           4              0.25 2018     1.020   60      1.004963  60.29778
#> 5:    B           3              0.30 2017     1.080   50      1.028436  51.42179
#> 6:    B           2              0.50 2016     1.012   40      1.034588  41.38352
#> 7:    B           1              1.00 2015     1.013   40      1.048038  41.92150

Optimized version based on comment by @Sathish:

data <- data.frame(
  Plan = c("A","A","A","B","B","B","B"),    
  Plan_Period=c(1,2,3,1,2,3,4),
  Plan_Elapsed_time=c(0.5,1,0.25,1,0.5,0.3,0.25),
  year=c(2016,2017,2018,2015,2016,2017,2018),
  Inflation= c(1.014,1.012,1.012,1.013,1.012, 1.080,1.020),
  Cost= c(10,20,30,40,40,50,60)
)

library(data.table)
setDT(data)[order(Plan, -Plan_Period), real_val := Cost * cumprod( Inflation ^ Plan_Elapsed_time ), by = .(Plan)]
data
#>    Plan Plan_Period Plan_Elapsed_time year Inflation Cost real_val
#> 1:    A           1              0.50 2016     1.014   10 10.22103
#> 2:    A           2              1.00 2017     1.012   20 20.30045
#> 3:    A           3              0.25 2018     1.012   30 30.08960
#> 4:    B           1              1.00 2015     1.013   40 41.92150
#> 5:    B           2              0.50 2016     1.012   40 41.38352
#> 6:    B           3              0.30 2017     1.080   50 51.42179
#> 7:    B           4              0.25 2018     1.020   60 60.29778

Here is a tidyverse solution. I think I understand the logic as explained, which is that the larger plan periods are more recent, and so have fewer terms of inflation ^ plan_elapsed1 to multiply by. Here we arrange to get the rows ordered by plan and then plan_period , and then use cumprod to make the right terms to multiply the cost by.

library(tidyverse)
data <- tibble(
  Plan = c("A","A","A","B","B","B","B"),
  Plan_Period = c(1,2,3,1,2,3,4),
  Plan_Elapsed_time = c(0.5,1,0.25,1,0.5,0.3,0.25),
  year = c(2016,2017,2018,2015,2016,2017,2018),
  Inflation = c(1.014,1.012,1.012,1.013,1.012, 1.080,1.020),
  Cost = c(10,20,30,40,40,50,60)
)

data %>%
  `colnames<-`(str_to_lower(colnames(.))) %>%
  mutate(deflate = inflation ^ plan_elapsed_time) %>%
  group_by(plan) %>%
  arrange(plan, desc(plan_period)) %>%
  mutate(
    cum_deflate = cumprod(deflate),
    real_cost = cost * cum_deflate
    ) %>%
  select(plan:cost, real_cost)
#> # A tibble: 7 x 7
#> # Groups:   plan [2]
#>   plan  plan_period plan_elapsed_time  year inflation  cost real_cost
#>   <chr>       <dbl>             <dbl> <dbl>     <dbl> <dbl>     <dbl>
#> 1 A              3.             0.250 2018.      1.01   30.      30.1
#> 2 A              2.             1.00  2017.      1.01   20.      20.3
#> 3 A              1.             0.500 2016.      1.01   10.      10.2
#> 4 B              4.             0.250 2018.      1.02   60.      60.3
#> 5 B              3.             0.300 2017.      1.08   50.      51.4
#> 6 B              2.             0.500 2016.      1.01   40.      41.4
#> 7 B              1.             1.00  2015.      1.01   40.      41.9

Created on 2018-04-09 by the reprex package (v0.2.0).

Consider by with inner sapply call for running conditional product:

by_list <- by(data, data$Plan, function(sub){      
  sub$RealValue <- sapply(sub$Plan_Period, function(i) 
    sub$Cost[sub$Plan_Period == i] * prod((sub$Inflation[sub$Plan_Period >= i])^(sub$Plan_Elapsed_time[sub$Plan_Period >= i]))
  )      
  return(sub)
})

finaldata <- do.call(rbind, unname(by_list))

finaldata
#   Plan Plan_Period Plan_Elapsed_time year Inflation Cost RealValue
# 1    A           1              0.50 2016     1.014   10  10.22103
# 2    A           2              1.00 2017     1.012   20  20.30045
# 3    A           3              0.25 2018     1.012   30  30.08960
# 4    B           1              1.00 2015     1.013   40  41.92150
# 5    B           2              0.50 2016     1.012   40  41.38352
# 6    B           3              0.30 2017     1.080   50  51.42179
# 7    B           4              0.25 2018     1.020   60  60.29778

Not sure if I misunderstood the question, but it seems fairly straightforward for writing a for-loop for this data.

n<-length(Plan)

for(i in 1:n){
 if (Plan[i]=="A" & Plan_Period[i]==1){
print(10*(1.014^0.5)*(1.012^1)*(0.25^1.012))
}
else if (Plan[i]=="A" & Plan_Period[i]==2){
print(20*(1.012^1)*(0.25^1.012))
}
 else if (Plan[i]=="A" &  Plan_Period[i]==3){
print(30*(1.012^0.25))
} 

else {
print(0)
  }
 }

Hope this is helpful!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM