如何在约束条件下进行累加
How to make an accumulated sum with constraints
我需要对特定日期范围内的值求和,我需要对很多科目执行此操作。
在下一个示例中,df1 包含三个主题的开始和结束日期,df2 包含日期及其对应值:
df1<-data.frame(sub=c("a","b","c"),
start=as.Date(c("2015/10/13","2015/10/13","2015/10/11")),
end=as.Date(c("2015/10/16","2015/10/18","2015/10/15")))
df2<-data.frame(date=seq(as.Date("2015/10/11"), as.Date("2015/10/18"), "days"),
value=c(32,30,28,15,19,23,35,18))
> df1
sub start end
1 a 2015-10-13 2015-10-16
2 b 2015-10-13 2015-10-18
3 c 2015-10-11 2015-10-15
> df2
date value
1 2015-10-11 32
2 2015-10-12 30
3 2015-10-13 28
4 2015-10-14 15
5 2015-10-15 19
6 2015-10-16 23
7 2015-10-17 35
8 2015-10-18 18
我想在 df2 中从 start
日期到 end
date 在 df1 中对 value
求和,我想对每个 sub
进行求和(在实际中问题有很多主题(即成对的开始日期和结束日期),所以我想也许我应该使用 for
循环)。
我期待这样的事情:
sub sum
a 85
b 138
c 124
其中 a = 28+15+19+23,b = 28+15+19+23+35+18 和 c = 32+30+28+15+19
感谢任何帮助
一个选项是 non-equi
加入而不使用任何循环
library(data.table)
setDT(df2)[df1, .(sub = sub, sum = sum(value)),
on = .(date >= start, date <= end), by = .EACHI][, .(sub, sum)]
# sub sum
#1: a 85
#2: b 138
#3: c 124
或者以tidy
的方式使用fuzzyjoin
library(fuzzyjoin)
library(dplyr)
fuzzy_left_join(df2, df1, by = c(date = 'start', date = 'end'),
match_fun = list(`>=`, `<=`)) %>%
group_by(sub) %>%
summarise(value = sum(value))
# A tibble: 3 x 2
# sub value
# <fct> <dbl>
#1 a 85
#2 b 138
#3 c 124
mapply
的一个选项是在 df1
中的 start
和 end
之间创建一个日期序列,并从 df2
中对这些日期进行子集化和 sum
value
.
df1$sum <- mapply(function(x, y) sum(df2$value[df2$date %in% x:y]),
df1$start, df1$end)
df1[c(1, 4)]
# sub sum
#1 a 85
#2 b 138
#3 c 124
这可以在单个 SQL 语句中完成,如下所示:
library(sqldf)
sqldf("select a.sub, sum(b.value) as sum
from df1 as a
left join df2 as b on b.date between a.start and a.end
group by a.sub")
给予:
sub sum
1 a 85
2 b 138
3 c 124
我需要对特定日期范围内的值求和,我需要对很多科目执行此操作。
在下一个示例中,df1 包含三个主题的开始和结束日期,df2 包含日期及其对应值:
df1<-data.frame(sub=c("a","b","c"),
start=as.Date(c("2015/10/13","2015/10/13","2015/10/11")),
end=as.Date(c("2015/10/16","2015/10/18","2015/10/15")))
df2<-data.frame(date=seq(as.Date("2015/10/11"), as.Date("2015/10/18"), "days"),
value=c(32,30,28,15,19,23,35,18))
> df1
sub start end
1 a 2015-10-13 2015-10-16
2 b 2015-10-13 2015-10-18
3 c 2015-10-11 2015-10-15
> df2
date value
1 2015-10-11 32
2 2015-10-12 30
3 2015-10-13 28
4 2015-10-14 15
5 2015-10-15 19
6 2015-10-16 23
7 2015-10-17 35
8 2015-10-18 18
我想在 df2 中从 start
日期到 end
date 在 df1 中对 value
求和,我想对每个 sub
进行求和(在实际中问题有很多主题(即成对的开始日期和结束日期),所以我想也许我应该使用 for
循环)。
我期待这样的事情:
sub sum
a 85
b 138
c 124
其中 a = 28+15+19+23,b = 28+15+19+23+35+18 和 c = 32+30+28+15+19
感谢任何帮助
一个选项是 non-equi
加入而不使用任何循环
library(data.table)
setDT(df2)[df1, .(sub = sub, sum = sum(value)),
on = .(date >= start, date <= end), by = .EACHI][, .(sub, sum)]
# sub sum
#1: a 85
#2: b 138
#3: c 124
或者以tidy
的方式使用fuzzyjoin
library(fuzzyjoin)
library(dplyr)
fuzzy_left_join(df2, df1, by = c(date = 'start', date = 'end'),
match_fun = list(`>=`, `<=`)) %>%
group_by(sub) %>%
summarise(value = sum(value))
# A tibble: 3 x 2
# sub value
# <fct> <dbl>
#1 a 85
#2 b 138
#3 c 124
mapply
的一个选项是在 df1
中的 start
和 end
之间创建一个日期序列,并从 df2
中对这些日期进行子集化和 sum
value
.
df1$sum <- mapply(function(x, y) sum(df2$value[df2$date %in% x:y]),
df1$start, df1$end)
df1[c(1, 4)]
# sub sum
#1 a 85
#2 b 138
#3 c 124
这可以在单个 SQL 语句中完成,如下所示:
library(sqldf)
sqldf("select a.sub, sum(b.value) as sum
from df1 as a
left join df2 as b on b.date between a.start and a.end
group by a.sub")
给予:
sub sum
1 a 85
2 b 138
3 c 124