使用前一行数值的滚动函数 [R]

huangapple go评论54阅读模式
英文:

rolling function using previous row values [R]

问题

我明白你的需求,你需要翻译代码和相关注释,但不需要翻译其他部分。以下是代码和注释的中文翻译:

# 我有一些地点(`a,b,c`),土壤具有一定的最大容量(`100,200`)。对于每个时间段(数据集中的每一行),我已经计算了水含量的变化(`change`)。

# 设置随机种子
set.seed(2023)
db <- data.table(ID=c(rep("a",3),rep("b",3),rep("c",3)),
                 capacity=c(rep(100,3),rep(200,6)),
                 prc=round(runif(9,1,100),0),
                 evpt=round(runif(9,1,100),0))

# 计算水含量的变化
db[prc>=evpt, change := prc - evpt]
db[prc<evpt, change := exp(-((evpt - prc) / capacity))]

# 在时间0时,地点存储最大的`capacity`水量。然后,如果`prc` > `evpt`,`change`是添加到先前含量的水,但不超过最大容量。如果`prc` < `evpt`,`change`是先前水含量的乘数,从而减少含量。

# 草稿函数
new_content <- function(change, capacity, prc, evpt) {
  if (prc > evpt) {
    min(change + previous_content, capacity)
  } else {
    previous_content * change
  }
}

# 然后,我应该应用该函数到每个地点,以获得一个新列(`content`),显示水含量的时间变化。如下面在Excel中计算的输出:

# 输出
# > db
#    ID capacity prc evpt     change  content
# 1:  a      100  39   20 19.0000000 100.0000
# 2:  a      100  74   35 39.0000000 100.0000
# 3:  a      100  67   19 48.0000000 100.0000
# 4:  b      200  49   78  0.8650223 173.0045
# 5:  b      200  41   70  0.8650223 149.6527
# 6:  b      200  94   75 19.0000000 168.6527
# 7:  c      200  74   51 23.0000000 200.0000
# 8:  c      200  67   71  0.9801987 196.0397
# 9:  c      200  77   73  4.0000000 200.0000

# 我无法解决的问题是如何定义变量`previous_content`,即一开始等于最大容量,然后等于前一行的内容。

# 我查阅了`data.table::frollapply`和`zoo:rollapply`的文档,但甚至无法为此起草一个初步的草稿。有什么帮助吗?谢谢!

希望这能满足你的需求。如果你有其他问题,请随时提出。

英文:

I have some sites (a,b,c) where the soil has a certain maximum capacity (100,200). For each period of time (every row in my dataset), I have calculated the change in water content (change).

set.seed(2023)
db &lt;- data.table(ID=c(rep(&quot;a&quot;,3),rep(&quot;b&quot;,3),rep(&quot;c&quot;,3)),
                 capacity=c(rep(100,3),rep(200,6)),
                 prc=round(runif(9,1,100),0),
                 evpt=round(runif(9,1,100),0))

db[prc&gt;=evpt,change:=prc-evpt]
db[prc&lt;evpt,change:=exp(-((evpt-prc)/capacity))]


   ID capacity prc evpt     change
1:  a      100  39   20 19.0000000
2:  a      100  74   35 39.0000000
3:  a      100  67   19 48.0000000
4:  b      200  49   78  0.8650223
5:  b      200  41   70  0.8650223
6:  b      200  94   75 19.0000000
7:  c      200  74   51 23.0000000
8:  c      200  67   71  0.9801987
9:  c      200  77   73  4.0000000

At time 0 the site hold the maximum capacity of water. Then, if prc >evpt, change is the water added to the previous content, without exceeding the maximum capacity. If prc < evpt, change is a multiplier of the previous water content, thus reducing the content.

# draft function
new_content &lt;- function(change,capacity,prc,evpt){
  if (prc&gt;evpt) {
    min(change+previous_content,capacity)
    } else {
      previous_content*change
    }
}

Then I should apply the function for each site to get a new column (content) showing the temporal variation of water content. As in the following output calculated in Excel:

&gt; db
   ID capacity prc evpt     change  content
1:  a      100  39   20 19.0000000 100.0000
2:  a      100  74   35 39.0000000 100.0000
3:  a      100  67   19 48.0000000 100.0000
4:  b      200  49   78  0.8650223 173.0045
5:  b      200  41   70  0.8650223 149.6527
6:  b      200  94   75 19.0000000 168.6527
7:  c      200  74   51 23.0000000 200.0000
8:  c      200  67   71  0.9801987 196.0397
9:  c      200  77   73  4.0000000 200.0000

The problem I cannot solve is how to define the variable previous_content, i.e. at the beginning equal to the maximum capacity and then to the content of the previous row.

I checked the documentation of both data.table::frollapply and zoo:rollapply but I was not able even to write a starting draft for that. Any help? Thanks!

答案1

得分: 1

Assuming the input shown in the Note at the end content2 generated using Reduce is the same as content:

db[, content2 := Reduce(function(x, i) with(.SD[i, ], {
    if (prc &gt; evpt) min(change+x, capacity)
    else x * change
  }), 1:.N, init = capacity[1], acc = TRUE)[-1], by = ID]

db
##    ID capacity prc evpt     change  content content2
## 1:  a      100  39   20 19.0000000 100.0000 100.0000
## 2:  a      100  74   35 39.0000000 100.0000 100.0000
## 3:  a      100  67   19 48.0000000 100.0000 100.0000
## 4:  b      200  49   78  0.8650223 173.0045 173.0045
## 5:  b      200  41   70  0.8650223 149.6527 149.6527
## 6:  b      200  94   75 19.0000000 168.6527 168.6527
## 7:  c      200  74   51 23.0000000 200.0000 200.0000
## 8:  c      200  67   71  0.9801987 196.0397 196.0397
## 9:  c      200  77   73  4.0000000 200.0000 200.0000

In the example in the question capacity is always constant within ID, and change is multiplied if it is <= 1 and added otherwise. If those are true generally, we can simplify the above:

db[, content3 := Reduce(function(x, change) 
      if (change &gt; 1) min(change + x, capacity[1]) else x * change, 
      change, init = capacity[1], acc = TRUE)[-1], 
    by = ID]

Note

library(data.table)

Lines &lt;-  "ID capacity prc evpt     change  content
a      100  39   20 19.0000000 100.0000
a      100  74   35 39.0000000 100.0000
a      100  67   19 48.0000000 100.0000
b      200  49   78  0.8650223 173.0045
b      200  41   70  0.8650223 149.6527
b      200  94   75 19.0000000 168.6527
c      200  74   51 23.0000000 200.0000
c      200  67   71  0.9801987 196.0397
c      200  77   73  4.0000000 200.0000"
db &lt;- fread(Lines)
英文:

Assuming the input shown in the Note at the end content2 generated using Reduce is the same as content:

db[, content2 := Reduce(function(x, i) with(.SD[i, ], {
    if (prc &gt; evpt) min(change+x, capacity)
    else x * change
  }), 1:.N, init = capacity[1], acc = TRUE)[-1], by = ID]

db
##    ID capacity prc evpt     change  content content2
## 1:  a      100  39   20 19.0000000 100.0000 100.0000
## 2:  a      100  74   35 39.0000000 100.0000 100.0000
## 3:  a      100  67   19 48.0000000 100.0000 100.0000
## 4:  b      200  49   78  0.8650223 173.0045 173.0045
## 5:  b      200  41   70  0.8650223 149.6527 149.6527
## 6:  b      200  94   75 19.0000000 168.6527 168.6527
## 7:  c      200  74   51 23.0000000 200.0000 200.0000
## 8:  c      200  67   71  0.9801987 196.0397 196.0397
## 9:  c      200  77   73  4.0000000 200.0000 200.0000

In the example in the question capacity is always constant within ID and change is multiplied if it is <= 1 and added otherwise. If those are true generally we can simplify the above:

db[, content3 := Reduce(function(x, change) 
      if (change &gt; 1) min(change + x, capacity[1]) else x * change, 
      change, init = capacity[1], acc = TRUE)[-1], 
    by = ID]

Note

library(data.table)

Lines &lt;-  &quot;ID capacity prc evpt     change  content
a      100  39   20 19.0000000 100.0000
a      100  74   35 39.0000000 100.0000
a      100  67   19 48.0000000 100.0000
b      200  49   78  0.8650223 173.0045
b      200  41   70  0.8650223 149.6527
b      200  94   75 19.0000000 168.6527
c      200  74   51 23.0000000 200.0000
c      200  67   71  0.9801987 196.0397
c      200  77   73  4.0000000 200.0000&quot;
db &lt;- fread(Lines)

huangapple
  • 本文由 发表于 2023年4月6日 19:45:37
  • 转载请务必保留本文链接:https://go.coder-hub.com/75949148.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定