R具有条件和重置的累积和

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了R具有条件和重置的累积和相关的知识,希望对你有一定的参考价值。

我有一个由-1和1组成的信号位置指示矢量。另外,我有基于Signal的值要求的体积数据。基本数据表如下所示:

df <- cbind(Signal, Volume)
head(df, 20)

           Signal    Volume
2016-01-04     NA  37912403
2016-01-05     -1  23258238
2016-01-06     -1  25096183
2016-01-07     -1  45172906
2016-01-08     -1  35402298
2016-01-11     -1  29932385
2016-01-12     -1  28395390
2016-01-13     -1  33410553
2016-01-14     -1  48658623
2016-01-15      1  46132781
2016-01-19      1  30998256
2016-01-20     -1  59051429
2016-01-21      1  30518939
2016-01-22      1  30495387
2016-01-25      1  32482015
2016-01-26     -1  26877080
2016-01-27     -1  58699359
2016-01-28      1 107475327
2016-01-29      1  62739548
2016-02-01      1  46132726

我想要实现的是(不使用for循环)是产生cum volume的向量,每次Signal变化时都会重置。另外,音量值应该乘以Signal的值,即当Signal为-1时,它应该将-Volume加到当前的暨音量上。基于SO的类似问题,我试过了

ave(df$a, cumsum(c(F, diff(sign(diff(df$a))) != 0)*df$Volume), FUN=seq_along) 

它产生正确的信号分组,但由于某种原因不包括音量。没有重置,解决方案相当简单(在SO上发布)

require(data.table)
DT <- data.table(dt)
DT[, Cum.Sum := cumsum(Volume), by=Signal]

有没有人知道dplyr或data.table类型的解决方案,用于重置和调整累积和?谢谢。

答案

这可以通过以下方式实现:

library(tidyverse)
library(data.table)     

z %>%
  group_by(rleid(Signal)) %>% #advance value every time Signal changes and group by that
  mutate(cum = Signal*cumsum(Volume)) %>% #cumsum in each group
  ungroup() %>% #ungroup so you could remove the grouping column
  select(-4) #remove grouping column

或使用data.table没有rle

z %>%
  mutate(rl = rep(1:length(rle(Signal)$length), times = rle(Signal)$length)) %>%
  group_by(rl) %>%
  mutate(cum = Signal*cumsum(Volume)) %>%
  ungroup() %>%
  select(-4)

#output
    date       Signal    Volume        cum

  <fct>       <int>     <int>      <int>
 1 2016-01-04     NA  37912403         NA
 2 2016-01-05    - 1  23258238 - 23258238
 3 2016-01-06    - 1  25096183 - 48354421
 4 2016-01-07    - 1  45172906 - 93527327
 5 2016-01-08    - 1  35402298 -128929625
 6 2016-01-11    - 1  29932385 -158862010
 7 2016-01-12    - 1  28395390 -187257400
 8 2016-01-13    - 1  33410553 -220667953
 9 2016-01-14    - 1  48658623 -269326576
10 2016-01-15      1  46132781   46132781
11 2016-01-19      1  30998256   77131037
12 2016-01-20    - 1  59051429 - 59051429
13 2016-01-21      1  30518939   30518939
14 2016-01-22      1  30495387   61014326
15 2016-01-25      1  32482015   93496341
16 2016-01-26    - 1  26877080 - 26877080
17 2016-01-27    - 1  58699359 - 85576439
18 2016-01-28      1 107475327  107475327
19 2016-01-29      1  62739548  170214875
20 2016-02-01      1  46132726  216347601

数据:

z <- read.table(text =      "date     Signal    Volume
           2016-01-04     NA  37912403
           2016-01-05     -1  23258238
           2016-01-06     -1  25096183
           2016-01-07     -1  45172906
           2016-01-08     -1  35402298
           2016-01-11     -1  29932385
           2016-01-12     -1  28395390
           2016-01-13     -1  33410553
           2016-01-14     -1  48658623
           2016-01-15      1  46132781
           2016-01-19      1  30998256
           2016-01-20     -1  59051429
           2016-01-21      1  30518939
           2016-01-22      1  30495387
           2016-01-25      1  32482015
           2016-01-26     -1  26877080
           2016-01-27     -1  58699359
           2016-01-28      1 107475327
           2016-01-29      1  62739548
           2016-02-01      1  46132726", header = T)
另一答案

一个纯粹的dplyr方式将是:

df %>% 
  na.omit() %>% # omit NA to not multiply by NA
  mutate(isStep = (Signal - lag(Signal, 1)) != 0) %>% # Create a dummy variable for steps 
  mutate(isStep = ifelse(is.na(isStep), FALSE, isStep)) %>% 
  mutate(grp = cumsum(isStep)) %>% # create new ID based on steps
  group_by(grp) %>%  # group by before created steps
  mutate(res = cumsum(Signal * Volume)) %>% # calculate value
  select(x, Signal, Volume, res)

# # A tibble: 19 x 5
# # Groups:   grp [6]
#      grp          x Signal    Volume        res
#    <int>     <fctr>  <int>     <int>      <int>
#  1     0 2016-01-05     -1  23258238  -23258238
#  2     0 2016-01-06     -1  25096183  -48354421
#  3     0 2016-01-07     -1  45172906  -93527327
#  4     0 2016-01-08     -1  35402298 -128929625
#  5     0 2016-01-11     -1  29932385 -158862010
#  6     0 2016-01-12     -1  28395390 -187257400
#  7     0 2016-01-13     -1  33410553 -220667953
#  8     0 2016-01-14     -1  48658623 -269326576
#  9     1 2016-01-15      1  46132781   46132781
# 10     1 2016-01-19      1  30998256   77131037
# 11     2 2016-01-20     -1  59051429  -59051429
# 12     3 2016-01-21      1  30518939   30518939
# 13     3 2016-01-22      1  30495387   61014326
# 14     3 2016-01-25      1  32482015   93496341
# 15     4 2016-01-26     -1  26877080  -26877080
# 16     4 2016-01-27     -1  58699359  -85576439
# 17     5 2016-01-28      1 107475327  107475327
# 18     5 2016-01-29      1  62739548  170214875
# 19     5 2016-02-01      1  46132726  216347601
另一答案

正如@docendo所建议的,这应该有效:

df[,cum := cumsum(Volume)*Signal,.(rleid(Signal))]

          date Signal    Volume        cum
 1: 2016-01-04     NA  37912403         NA
 2: 2016-01-05     -1  23258238  -23258238
 3: 2016-01-06     -1  25096183  -48354421
 4: 2016-01-07     -1  45172906  -93527327
 5: 2016-01-08     -1  35402298 -128929625
 6: 2016-01-11     -1  29932385 -158862010
 7: 2016-01-12     -1  28395390 -187257400
 8: 2016-01-13     -1  33410553 -220667953
 9: 2016-01-14     -1  48658623 -269326576
10: 2016-01-15      1  46132781   46132781
11: 2016-01-19      1  30998256   77131037

以上是关于R具有条件和重置的累积和的主要内容,如果未能解决你的问题,请参考以下文章

基于条件的累积和,但条件结束后会重置

根据条件重置的 7 天累积总和

R(dplyr)中复位的条件运行计数(累计和)

r 累积和函数,条件

如何在 R 中生成具有累积频率和相对频率的频率表

具有不同分母的除法的累积和 R