【问题标题】:R: Recursively add rowsR:递归添加行
【发布时间】:2021-09-14 06:19:11
【问题描述】:

j 表面接触后手的细菌浓度可以由以下递归关系决定:

H[j+1]=H[j]+T[j]*(S[j]-H[j])

其中S 是手接触的表面浓度(为方便起见,假设是随机的)。 T 是每个联系人的传输效率。我想计算最终的手牌浓度(起始浓度为零)。

我有一个数据框,其中包含一个表面接触向量和每个表面的传输效率。我有两个组ab 并且在每个组中假设我将依次触摸每个组1:length(df)

 df <- data.frame(S = runif(10)*100, T = runif(10),g=rep(c("a","b"),each=5))

我想尽可能使用dplyr 按组计算H 的累积总和。

一种特殊情况:

如果g = "a",则H的起始值为0。 如果g=="b"H 的起始值是g=="a" 时的最后一个值

【问题讨论】:

  • 不清楚H在你的数据集中是什么。所以我认为如果你稍微修改一下你的问题会更好。
  • 到目前为止,您尝试了哪些没有奏效的方法?目前尚不清楚您的代码将如何与方程式相关联,以及尝试实现它可能会出现什么问题
  • 非常好的问题!

标签: r dplyr purrr rolling-computation accumulate


【解决方案1】:

这是我将用于这个问题的另一个通用版本:

df$H <- Reduce(function(x, y) {
  x + df$T[y] * (df$g[y] == df$g[y + 1]) * (df$S[y] - x) 
}, init = 0,
seq_len(nrow(df))[-nrow(df)], accumulate = TRUE)

df

           S         T g        H
1  37.698250 0.8550377 a  0.00000
2   3.843585 0.4722659 a 32.23342
3  33.150788 0.3684791 a 18.82587
4   8.948116 0.8893603 a 24.10430
5  57.061844 0.5452377 a 10.62499
6  49.648827 0.7719067 b 10.62499
7  95.403697 0.5835950 b 40.74775
8  10.598677 0.1220491 b 72.64469
9  91.913365 0.2166443 b 65.07203
10 69.644200 0.2603413 b 70.88705

【讨论】:

  • 所以,如果我理解,那么.init 应该只取最后一次迭代的值。那么,你的代码就好了。
  • 这不是和Anil用的那个看起来更紧凑的相似吗
  • 试试df %&gt;% mutate(nr = rowid(g)) %&gt;% pivot_wider(names_from = g, values_from = c(S, T)) %&gt;% mutate(H_a = unlist(accumulate2(S_a[-n()], T_a[-n()], .init = 0, ~ ..1 + ..3 * (..2 - ..1))), H_b = unlist(accumulate2(S_b[-n()], T_b[-n()], .init = last(H_a), ~ ..1 + ..3 * (..2 - ..1)))) %&gt;% pivot_longer(cols = -nr, names_to = c(".value", "g"), names_sep="_") %&gt;% arrange(g) %&gt;% select(-nr)
  • @akrun 终于修改了我的! :)
  • 非常感谢您对此的帮助,非常感谢。我想接受 akrun 的回答,因为它是通用版本。我意识到我没有在问题中明确说明这一点。
【解决方案2】:

为了完整起见并从 Arun 和 Onyambu 那里获取线索(关于一个单独的问题),我也在此处添加了 baseR 答案。

transform(df, H = Reduce(function(.x, .y) .x + df$T[.y] * (df$S[.y] - .x) * !c(!duplicated(df$g)[-1], 0)[.y],
                         seq(nrow(df)),
                         init = 0,
                         accumulate = TRUE)[-(1 + nrow(df))])

           S         T g        H
1  37.698250 0.8550377 a  0.00000
2   3.843585 0.4722659 a 32.23342
3  33.150788 0.3684791 a 18.82587
4   8.948116 0.8893603 a 24.10430
5  57.061844 0.5452377 a 10.62499
6  49.648827 0.7719067 b 10.62499
7  95.403697 0.5835950 b 40.74775
8  10.598677 0.1220491 b 72.64469
9  91.913365 0.2166443 b 65.07203
10 69.644200 0.2603413 b 70.88705

较早的答案 上面我朋友的回答略有不同,我希望这可以达到您的目的。我唯一的假设是您的数据已经按组排序并且ab 之前(完全如示例中所示)。既然你没有给随机种子,我也拿了我朋友拿的同样的数据。

  • 策略/hack,我在accumulate2 参数中使用了0T 值,以便H 在组a 中的最后一个值在组b 的第一个值中重复
library(tidyverse)

df <- read.table(header = TRUE, text = '           S         T g
1  37.698250 0.8550377 a
2   3.843585 0.4722659 a
3  33.150788 0.3684791 a
4   8.948116 0.8893603 a
5  57.061844 0.5452377 a
6  49.648827 0.7719067 b
7  95.403697 0.5835950 b
8  10.598677 0.1220491 b
9  91.913365 0.2166443 b
10 69.644200 0.2603413 b')

df %>%
  mutate(H = accumulate2(S, replace(T, length(g[g=='a']), 0), .init = 0, ~ ..1 + ..3 * (..2 - ..1))[-(1+n())])


           S         T g        H
1  37.698250 0.8550377 a  0.00000
2   3.843585 0.4722659 a 32.23342
3  33.150788 0.3684791 a 18.82587
4   8.948116 0.8893603 a 24.10430
5  57.061844 0.5452377 a 10.62499
6  49.648827 0.7719067 b 10.62499
7  95.403697 0.5835950 b 40.74775
8  10.598677 0.1220491 b 72.64469
9  91.913365 0.2166443 b 65.07203
10 69.644200 0.2603413 b 70.88705

#check - formula
#H[j+1]=H[j]+T[j]*(S[j]-H[j])
# for j =2
# H[2] = H[1] + T[1] * (S[1] -H[1])

0 + 0.8550377 * (37.698250 - 0)
#> [1] 32.23342

#for j=7 (second row group b)

#H[6] + T[6] * (S[6] - H[6])
10.62499 + 0.7719067 * (49.648827 - 10.62499)
#> [1] 40.74775

reprex package (v2.0.0) 于 2021-07-10 创建

【讨论】:

  • 非常感谢阿尼尔介绍accumulate2。我以前没有见过这个,我认为它现在很快就会成为我工作流程的一部分。我愿意接受 Akrun 的回答,因为它是 g 可以有任意长度的通用解决方案。
  • @HCAI,他很容易概括它,而我花了一段时间才弄清楚如何去做。他的策略无疑是最好的。 :)
  • 我想在堆栈允许时为您提供赏金。感谢您的所有帮助!
  • @HCAI,为那里的一个小错误编辑了较早的答案(以前我剪裁倒数第二个值而不是预期的最后一个值)。另外,我还添加了一个 BaseR 策略来处理 accumulate/Reduce 家庭中的多个输入案例,这是我从我的朋友 Anoushiravan 和 Onyambu 那里学到的
【解决方案3】:

这是@AnilGoyal 为一般案例展示的类似方法

library(dplyr)
library(purrr)
df %>%
    mutate(H = accumulate2(S, T* !lead(!duplicated(g), default = FALSE),
          .init = 0, ~ ..1 + ..3 * (..2 - ..1))[-n()])

【讨论】:

  • 你们用黑魔法解决了这个问题,而我是一个简单的凡人:)
猜你喜欢
  • 2015-02-01
  • 1970-01-01
  • 2011-11-03
  • 2021-03-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多