按相等间隔将数据框中的一组数据装箱的更好方法
Better way of binning data in a group in a data frame by equal intervals
我有一个数据框,其特征在于许多不同的 ID。对于每个 ID 都有多个事件,这些事件的特征是事件之间的累积持续时间(小时)和该事件的持续时间(秒)。所以,它看起来像:
Id <- c(1,1,1,1,1,1,2,2,2,2,2)
cumulative_time<-c(0,3.58,8.88,11.19,21.86,29.54,0,5,14,19,23)
duration<-c(188,124,706,53,669,1506.2,335,349,395,385,175)
test = data.frame(Id,cumulative_time,duration)
> test
Id cummulative_time duration
1 1 0.00 188.0
2 1 3.58 124.0
3 1 8.88 706.0
4 1 11.19 53.0
5 1 21.86 669.0
6 1 29.54 1506.2
7 2 0.00 335.0
8 2 5.00 349.0
9 2 14.00 395.0
10 2 19.00 385.0
11 2 23.00 175.0
我想按 ID 分组,然后按每 10 小时的累积量抽样重组组,并在这 10 小时内按 10 小时间隔内发生的持续时间求和。我想要的垃圾箱数量应该是从 0 到 30 小时。因此将是 3 个箱子。
我查看了 cut
函数并设法在数据框中对其进行了破解 - 即使我作为新的 r 用户也知道它并不漂亮
test_cut = test %>%
mutate(bin_durations = cut(test$cummulative_time,breaks = c(0,10,20,30),labels = c("10","20","30"),include.lowest = TRUE)) %>%
group_by(Id,bin_durations) %>%
mutate(total_duration = sum(duration)) %>%
select(Id,bin_durations,total_duration) %>%
distinct()
给出输出:
test_cut
Id time_bins duration
1 1 10 1018.0
2 1 20 53.0
3 1 30 2175.2
4 2 10 684.0
5 2 20 780.0
6 2 30 175.0
最终我希望间隔 window 和 bin 的数量是任意的——如果我有 5000 小时的跨度并且我想在 1 小时的样本中进行 bin。为此,我会使用 breaks=seq(0,5000,1)
作为 bins
我会说 labels = as.character(seq(1,5000,1))
这也适用于非常大的数据框,因此计算速度有点需要。
dplyr 解决方案会很棒,因为我正在按组应用分箱。
我的猜测是 cut
和 split
之间有一个很好的交互来生成所需的输出。
提前致谢。
更新
经过测试,我发现即使是我目前的实现也不是我想要的,就像我说的那样:
n=3
test_cut = test %>%
mutate(bin_durations = cut(test$cumulative_time,breaks=seq(0,30,n),labels = as.character(seq(n,30,n)),include.lowest = TRUE)) %>%
group_by(Id,bin_durations) %>%
mutate(total_duration = sum(duration)) %>%
select(Id,bin_durations,total_duration) %>%
distinct()
我明白了
test_cut
# A tibble: 11 x 3
# Groups: Id, bin_durations [11]
Id bin_durations total_duration
<dbl> <fct> <dbl>
1 1 3 188
2 1 6 124
3 1 9 706
4 1 12 53
5 1 24 669
6 1 30 1506.
7 2 3 335
8 2 6 349
9 2 15 395
10 2 21 385
11 2 24 175
在 bin 序列中没有出现的地方,我应该在持续时间列中得到 0。而不是遗漏。
因此,它应该看起来像:
test_cut
# A tibble: 11 x 3
# Groups: Id, bin_durations [11]
Id bin_durations total_duration
<dbl> <fct> <dbl>
1 1 3 188
2 1 6 124
3 1 9 706
4 1 12 53
5 1 15 0
6 1 18 0
7 1 21 0
8 1 24 669
9 1 27 0
10 1 30 1506.
11 2 3 335
12 2 6 349
13 2 9 0
14 2 12 0
15 2 15 395
16 2 18 0
17 2 21 385
18 2 24 175
19 2 27 0
20 2 30 0
这是一个整数除法的想法(%/%
)
library(tidyverse)
test %>%
group_by(Id, grp = cumulative_time %/% 10) %>%
summarise(toatal_duration = sum(duration))
这给出了,
# A tibble: 6 x 3
# Groups: Id [?]
Id grp toatal_duration
<dbl> <dbl> <dbl>
1 1 0 1018
2 1 1 53
3 1 2 2175.
4 2 0 684
5 2 1 780
6 2 2 175
为了解决您更新后的问题,我们可以使用 complete
来添加缺失的行。因此,对于同一个示例,在 3 小时内分箱,
test %>%
group_by(Id, grp = cumulative_time %/% 3) %>%
summarise(toatal_duration = sum(duration)) %>%
ungroup() %>%
complete(Id, grp = seq(min(grp), max(grp)), fill = list(toatal_duration = 0))
这给出了,
# A tibble: 20 x 3
Id grp toatal_duration
<dbl> <dbl> <dbl>
1 1 0 188
2 1 1 124
3 1 2 706
4 1 3 53
5 1 4 0
6 1 5 0
7 1 6 0
8 1 7 669
9 1 8 0
10 1 9 1506.
11 2 0 335
12 2 1 349
13 2 2 0
14 2 3 0
15 2 4 395
16 2 5 0
17 2 6 385
18 2 7 175
19 2 8 0
20 2 9 0
我们可以进行以下更改:
test$cummulative_time
可以简单地 cumulative_time
breaks
可以分解出来然后用在 cut
中,如图所示
- 第二个
mutate
可以更改为 summarize
,在这种情况下,不需要 select
和 distinct
- 用匹配的
ungroup
关闭任何 group_by
总是一个好主意,或者在 summarize
的情况下我们可以使用 .groups = "drop")
- 添加
complete
为不存在的级别插入 0
实施这些更改我们有:
library(dplyr)
library(tidyr)
breaks <- seq(0, 40, 10)
test %>%
mutate(bin_durations = cut(cumulative_time, breaks = breaks,
labels = breaks[-1], include.lowest = TRUE)) %>%
group_by(Id,bin_durations) %>%
summarize(total_duration = sum(duration), .groups = "drop") %>%
complete(Id, bin_durations, fill = list(total_duration = 0))
给予:
# A tibble: 8 x 3
Id bin_durations total_duration
<dbl> <fct> <dbl>
1 1 10 1018
2 1 20 53
3 1 30 2175.
4 1 40 0
5 2 10 684
6 2 20 780
7 2 30 175
8 2 40 0
我有一个数据框,其特征在于许多不同的 ID。对于每个 ID 都有多个事件,这些事件的特征是事件之间的累积持续时间(小时)和该事件的持续时间(秒)。所以,它看起来像:
Id <- c(1,1,1,1,1,1,2,2,2,2,2)
cumulative_time<-c(0,3.58,8.88,11.19,21.86,29.54,0,5,14,19,23)
duration<-c(188,124,706,53,669,1506.2,335,349,395,385,175)
test = data.frame(Id,cumulative_time,duration)
> test
Id cummulative_time duration
1 1 0.00 188.0
2 1 3.58 124.0
3 1 8.88 706.0
4 1 11.19 53.0
5 1 21.86 669.0
6 1 29.54 1506.2
7 2 0.00 335.0
8 2 5.00 349.0
9 2 14.00 395.0
10 2 19.00 385.0
11 2 23.00 175.0
我想按 ID 分组,然后按每 10 小时的累积量抽样重组组,并在这 10 小时内按 10 小时间隔内发生的持续时间求和。我想要的垃圾箱数量应该是从 0 到 30 小时。因此将是 3 个箱子。
我查看了 cut
函数并设法在数据框中对其进行了破解 - 即使我作为新的 r 用户也知道它并不漂亮
test_cut = test %>%
mutate(bin_durations = cut(test$cummulative_time,breaks = c(0,10,20,30),labels = c("10","20","30"),include.lowest = TRUE)) %>%
group_by(Id,bin_durations) %>%
mutate(total_duration = sum(duration)) %>%
select(Id,bin_durations,total_duration) %>%
distinct()
给出输出:
test_cut
Id time_bins duration
1 1 10 1018.0
2 1 20 53.0
3 1 30 2175.2
4 2 10 684.0
5 2 20 780.0
6 2 30 175.0
最终我希望间隔 window 和 bin 的数量是任意的——如果我有 5000 小时的跨度并且我想在 1 小时的样本中进行 bin。为此,我会使用 breaks=seq(0,5000,1)
作为 bins
我会说 labels = as.character(seq(1,5000,1))
这也适用于非常大的数据框,因此计算速度有点需要。
dplyr 解决方案会很棒,因为我正在按组应用分箱。
我的猜测是 cut
和 split
之间有一个很好的交互来生成所需的输出。
提前致谢。
更新
经过测试,我发现即使是我目前的实现也不是我想要的,就像我说的那样:
n=3
test_cut = test %>%
mutate(bin_durations = cut(test$cumulative_time,breaks=seq(0,30,n),labels = as.character(seq(n,30,n)),include.lowest = TRUE)) %>%
group_by(Id,bin_durations) %>%
mutate(total_duration = sum(duration)) %>%
select(Id,bin_durations,total_duration) %>%
distinct()
我明白了
test_cut
# A tibble: 11 x 3
# Groups: Id, bin_durations [11]
Id bin_durations total_duration
<dbl> <fct> <dbl>
1 1 3 188
2 1 6 124
3 1 9 706
4 1 12 53
5 1 24 669
6 1 30 1506.
7 2 3 335
8 2 6 349
9 2 15 395
10 2 21 385
11 2 24 175
在 bin 序列中没有出现的地方,我应该在持续时间列中得到 0。而不是遗漏。
因此,它应该看起来像:
test_cut
# A tibble: 11 x 3
# Groups: Id, bin_durations [11]
Id bin_durations total_duration
<dbl> <fct> <dbl>
1 1 3 188
2 1 6 124
3 1 9 706
4 1 12 53
5 1 15 0
6 1 18 0
7 1 21 0
8 1 24 669
9 1 27 0
10 1 30 1506.
11 2 3 335
12 2 6 349
13 2 9 0
14 2 12 0
15 2 15 395
16 2 18 0
17 2 21 385
18 2 24 175
19 2 27 0
20 2 30 0
这是一个整数除法的想法(%/%
)
library(tidyverse)
test %>%
group_by(Id, grp = cumulative_time %/% 10) %>%
summarise(toatal_duration = sum(duration))
这给出了,
# A tibble: 6 x 3 # Groups: Id [?] Id grp toatal_duration <dbl> <dbl> <dbl> 1 1 0 1018 2 1 1 53 3 1 2 2175. 4 2 0 684 5 2 1 780 6 2 2 175
为了解决您更新后的问题,我们可以使用 complete
来添加缺失的行。因此,对于同一个示例,在 3 小时内分箱,
test %>%
group_by(Id, grp = cumulative_time %/% 3) %>%
summarise(toatal_duration = sum(duration)) %>%
ungroup() %>%
complete(Id, grp = seq(min(grp), max(grp)), fill = list(toatal_duration = 0))
这给出了,
# A tibble: 20 x 3 Id grp toatal_duration <dbl> <dbl> <dbl> 1 1 0 188 2 1 1 124 3 1 2 706 4 1 3 53 5 1 4 0 6 1 5 0 7 1 6 0 8 1 7 669 9 1 8 0 10 1 9 1506. 11 2 0 335 12 2 1 349 13 2 2 0 14 2 3 0 15 2 4 395 16 2 5 0 17 2 6 385 18 2 7 175 19 2 8 0 20 2 9 0
我们可以进行以下更改:
test$cummulative_time
可以简单地cumulative_time
breaks
可以分解出来然后用在cut
中,如图所示- 第二个
mutate
可以更改为summarize
,在这种情况下,不需要select
和distinct
- 用匹配的
ungroup
关闭任何group_by
总是一个好主意,或者在summarize
的情况下我们可以使用.groups = "drop")
- 添加
complete
为不存在的级别插入 0
实施这些更改我们有:
library(dplyr)
library(tidyr)
breaks <- seq(0, 40, 10)
test %>%
mutate(bin_durations = cut(cumulative_time, breaks = breaks,
labels = breaks[-1], include.lowest = TRUE)) %>%
group_by(Id,bin_durations) %>%
summarize(total_duration = sum(duration), .groups = "drop") %>%
complete(Id, bin_durations, fill = list(total_duration = 0))
给予:
# A tibble: 8 x 3
Id bin_durations total_duration
<dbl> <fct> <dbl>
1 1 10 1018
2 1 20 53
3 1 30 2175.
4 1 40 0
5 2 10 684
6 2 20 780
7 2 30 175
8 2 40 0