创建间隔
Creating intervals
我有一个数据集,我想将其分成 10 天的时间间隔。我在下面包含的代码可以做到这一点,但在过去一周左右的时间里,有些日子(例如,一个月的 31 日或 30 日)仍然自行结束。
我想删除创建它的间隔或将它们包含在之前的间隔中。
例如:
如果我以 10 天为间隔分隔 1 月,它会将前 10 天放入列表的一个元素中,将第二个 10 天放入另一个元素中,将第三个 10 天放入另一个元素中。然后它将 1 月 31 日单独放入列表的一个元素中。
我想要的输出是从列表中删除这些元素,或者更优选将它们包含在第三个 10 天间隔中。那可以吗?如果是这样,最好的方法是什么?
library(lubridate)
library(tidyverse)
date <- rep_len(seq(dmy("26-12-2010"), dmy("20-12-2013"), by = "days"), 500)
ID <- rep(seq(1, 5), 100)
df <- data.frame(date = date,
x = runif(length(date), min = 60000, max = 80000),
y = runif(length(date), min = 800000, max = 900000),
ID)
int <- df %>%
arrange(ID) %>%
mutate(new = ceiling_date(date, '10 day')) %>%
# mutate(cut = data.table::rleid(cut(new, breaks = "10 day"))) %>%
group_by(new) %>%
group_split()
如果组中只有一行,请为其提供先前的 new
值。试试这个 -
library(dplyr)
library(lubridate)
df %>%
arrange(ID, date) %>%
mutate(new = ceiling_date(date, '10 day')) %>%
add_count(new) %>%
mutate(new = if_else(n == 1, lag(new), new)) %>%
select(-n) %>%
group_split(new)
以上仅适用于组合具有 1 个观察值的组。如果我们想合并超过 1 天,请使用下面的代码来计算一组中的天数。如果天数小于 n
天数,则合并组。
n <- 2
df %>%
arrange(ID, date) %>%
mutate(new = ceiling_date(date, '10 day'),
ID = match(new, unique(new))) -> tmp
tmp %>%
group_by(new, ID) %>%
summarise(count_unique = n_distinct(date)) %>%
ungroup %>%
mutate(new = if_else(count_unique < n, lag(new), new)) %>%
inner_join(tmp, by = 'ID') %>%
select(new = new.x, date, x, y) %>%
group_split(new)
这是一个解决方案,它按 10 天的间隔拆分月份,但更正 new
以将一个月的第 31 天分配给最后一个时期。所以,
- 第 1 到 10 天属于一个月的前三分之一,
- 第 11 天到第 20 天到第二个三分之一,并且
- 第21天到第31天到第三天
int <- df %>%
# arrange(ID) %>% # skipped for readability of result
mutate(new = floor_date(date, '10 day')) %>%
mutate(new = if_else(day(new) == 31, new - days(10), new)) %>%
group_by(new) %>%
group_split()
int[[1]]
# A tibble: 6 x 5
date x y ID new
<date> <dbl> <dbl> <int> <date>
1 2010-12-26 71469. 819084. 1 2010-12-21
2 2010-12-27 69417. 893227. 2 2010-12-21
3 2010-12-28 70865. 831341. 3 2010-12-21
4 2010-12-29 68322. 812423. 4 2010-12-21
5 2010-12-30 65643. 837395. 5 2010-12-21
6 2010-12-31 63638. 892200. 1 2010-12-21
现在,2010-12-31
被分配到 12 月 3 日。
请注意,new
通过调用 floor_date()
而不是 ceiling_date()
来指示间隔 的 开始。这是为了避免跨月边界日算术的潜在问题,并明确间隔属于哪个月。例如,对于二月的最后一天,ceiling_date(ymd('2011-02-28'), '10 day')
returns "2011-03-03" 这是三月的日期。
备选方案
library(lubridate)
library(tidyverse)
dt <- rep_len(seq(dmy("26-12-2010"), dmy("20-12-2013"), by = "days"), 500)
ID <- rep(seq(1, 5), 100)
df <- data.frame(dt = dt,
x = runif(length(dt), min = 60000, max = 80000),
y = runif(length(dt), min = 800000, max = 900000),
ID)
- 将额外的天数(第 31 天)计入最后三分之一
int_df <- df %>%
# arrange(ID) %>%
mutate(day_date = day(dt),
day_new = case_when(
day_date <= 10 ~ 1,
day_date <= 20 ~ 11,
TRUE ~ 21
),
new = ymd(paste(year(dt), month(dt), day_new, sep = "-"))) %>%
select(-c(day_date, day_new)) %>%
group_by(new) %>%
group_split()
int_df[[1]]
#> # A tibble: 6 x 5
#> dt x y ID new
#> <date> <dbl> <dbl> <int> <date>
#> 1 2010-12-26 62395. 837491. 1 2010-12-21
#> 2 2010-12-27 66236. 836481. 2 2010-12-21
#> 3 2010-12-28 79918. 818399. 3 2010-12-21
#> 4 2010-12-29 67613. 807213. 4 2010-12-21
#> 5 2010-12-30 72980. 899380. 5 2010-12-21
#> 6 2010-12-31 61004. 876191. 1 2010-12-21
- 排除额外天数(第 31 天)
int_df <- df %>%
# arrange(ID) %>%
mutate(day_date = day(dt),
day_new = case_when(
day_date <= 10 ~ 1,
day_date <= 20 ~ 11,
day_date <= 30 ~ 21,
TRUE ~ 31
),
new = ymd(paste(year(dt), month(dt), day_new, sep = "-"))) %>%
filter(day_date != 31) %>%
select(-c(day_date, day_new)) %>%
group_by(new) %>%
group_split()
int_df[[1]]
#> # A tibble: 5 x 5
#> dt x y ID new
#> <date> <dbl> <dbl> <int> <date>
#> 1 2010-12-26 62395. 837491. 1 2010-12-21
#> 2 2010-12-27 66236. 836481. 2 2010-12-21
#> 3 2010-12-28 79918. 818399. 3 2010-12-21
#> 4 2010-12-29 67613. 807213. 4 2010-12-21
#> 5 2010-12-30 72980. 899380. 5 2010-12-21
由 reprex package (v2.0.0)
于 2021-07-03 创建
我有一个数据集,我想将其分成 10 天的时间间隔。我在下面包含的代码可以做到这一点,但在过去一周左右的时间里,有些日子(例如,一个月的 31 日或 30 日)仍然自行结束。
我想删除创建它的间隔或将它们包含在之前的间隔中。
例如: 如果我以 10 天为间隔分隔 1 月,它会将前 10 天放入列表的一个元素中,将第二个 10 天放入另一个元素中,将第三个 10 天放入另一个元素中。然后它将 1 月 31 日单独放入列表的一个元素中。
我想要的输出是从列表中删除这些元素,或者更优选将它们包含在第三个 10 天间隔中。那可以吗?如果是这样,最好的方法是什么?
library(lubridate)
library(tidyverse)
date <- rep_len(seq(dmy("26-12-2010"), dmy("20-12-2013"), by = "days"), 500)
ID <- rep(seq(1, 5), 100)
df <- data.frame(date = date,
x = runif(length(date), min = 60000, max = 80000),
y = runif(length(date), min = 800000, max = 900000),
ID)
int <- df %>%
arrange(ID) %>%
mutate(new = ceiling_date(date, '10 day')) %>%
# mutate(cut = data.table::rleid(cut(new, breaks = "10 day"))) %>%
group_by(new) %>%
group_split()
如果组中只有一行,请为其提供先前的 new
值。试试这个 -
library(dplyr)
library(lubridate)
df %>%
arrange(ID, date) %>%
mutate(new = ceiling_date(date, '10 day')) %>%
add_count(new) %>%
mutate(new = if_else(n == 1, lag(new), new)) %>%
select(-n) %>%
group_split(new)
以上仅适用于组合具有 1 个观察值的组。如果我们想合并超过 1 天,请使用下面的代码来计算一组中的天数。如果天数小于 n
天数,则合并组。
n <- 2
df %>%
arrange(ID, date) %>%
mutate(new = ceiling_date(date, '10 day'),
ID = match(new, unique(new))) -> tmp
tmp %>%
group_by(new, ID) %>%
summarise(count_unique = n_distinct(date)) %>%
ungroup %>%
mutate(new = if_else(count_unique < n, lag(new), new)) %>%
inner_join(tmp, by = 'ID') %>%
select(new = new.x, date, x, y) %>%
group_split(new)
这是一个解决方案,它按 10 天的间隔拆分月份,但更正 new
以将一个月的第 31 天分配给最后一个时期。所以,
- 第 1 到 10 天属于一个月的前三分之一,
- 第 11 天到第 20 天到第二个三分之一,并且
- 第21天到第31天到第三天
int <- df %>%
# arrange(ID) %>% # skipped for readability of result
mutate(new = floor_date(date, '10 day')) %>%
mutate(new = if_else(day(new) == 31, new - days(10), new)) %>%
group_by(new) %>%
group_split()
int[[1]]
# A tibble: 6 x 5 date x y ID new <date> <dbl> <dbl> <int> <date> 1 2010-12-26 71469. 819084. 1 2010-12-21 2 2010-12-27 69417. 893227. 2 2010-12-21 3 2010-12-28 70865. 831341. 3 2010-12-21 4 2010-12-29 68322. 812423. 4 2010-12-21 5 2010-12-30 65643. 837395. 5 2010-12-21 6 2010-12-31 63638. 892200. 1 2010-12-21
现在,2010-12-31
被分配到 12 月 3 日。
请注意,new
通过调用 floor_date()
而不是 ceiling_date()
来指示间隔 的 开始。这是为了避免跨月边界日算术的潜在问题,并明确间隔属于哪个月。例如,对于二月的最后一天,ceiling_date(ymd('2011-02-28'), '10 day')
returns "2011-03-03" 这是三月的日期。
备选方案
library(lubridate)
library(tidyverse)
dt <- rep_len(seq(dmy("26-12-2010"), dmy("20-12-2013"), by = "days"), 500)
ID <- rep(seq(1, 5), 100)
df <- data.frame(dt = dt,
x = runif(length(dt), min = 60000, max = 80000),
y = runif(length(dt), min = 800000, max = 900000),
ID)
- 将额外的天数(第 31 天)计入最后三分之一
int_df <- df %>%
# arrange(ID) %>%
mutate(day_date = day(dt),
day_new = case_when(
day_date <= 10 ~ 1,
day_date <= 20 ~ 11,
TRUE ~ 21
),
new = ymd(paste(year(dt), month(dt), day_new, sep = "-"))) %>%
select(-c(day_date, day_new)) %>%
group_by(new) %>%
group_split()
int_df[[1]]
#> # A tibble: 6 x 5
#> dt x y ID new
#> <date> <dbl> <dbl> <int> <date>
#> 1 2010-12-26 62395. 837491. 1 2010-12-21
#> 2 2010-12-27 66236. 836481. 2 2010-12-21
#> 3 2010-12-28 79918. 818399. 3 2010-12-21
#> 4 2010-12-29 67613. 807213. 4 2010-12-21
#> 5 2010-12-30 72980. 899380. 5 2010-12-21
#> 6 2010-12-31 61004. 876191. 1 2010-12-21
- 排除额外天数(第 31 天)
int_df <- df %>%
# arrange(ID) %>%
mutate(day_date = day(dt),
day_new = case_when(
day_date <= 10 ~ 1,
day_date <= 20 ~ 11,
day_date <= 30 ~ 21,
TRUE ~ 31
),
new = ymd(paste(year(dt), month(dt), day_new, sep = "-"))) %>%
filter(day_date != 31) %>%
select(-c(day_date, day_new)) %>%
group_by(new) %>%
group_split()
int_df[[1]]
#> # A tibble: 5 x 5
#> dt x y ID new
#> <date> <dbl> <dbl> <int> <date>
#> 1 2010-12-26 62395. 837491. 1 2010-12-21
#> 2 2010-12-27 66236. 836481. 2 2010-12-21
#> 3 2010-12-28 79918. 818399. 3 2010-12-21
#> 4 2010-12-29 67613. 807213. 4 2010-12-21
#> 5 2010-12-30 72980. 899380. 5 2010-12-21
由 reprex package (v2.0.0)
于 2021-07-03 创建