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

时间:2018-03-01 13:37:22

标签: r sum dplyr data.table conditional

我有一个由-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类型的解决方案,用于重置和调整累积和?感谢。

3 个答案:

答案 0 :(得分:3)

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

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)

答案 1 :(得分:2)

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

答案 2 :(得分:0)

根据@docendo的建议,这应该有效:

String nomTable;

DataTable ListeEtablissementTable = new DataTable();
DataTable ListeInteretsTable = new DataTable();
DataSet ds = new DataSet();
SqlDataAdapter da;
SqlCommandBuilder cmdb;

private void listeInterets_Click(object sender, EventArgs e)
{
    nomTable = "ListeInteretsTable";
    d.cnx.Open();
    da = new SqlDataAdapter("select Nome from Offices", d.cnx);
    ds = new DataSet();
    da.Fill(ds, nomTable);
    dataGridView1.DataSource = ds.Tables[nomTable];
}

private void Sauvgarder_Click(object sender, EventArgs e)
{
    d.cnx.Open();
    cmdb = new SqlCommandBuilder(da);
    da.Update(ds, nomTable);
    d.cnx.Close();
}