计算特定范围内多个重叠事件的最大值
Calculate largest value for multiple overlapping events in a specific range
我有多个大型数据框来捕获持续一定时间的事件。这个例子给出了我的数据集的简化版本
数据框 1:
ID Days Date Value
1 10 80 30
1 10 85 30
2 20 75 20
2 10 80 20
3 5 90 30
数据框 2:
ID Days Date Value
1 20 0 30
1 10 3 20
2 20 5 30
3 20 1 10
3 10 10 10
同一个ID
用于所有数据集中的同一个人
Days
指定事件的长度(如果 Days
的值为 10,则事件持续 10 天)
Date
指定事件开始的日期。在这种情况下,Date
可以是 0 到 90 或 91 之间的任何数字(数据代表季度中的天数)
Value
是重复指定的 Days
次的属性。例如,对于 df1 中的第一行,值 30
从第 80 天开始重复 10 次( 30 重复 10 天)
我感兴趣的是为每个数据框中的每个 ID
赋予每天的最高值。请记住,多个事件可以重叠,然后必须对值进行求和。
最终数据框应如下所示:
ID HighestValuedf1 HighestValuedf2
1 60 80
2 40 30
3 30 20
例如,对于ID
1,三个事件重叠,导致数据框2中的最高值为80。对于ID
3,df1和df1的事件之间没有重叠,仅与 df2.[=25=] 重叠
由于文件的大小,我更喜欢一种避免将所有数据帧合并到一个数据帧中的解决方案。
编辑
我重新排列了我的数据,以便所有重叠的事件都在一个数据框中。我只需要每个数据帧的最高重叠值。
重现数据帧的代码:
ID = c(1,1,2,2,3)
Date = c(80,85,75,80,90)
Days = c(10,10,20,10,5)
Value = c(30,30,20,20,30)
df1 = data.frame(ID,Days, Date,Value)
ID = c(1,1,2,3,3)
Date = c(1,3,5,1,10)
Days = c(20,10,20,20,10 )
Value =c(30,20,30,10,10)
df2 = data.frame(ID,Days, Date,Value)
ID= c(1,2,3)
HighestValuedf1 = c(60,40,30)
HighestValuedf2 = c(80,30,20)
df3 = data.frame(ID, HighestValuedf1, HighestValuedf2)
我将每天的最高值解释为整个时间段内单日的最高值。这可能不是最有效的解决方案,因为我希望可以使用 map
或 apply
函数来完成某些事情,但我第一眼看不到如何做。使用上面定义的 df1
和 df2
:
编辑:在理解 df1 和 df2 应该代表连续的季度后修改代码。我认为最简单的方法是简单地堆叠数据帧,以便自动捕获任何重叠的内容(即 df2 的第 1 天是第 91 天)。由于季度的长度不同,您可能需要手动调整此代码,或者最好将季度的天数转换为具有日期格式的一年中的实际日期(例如,df1 第 1 天变为 2017 年 1 月 1 日)。下面的代码只是重新排列以实现此目的,然后通过在 1:90、91:180 天进行过滤来生成每个季度所需的结果,如图所示)
ID = c(1,1,2,2,3)
Date = c(80,85,75,80,90)
Days = c(10,10,20,10,5)
Value = c(30,30,20,20,30)
df1 = data.frame(ID,Days, Date,Value)
ID = c(1,1,2,3,3)
Date = c(1,3,5,1,10)
Days = c(20,10,20,20,10 )
Value =c(30,20,30,10,10)
df2 = data.frame(ID,Days, Date,Value)
library(tidyverse)
#> -- Attaching packages --------------------------------------------------------------------- tidyverse 1.2.1 --
#> v ggplot2 2.2.1.9000 v purrr 0.2.4
#> v tibble 1.4.2 v dplyr 0.7.4
#> v tidyr 0.7.2 v stringr 1.2.0
#> v readr 1.1.1 v forcats 0.2.0
#> -- Conflicts ------------------------------------------------------------------------ tidyverse_conflicts() --
#> x dplyr::filter() masks stats::filter()
#> x dplyr::lag() masks stats::lag()
df2 <- df2 %>%
mutate(Date = Date + 90)
# Make a dataframe with complete set of day-ID combinations
df_completed <- df1 %>%
mutate(day = factor(Date, levels = 1:180)) %>% # set to total day length
complete(ID, day) %>%
mutate(daysum = 0) %>%
select(ID, day, daysum)
# Function to apply to each data frame containing events
# Should take each event and add value to the appropriate days
sum_df_daily <- function(df_complete, df){
for (i in 1:nrow(df)){
event_days <- seq(df[i, "Date"], df[i, "Date"] + df[i, "Days"] - 1)
df_complete <- df_complete %>%
mutate(
to_add = case_when(
ID == df[i, "ID"] & day %in% event_days ~ df[i, "Value"],
!(ID == df[i, "ID"] & day %in% event_days) ~ 0
),
daysum = daysum + to_add
)
}
return(df_complete)
}
df_filled <- df_completed %>%
sum_df_daily(df1) %>%
sum_df_daily(df2) %>%
mutate(
quarter = case_when(
day %in% 1:90 ~ "q1",
day %in% 91:180 ~ "q2"
)
)
df_filled %>%
group_by(quarter, ID) %>%
summarise(maxsum = max(daysum))
#> # A tibble: 6 x 3
#> # Groups: quarter [?]
#> quarter ID maxsum
#> <chr> <dbl> <dbl>
#> 1 q1 1.00 60.0
#> 2 q1 2.00 40.0
#> 3 q1 3.00 30.0
#> 4 q2 1.00 80.0
#> 5 q2 2.00 30.0
#> 6 q2 3.00 40.0
我有多个大型数据框来捕获持续一定时间的事件。这个例子给出了我的数据集的简化版本
数据框 1:
ID Days Date Value
1 10 80 30
1 10 85 30
2 20 75 20
2 10 80 20
3 5 90 30
数据框 2:
ID Days Date Value
1 20 0 30
1 10 3 20
2 20 5 30
3 20 1 10
3 10 10 10
同一个
ID
用于所有数据集中的同一个人Days
指定事件的长度(如果Days
的值为 10,则事件持续 10 天)Date
指定事件开始的日期。在这种情况下,Date
可以是 0 到 90 或 91 之间的任何数字(数据代表季度中的天数)Value
是重复指定的Days
次的属性。例如,对于 df1 中的第一行,值30
从第 80 天开始重复 10 次( 30 重复 10 天)
我感兴趣的是为每个数据框中的每个 ID
赋予每天的最高值。请记住,多个事件可以重叠,然后必须对值进行求和。
最终数据框应如下所示:
ID HighestValuedf1 HighestValuedf2
1 60 80
2 40 30
3 30 20
例如,对于ID
1,三个事件重叠,导致数据框2中的最高值为80。对于ID
3,df1和df1的事件之间没有重叠,仅与 df2.[=25=] 重叠
由于文件的大小,我更喜欢一种避免将所有数据帧合并到一个数据帧中的解决方案。
编辑 我重新排列了我的数据,以便所有重叠的事件都在一个数据框中。我只需要每个数据帧的最高重叠值。
重现数据帧的代码:
ID = c(1,1,2,2,3)
Date = c(80,85,75,80,90)
Days = c(10,10,20,10,5)
Value = c(30,30,20,20,30)
df1 = data.frame(ID,Days, Date,Value)
ID = c(1,1,2,3,3)
Date = c(1,3,5,1,10)
Days = c(20,10,20,20,10 )
Value =c(30,20,30,10,10)
df2 = data.frame(ID,Days, Date,Value)
ID= c(1,2,3)
HighestValuedf1 = c(60,40,30)
HighestValuedf2 = c(80,30,20)
df3 = data.frame(ID, HighestValuedf1, HighestValuedf2)
我将每天的最高值解释为整个时间段内单日的最高值。这可能不是最有效的解决方案,因为我希望可以使用 map
或 apply
函数来完成某些事情,但我第一眼看不到如何做。使用上面定义的 df1
和 df2
:
编辑:在理解 df1 和 df2 应该代表连续的季度后修改代码。我认为最简单的方法是简单地堆叠数据帧,以便自动捕获任何重叠的内容(即 df2 的第 1 天是第 91 天)。由于季度的长度不同,您可能需要手动调整此代码,或者最好将季度的天数转换为具有日期格式的一年中的实际日期(例如,df1 第 1 天变为 2017 年 1 月 1 日)。下面的代码只是重新排列以实现此目的,然后通过在 1:90、91:180 天进行过滤来生成每个季度所需的结果,如图所示)
ID = c(1,1,2,2,3)
Date = c(80,85,75,80,90)
Days = c(10,10,20,10,5)
Value = c(30,30,20,20,30)
df1 = data.frame(ID,Days, Date,Value)
ID = c(1,1,2,3,3)
Date = c(1,3,5,1,10)
Days = c(20,10,20,20,10 )
Value =c(30,20,30,10,10)
df2 = data.frame(ID,Days, Date,Value)
library(tidyverse)
#> -- Attaching packages --------------------------------------------------------------------- tidyverse 1.2.1 --
#> v ggplot2 2.2.1.9000 v purrr 0.2.4
#> v tibble 1.4.2 v dplyr 0.7.4
#> v tidyr 0.7.2 v stringr 1.2.0
#> v readr 1.1.1 v forcats 0.2.0
#> -- Conflicts ------------------------------------------------------------------------ tidyverse_conflicts() --
#> x dplyr::filter() masks stats::filter()
#> x dplyr::lag() masks stats::lag()
df2 <- df2 %>%
mutate(Date = Date + 90)
# Make a dataframe with complete set of day-ID combinations
df_completed <- df1 %>%
mutate(day = factor(Date, levels = 1:180)) %>% # set to total day length
complete(ID, day) %>%
mutate(daysum = 0) %>%
select(ID, day, daysum)
# Function to apply to each data frame containing events
# Should take each event and add value to the appropriate days
sum_df_daily <- function(df_complete, df){
for (i in 1:nrow(df)){
event_days <- seq(df[i, "Date"], df[i, "Date"] + df[i, "Days"] - 1)
df_complete <- df_complete %>%
mutate(
to_add = case_when(
ID == df[i, "ID"] & day %in% event_days ~ df[i, "Value"],
!(ID == df[i, "ID"] & day %in% event_days) ~ 0
),
daysum = daysum + to_add
)
}
return(df_complete)
}
df_filled <- df_completed %>%
sum_df_daily(df1) %>%
sum_df_daily(df2) %>%
mutate(
quarter = case_when(
day %in% 1:90 ~ "q1",
day %in% 91:180 ~ "q2"
)
)
df_filled %>%
group_by(quarter, ID) %>%
summarise(maxsum = max(daysum))
#> # A tibble: 6 x 3
#> # Groups: quarter [?]
#> quarter ID maxsum
#> <chr> <dbl> <dbl>
#> 1 q1 1.00 60.0
#> 2 q1 2.00 40.0
#> 3 q1 3.00 30.0
#> 4 q2 1.00 80.0
#> 5 q2 2.00 30.0
#> 6 q2 3.00 40.0