【问题标题】:Iterative Calculations using dplyr使用 dplyr 进行迭代计算
【发布时间】:2018-02-11 09:40:53
【问题描述】:

我想知道使用dplyr 是否可以进行以下计算。

x <- data.frame(
  yr = c(2012, 2013, 2014, 2015, 2016),
  rate = c(1.1, 1.2, 0.8, -0.4, 0.5)
) %>% arrange(desc(yr))

这就是我想要计算 y 的方式:

y[i] = ifelse(yr == max(yr), 100,
    100 * y[i-1]/(100 + rate[i-1]))

如果我尝试这样的事情:

x %>%
  mutate(
    y = ifelse(
      yr == max(yr), 100,
      100 * lag(y) / (100 + lag(rate)) 
    )
  )

它返回以下错误:Evaluation error: object 'y' not found.

如标题所示,我想要一个管道内的 dplyr 解决方案,而不使用像 zoodata.table 这样的包,主要是因为它在不同数据库中的 SQL 可翻译性。
这可能吗?

【问题讨论】:

  • ifelse 中,'y' 尚未创建。如果'y'的值应该基于之前的值,那么你可能需要accumulate。不清楚accumulate能否翻译
  • 我确实理解了错误消息,但不清楚如何解决这个问题。你说得对 - 很遗憾,accumulate 似乎没有翻译。

标签: r dplyr iteration


【解决方案1】:

像这样尝试cumprod

x %>% mutate(y = 100 * cumprod(100 / (100 + lag(rate, default = 0))))

给予:

    yr rate         y
1 2016  0.5 100.00000
2 2015 -0.4  99.50249
3 2014  0.8  99.90210
4 2013  1.2  99.10922
5 2012  1.1  97.93401

关于数据库,我怀疑 dplyr 可以做到这一点,但您可以直接对数据库使用 sql。这是使用带有 sqlite 后端的 sqldf 的示例。相同的代码也适用于 H2 数据库后端。

library(sqldf)

sqldf("select a.yr, a.rate, 100 * coalesce(exp(sum(log(100/(100 + b.rate)))), 1) y 
      from x a left join x b on a.yr < b.yr group by a.yr 
      order by a.yr desc")

给予:

    yr rate         y
1 2016  0.5 100.00000
2 2015 -0.4  99.50249
3 2014  0.8  99.90210
4 2013  1.2  99.10922
5 2012  1.1  97.93401

【讨论】:

  • 我无法在 Postgres DB 中正确执行 cumprod 或 sql 语句...您能解释一下您是如何获得 y 的函数的吗?尽管如此,cumprod 在 Spark 中的作用就像一个魅力。谢谢!
  • @g-grothendieck & 当我询问 y 的函数时,我的意思是 [100 * coalesce(exp(sum(log(100/(100 + b.rate)))), 1)]。
  • sqlite 没有 prod 的聚合函数,但 exp(sum(log(...))sum 转换为它。 coalesce 返回其第一个非空参数。
  • 我对@9​​87654333@ 感到特别困惑,但感谢您的解释:)
【解决方案2】:

一个选项是使用来自purrraccumulate

library(tidyverse)
x %>%
   mutate(y = accumulate(rate[-n()], 
              ~  100 * .x/(100 + .y), 
                 .init = 100))
#   yr rate         y
#1 2016  0.5 100.00000 
#2 2015 -0.4  99.50249
#3 2014  0.8  99.90210
#4 2013  1.2  99.10922
#5 2012  1.1  97.93401

也可以在base RReduce 中完成

Reduce(function(u, v) 100 * u/(100 + v) , x$rate[-nrow(x)],init = 100, accumulate = TRUE)
#[1] 100.00000  99.50249  99.90210  99.10922  97.93401

根据 OP 的逻辑,第一个元素被初始化为 100

>  100 * (100)/(100 + 0.5)  # 2nd element
[1] 99.50249
>  100 * 99.50249/(100 - 0.4) # 3rd element
[1] 99.9021
>  100 * 99.9021/(100 + 0.8) # 4th element
[1] 99.10923
>  100 * 99.10923/(100 + 1.2) # 5th element
[1] 97.93402

【讨论】:

  • 我喜欢使用purrr::accumulate,因为它允许我们使用管道,但它似乎只适用于 R 对象。对此感到抱歉,应该通过创建本地 Postgres 数据库来创建更好的可重现代码。不过感谢您的帮助!
  • @creativename 没问题。很高兴能帮助你。我没有在 Postgres 上测试它。对此感到抱歉
【解决方案3】:

另一种选择是使用for 循环

library(dplyr)

#initialize column "y"
x$y <- NA

#process one row at a time
for (i in seq(nrow(x))) {
  x[i,] <- (x[seq(i),] %>%
              mutate(y = ifelse(yr==max(yr), 100, 100 * lag(y) / (100 + lag(rate)))))[i,]
}
x

输出是:

    yr rate         y
1 2016  0.5 100.00000
2 2015 -0.4  99.50249
3 2014  0.8  99.90210
4 2013  1.2  99.10922
5 2012  1.1  97.93401

样本数据:

x <- structure(list(yr = c(2016, 2015, 2014, 2013, 2012), rate = c(0.5, 
-0.4, 0.8, 1.2, 1.1)), class = "data.frame", row.names = c(NA, 
-5L), .Names = c("yr", "rate"))

【讨论】:

  • 感谢您的回答。如果 x 是 Postgres 的表,我无法做到这一点,但我同意这可能是任何其他 R 对象的解决方案。
  • @creativename 哦,我明白了。很高兴你找到了答案。干杯!
猜你喜欢
  • 2016-12-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-12-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多