如何创建一个函数和一个循环来计算 R 中数据框中变量的增长率

How to create a function and a loop to calculate growth rates of variables in a data frame in R

R 和 Stack Overflow 的新手。假设我将以下宏观经济数据加载到 R 中名为 testdata 的数据框中。

> testdata
      date    gdp cpi_index rpi_index
21 2013 Q1 409985   125.067     247.4
22 2013 Q2 412620   125.971     249.7
23 2013 Q3 415577   126.352     250.9
24 2013 Q4 417265   127.123     252.5
25 2014 Q1 420091   127.241     253.9
26 2014 Q2 423249   128.139     256.0
27 2014 Q3 426022   128.191     256.9
28 2014 Q4 428347   128.312     257.4

我想生成一个名为 testdata_growth 的新数据,其中包含测试数据中宏变量的 q-o-q 增长率。目前我的处理方式如下:

# Generating q-o-q growth rates
gdp_growth <- c(NA, diff(testdata$gdp)/ testdata$gdp[-1])
rpi_index_growth <- c(NA, diff(testdata$rpi_index)/ testdata$rpi_index[-1])
cpi_index_growth <- c(NA, diff(testdata$cpi_index)/ testdata$cpi_index[-1])

# Combining growth rates into a new data frame
testdata_growth <- data.frame(testdata$date, gdp_growth, rpi_index_growth, cpi_index_growth)

我的问题是如何将上述代码编写成一个循环,以便我可以更快地生成具有增长率的新数据框(因为我有数十个宏观经济变量需要应用此增长率计算) .

如有任何帮助,我们将不胜感激。

谢谢!

(此外,如果您对如何改进我的问题有任何意见,下次我 post 进入 Stack Overflow 时,我会考虑这些 - 非常感谢!)

编辑:在下面添加了 dput(testdata)

    > dput(testdata)
structure(list(date = structure(21:28, .Label = c("2008 Q1", 
"2008 Q2", "2008 Q3", "2008 Q4", "2009 Q1", "2009 Q2", "2009 Q3", 
"2009 Q4", "2010 Q1", "2010 Q2", "2010 Q3", "2010 Q4", "2011 Q1", 
"2011 Q2", "2011 Q3", "2011 Q4", "2012 Q1", "2012 Q2", "2012 Q3", 
"2012 Q4", "2013 Q1", "2013 Q2", "2013 Q3", "2013 Q4", "2014 Q1", 
"2014 Q2", "2014 Q3", "2014 Q4"), class = "factor"), gdp = c(409985L, 
412620L, 415577L, 417265L, 420091L, 423249L, 426022L, 428347L
), cpi_index = c(125.067, 125.971, 126.352, 127.123, 127.241, 
128.139, 128.191, 128.312), rpi_index = c(247.4, 249.7, 250.9, 
252.5, 253.9, 256, 256.9, 257.4)), .Names = c("date", "gdp", 
"cpi_index", "rpi_index"), row.names = 21:28, class = "data.frame")
library(dplyr)

testdata %>%
  select(-date) %>%
  mutate_each(funs(. / lag(.) - 1))

#           gdp    cpi_index   rpi_index
# 1          NA           NA          NA
# 2 0.006427064 0.0072281257 0.009296686
# 3 0.007166400 0.0030245056 0.004805767
# 4 0.004061822 0.0061020008 0.006377043
# 5 0.006772674 0.0009282349 0.005544554
# 6 0.007517419 0.0070574736 0.008270973
# 7 0.006551699 0.0004058093 0.003515625
# 8 0.005457465 0.0009439040 0.001946283

忍不住...

library(dplyr)
library(tidyr)
library(ggplot2)
library(scales)

testdata %>%
  select(-date) %>%
  mutate_each(funs(. / lag(.) - 1)) %>%
  bind_cols(testdata[1], .) %>%
  gather(index, value, -date) %>% 
  ggplot(., aes(x = date, y = value, 
                color = factor(index), 
                group = factor(index))) + 
    geom_line() +
    scale_y_continuous(labels = percent)

您也可以使用 data.table。 data.table 是一个非常强大的数据操作包。您可以开始 here.

library("data.table")
as.data.table(testdata)[, lapply(.SD, function(x)x/shift(x) - 1), .SDcols = 2:4]


           gdp    cpi_index   rpi_index
1:          NA           NA          NA
2: 0.006427064 0.0072281257 0.009296686
3: 0.007166400 0.0030245056 0.004805767
4: 0.004061822 0.0061020008 0.006377043
5: 0.006772674 0.0009282349 0.005544554
6: 0.007517419 0.0070574736 0.008270973
7: 0.006551699 0.0004058093 0.003515625
8: 0.005457465 0.0009439040 0.001946283

您可以根据 logged 值的 diff结果计算它。

cbind(testdata[1],sapply(testdata[-1], function(x) c(0,exp(diff(log(x)))-1)))
      date         gdp    cpi_index   rpi_index
21 2013 Q1 0.000000000 0.0000000000 0.000000000
22 2013 Q2 0.006427064 0.0072281257 0.009296686
23 2013 Q3 0.007166400 0.0030245056 0.004805767
24 2013 Q4 0.004061822 0.0061020008 0.006377043
25 2014 Q1 0.006772674 0.0009282349 0.005544554
26 2014 Q2 0.007517419 0.0070574736 0.008270973
27 2014 Q3 0.006551699 0.0004058093 0.003515625
28 2014 Q4 0.005457465 0.0009439040 0.001946283

一种 data.table 解决方案,通过循环将增长列直接添加到数据集,使用在循环中创建的新列名称 (column_growth)。

list.of.columns = 您想要增长率的列的名称。

如果您不想按组计算费率,请删除 , by=group_ID

library(data.table)

for (col in list.of.columns){
  
  growth.col.name = paste0(col, '_growth')
  
  df[,eval(growth.col.name):= get(col)/shift(get(col)) - 1, by=group_ID]
  
}