2017-01-14 8 views
0

日付と値のデータフレームがあり、正の数値のみの場合は累積、負の場合は累計が必要です。日付は同じ日付を複数回持つことがあり、数日が欠けている(値がない=行がない)日付で指定されたデータフレームの特定の数値の累積合計

最初は累積合計をテストしました。これらは、日付の順に累積的ではなく、あった。

df$cumsum <- cumsum(df$values) 
# or 
df$cumsum <- ave(df$values, FUN=cumsum) 
# Should cumulate by date but did not in right order 
df$cumsum <- cumsum(df[order(df$date, df$values), "values"]) 

は最後に、私は(ない本当に私はデータフレーム中でやってみたかったが、仕事をしていませんよう)望んでいたとして、最初のステップを行い解決策を見つけました

dt <- data.table(df) 
dt[order(date), cumsum := cumsum(values)] 

素晴らしいですが、値> 0をフィルタリングするすべての試みがうまくいかなかった。最後に、データをサブセット化して結果を得ましたが、実際には私が望んでいたものではありません。

df["cumsum_pos"] = df["values"][df["values"] > 0].cumsum() 
df["cumsum_neg"] = df["values"][df["values"] < 0].cumsum() 

/編集

df <- data.frame(date = as.Date(c("2016-12-08", "2016-12-07", "2016-12-05", "2017-01-05", 
            "2017-01-10", "2017-01-11", "2017-01-11")), 
       values = c(10, -10, 5, 5, -7, 8, 8)) 

# just the cumsum 
# expected output = c(5, -5, 5, 10, 3, 11, 19) 

df$cumsum <- cumsum(df$values) 
# output = c(10, 0, 5, 10, 3, 11, 19) 

df$cumsum <- ave(df$values, FUN=cumsum) 
# output = c(10, 0, 5, 10, 3, 11, 19) 

df$cumsum <- cumsum(df[order(df$date, df$values), "values"]) 
# output = c(5, -5, 5, 10, 3, 11, 19) correct in this example 
# doesn't work with dates in a different order 2016-12-31, 2016-12-30, ... 2015-12-31, 2015-12-30 

# Now for just the positives 
# expected output = c(10, 0, 5, 15, 15, 23, 31) 
df$cumsum.pos[df$values > 0] <- cumsum(df[order(df$date, df$values), "values"][df$values > 0]) 
# output = c(5, NA, 15, 20, NA, 28, 36) 

# And then the same with just the negatives 

/編集

ニコラス:

dt.pos <- data.table(subset(df, values> 0)) 
dt.pos[order(date), cumsum := cumsum(values)] 

dt.neg <- data.table(subset(df, values < 0)) 
dt.neg[order(date), cumsum := cumsum(values)] 

私は(注文したデータフレーム付き)Pythonの同等のような単純なものを探していますコメントで正しい出力が得られない

df<-df[order(df$date),] 
# values = c(5, -10, 10, 5, -7, 8, 8) 
# expected output = c(5, 5, 15, 20, 20, 28, 36) 
df$cumsum<-ave(df$values,df$values>0,FUN=cumsum) 
# output = c(5, -10, 15, 20, -17, 28, 36) 
+1

小さな再現可能な例を示してくださいと予想される出力 – akrun

+1

まず順あなたdata.frame: 'DF <-df [オーダー(DFの$日付)、]' 'そしてave'を使用:df $ cumsum <-ave(df $ value、df $ value> 0、FUN = cumsum) ' – nicola

+0

残念ながら、それはネガも追加しているので、それは正しい方向への一歩ですが、私は思っています。 – sezi80

答えて

1

これは使用できます。

library(data.table) 
df <- as.data.table(df) 

# Order by date 
df <- df[order(date)] 

# Perform the cumsum for positives and negatives separately 
df[, expected := cumsum(values), by = sign(values)] 

# Just for the negatives, get the previous positive value 
df[, expected := ifelse(values > 0, expected, c(0, expected[-.N]))] 

print(df) 

     date values expected 
1: 2016-12-05  5  5 
2: 2016-12-07 -10  5 
3: 2016-12-08  10  15 
4: 2017-01-05  5  20 
5: 2017-01-10  -7  20 
6: 2017-01-11  8  28 
7: 2017-01-11  8  36 

連続する負の値が複数ある場合は、操作を繰り返す必要があります。例えば、データフレームは、このいずれかの場合:上記のコードの

df <- data.frame(date = as.Date(c("2016-12-08", "2016-12-07", "2016-12-05", "2017-01-05","2017-01-10", "2017-01-10", "2017-01-11", "2017-01-11")), 
values = c(10, -10, 5, 5, -7, -15, 8, 8)) 

一つの単一の実行には、次の出力を生成します:

  date values expected 
1: 2016-12-05  5  5 
2: 2016-12-07 -10  5 
3: 2016-12-08  10  15 
4: 2017-01-05  5  20 
5: 2017-01-10  -7  20 
6: 2017-01-10 -15  -17 
7: 2017-01-11  8  28 
8: 2017-01-11  8  36 

値-17間違っているだろう。この問題を回避するには、負の値が残らなくなるまでプロセスを繰り返すことができます。だから、完全なコードは次のようになります。

df <- df[order(date)] 
df[, expected := cumsum(values), by = sign(values)] 

# If there are negative values, repeat the process 
while(length(which(df$expected < 0))){ 
    df[, expected := ifelse(values > 0, expected, c(0, expected[-.N]))] 
} 

print(df) 
     date values expected 
1: 2016-12-05  5  5 
2: 2016-12-07 -10  5 
3: 2016-12-08  10  15 
4: 2017-01-05  5  20 
5: 2017-01-10  -7  20 
6: 2017-01-10 -15  20 
7: 2017-01-11  8  28 
8: 2017-01-11  8  36 
+0

あなたの努力に感謝します。しかし、これはすでに私が解決策を与えた最初の部分に過ぎませんでした。私は肯定的な価値のためにcumsumが必要です。 – sezi80

+0

@ sezi80申し訳ありませんが、私は質問を理解していませんでした。私は答えを更新しました、それは陽性と陰性のためのcumsumを別々に計算します。これはあなたの期待される成果ですか? –

+0

私の最初の投稿は十分に記述的ではないようです。私は肯定的なcumsumを望んでいるので、 'geom_line()'はまっすぐに行くでしょう。データをサブセット化せずに。 '期待される出力= c(5,5,15,20,20,28,36)' – sezi80

関連する問題