【问题标题】:How select random non-consecutive dates for every grouped element?如何为每个分组元素选择随机的非连续日期?
【发布时间】:2021-04-22 08:57:13
【问题描述】:

我目前正在尝试为每个分组列选择不连续的日期。

换句话说,我有以下数据框:

我想基本上group_by(Site) 然后为每个分组站点只保留 3 个随机不连续的日期。例如,如果 HP37P1B 的日期对应于 3 月 12 日、3 月 13 日、3 月 14 日和 3 月 7 日 - 我需要一个数据框(例如),它只有:

HP37P1B 12th March

HP37P1B 14th March

HP37P1B 7th March

到目前为止,我已经尝试了许多使用 diff()ave()lubridate 包的 stackoverflow 帖子,但我没有任何成功。

编辑

根据下面的 cmets,我试图让这个问题可重现

dput(uniqueSiteDate)

structure(list(Site = c("HP37P1B", "HP37P2B", "HP37P4B", "HP4008U", 
"INME03R", "INME03U", "INOA03R", "IPTO04R", "IPTO04U", "IPTO06R", 
"IPTO06U", "OLCAP2B", "OLCAP3B", "OLCAP5B", "PANMP1B", "PANMP2B", 
"PANMP3B", "STIN02R", "STIN02U", "UPMAP1B", "UPMAP3B", "UPMAP4B", 
"UPMAP5B", "UPMAP6B", "VAR210R", "VAR310R", "VAR310U", "VAR410R", 
"VAR410U", "HP36P1B", "HP36P3B", "HP36P4B", "HP4008R", "INBS04R", 
"INBS04U", "SEL107R", "SEL107U", "SEL207R", "SEL207U", "OLV110R", 
"OLV110U", "OLV208R", "OLV208U", "THEN10U", "HP37P1B", "HP37P2B", 
"HP37P4B", "HP4008U", "INME03R", "INME03U", "INOA03R", "IPTO04R", 
"IPTO04U", "IPTO06R", "IPTO06U", "OLCAP2B", "OLCAP3B", "OLCAP5B", 
"PANMP1B", "PANMP2B", "PANMP3B", "STIN02R", "STIN02U", "UPMAP1B", 
"UPMAP3B", "UPMAP4B", "UPMAP5B", "UPMAP6B", "VAR210R", "VAR310R", 
"VAR310U", "VAR410R", "VAR410U", "OLV110R", "OLV110U", "OLV208R", 
"OLV208U", "THEN10U", "HP37P1B", "HP37P2B", "HP37P4B", "HP4008U", 
"INME03R", "INME03U", "INOA03R", "IPTO04R", "IPTO04U", "IPTO06R", 
"IPTO06U", "OLCAP2B", "OLCAP3B", "OLCAP5B", "PANMP1B", "PANMP2B", 
"PANMP3B", "STIN02R", "STIN02U", "UPMAP1B", "UPMAP3B", "UPMAP4B", 
"UPMAP5B", "UPMAP6B", "VAR210R", "VAR310R", "VAR310U", "VAR410R", 
"VAR410U", "OLV110R", "OLV110U", "OLV208R", "OLV208U", "THEN10U", 
"HP37P1B", "HP37P2B", "HP37P4B", "HP4008U", "INME03R", "INME03U", 
"INOA03R", "IPTO04R", "IPTO04U", "IPTO06R", "IPTO06U", "OLCAP2B", 
"OLCAP3B"), Date = structure(c(18333, 18333, 18333, 18333, 18335, 
18335, 18335, 18338, 18335, 18338, 18335, 18333, 18333, 18333, 
18334, 18334, 18334, 18331, 18331, 18331, 18330, 18330, 18330, 
18330, 18332, 18332, 18332, 18332, 18332, 18325, 18325, 18325, 
18325, 18327, 18327, 18327, 18327, 18327, 18328, 18340, 18340, 
18340, 18340, 18340, 18334, 18334, 18334, 18334, 18336, 18336, 
18336, 18339, 18336, 18340, 18336, 18335, 18334, 18334, 18335, 
18335, 18335, 18332, 18332, 18332, 18331, 18331, 18331, 18331, 
18333, 18333, 18333, 18333, 18333, 18341, 18341, 18341, 18341,
18341, 18335, 18335, 18335, 18335, 18383, 18383, 18383, 18384, 
18384, 18384, 18384, 18385, 18385, 18335, 18342, 18342, 18341, 
18383, 18383, 18345, 18349, 18349, 18349, 18349, 18340, 18339, 
18340, 18341, 18339, 18386, 18386, 18348, 18346, 18347, 18328, 
18328, 18328, 18328, 18390, 18389, 18391, 18392, 18392, 18392, 
18392, 18392, 18392), class = "Date")), row.names = c(NA, -125L
), groups = structure(list(Site = c("HP36P1B", "HP36P3B", "HP36P4B", 
"HP37P1B", "HP37P2B", "HP37P4B", "HP4008R", "HP4008U", "INBS04R", 
"INBS04U", "INME03R", "INME03U", "INOA03R", "IPTO04R", "IPTO04U", 
"IPTO06R", "IPTO06U", "OLCAP2B", "OLCAP3B", "OLCAP5B", "OLV110R", 
"OLV110U", "OLV208R", "OLV208U", "PANMP1B", "PANMP2B", "PANMP3B", 
"SEL107R", "SEL107U", "SEL207R", "SEL207U", "STIN02R", "STIN02U", 
"THEN10U", "UPMAP1B", "UPMAP3B", "UPMAP4B", "UPMAP5B", "UPMAP6B", 
"VAR210R", "VAR310R", "VAR310U", "VAR410R", "VAR410U"), .rows = structure(list(
    30L, 31L, 32L, c(1L, 45L, 79L, 113L), c(2L, 46L, 80L, 114L
    ), c(3L, 47L, 81L, 115L), 33L, c(4L, 48L, 82L, 116L), 34L, 
    35L, c(5L, 49L, 83L, 117L), c(6L, 50L, 84L, 118L), c(7L, 
    51L, 85L, 119L), c(8L, 52L, 86L, 120L), c(9L, 53L, 87L, 121L
    ), c(10L, 54L, 88L, 122L), c(11L, 55L, 89L, 123L), c(12L, 
    56L, 90L, 124L), c(13L, 57L, 91L, 125L), c(14L, 58L, 92L), 
    c(40L, 74L, 108L), c(41L, 75L, 109L), c(42L, 76L, 110L), 
    c(43L, 77L, 111L), c(15L, 59L, 93L), c(16L, 60L, 94L), c(17L, 
    61L, 95L), 36L, 37L, 38L, 39L, c(18L, 62L, 96L), c(19L, 63L, 
    97L), c(44L, 78L, 112L), c(20L, 64L, 98L), c(21L, 65L, 99L
    ), c(22L, 66L, 100L), c(23L, 67L, 101L), c(24L, 68L, 102L
    ), c(25L, 69L, 103L), c(26L, 70L, 104L), c(27L, 71L, 105L
    ), c(28L, 72L, 106L), c(29L, 73L, 107L)), ptype = integer(0), class = c("vctrs_list_of", 
"vctrs_vctr", "list"))), row.names = c(NA, -44L), class = c("tbl_df", 
"tbl", "data.frame"), .drop = TRUE), class = c("grouped_df", 
"tbl_df", "tbl", "data.frame"))

要回答其他问题,有时每个站点的日期超过 3 个,但有时每个站点只有 1 个日期。但想法是选择 n 个给定站点的非连续日期。换句话说,如果一个特定的网站有 4 个日期,我需要 3 个不连续的日期。如果某个特定网站只有 1 个日期,我们就把它留在里面。

【问题讨论】:

  • 1.你能举个例子reproducible吗? 2.Site的日期是否总是至少有3个? 3.“非连续”部分是硬性要求吗?或者随机抽样 3 个日期(因此可能是连续的)的解决方案是否令人满意?如果没有,是否保证不仅有 3 个日期,而且有 3 个日期可以找到解决方案?
  • 即使你的图片与所述示例不匹配??第一个 site 的日期对于所有三行都是相同的。
  • 我添加了更多信息来帮助回答这个问题@Aurèle
  • @AnoushiravanR 见上面的编辑
  • 在提供的数据中,第一组的所有日期都相同?

标签: r random dplyr


【解决方案1】:

请检查它是否达到目的?实际上,使用提供标准选择最大可能的日期是困难的(至少对我而言)。我们可以通过以下策略识别连续和非连续组中的日期。但是考虑一组说 3 个连续日期的两个场景。如果 随机 样本包含 2 个单元,则这些单元也可以是连续的或不连续的。假设如果我们进一步选择奇数 (2) 行或偶数 (1) 行,那么在我看来,样本将是判断性的,而不是随机的。这是采用的策略-

  • 将数据分组
  • 通过purrr::map_df分别对各组进行操作,最后一行绑定数据
  • 将数据(现在为组)分为连续日期和非连续日期(每个连续日期将在其自己的组中)。从每个组中选择唯一的行。
  • 最后从每一行中选择三个(或更少,根据组结果)。
library(tidyverse)

df %>% 
  ungroup() %>% 
  group_split(Site) %>% 
  map_df(., ~ .x %>% ungroup() %>%
        arrange(Date) %>%
        mutate(n = 1) %>%
        complete(Date = seq.Date(first(Date), last(Date), by = 'days')) %>%
        group_by(n = cumsum(is.na(n))) %>%
        filter(!is.na(Site)) %>%
        sample_n(1) %>%
        ungroup() %>%
        sample_n(min(n(), 3))) %>%
  select(-n)

# A tibble: 86 x 2
   Date       Site   
   <date>     <chr>  
 1 2020-03-04 HP36P1B
 2 2020-03-04 HP36P3B
 3 2020-03-04 HP36P4B
 4 2020-03-07 HP37P1B
 5 2020-03-12 HP37P1B
 6 2020-03-07 HP37P2B
 7 2020-03-12 HP37P2B
 8 2020-03-07 HP37P4B
 9 2020-03-12 HP37P4B
10 2020-03-04 HP4008R
# ... with 76 more rows

注意:您的 dput 已分组,因此我必须在代码的第二行添加 ungroup(),您可以将其删除

【讨论】:

  • 非常感谢@AnilGoyal。但是,对于 HP37P1B 的示例 - 可以选择 3 个不连续的日期,但只选择了两个。例如,我们可以选择 3 月 7 日(你做了)、3 月 12 日(你做了),但也可以选择 3 月 14 日。其他一些网站也是如此。
  • 是的,但是样本不会是随机的。这是唯一可能的样本
  • 不,我的意思是 - 我想选择至少 3 个随机不连续的。在您的代码中,我们只选择了 2 个。
  • HP37P1B的情况下,至少可以选择3个不连续的日期,而HP36P1B的情况下,只能选择1个日期。
  • ?那有意义吗? - 基本上,如果我要你选择任意数量的非连续日期(随机),给定样本量。
【解决方案2】:

这应该可行,但我无法对您的数据进行真正的测试,因为每个站点只包含一行(因此只有一个日期)。


l <- dat %>% group_by( Site ) %>%
    group_map( function(x,y) {

        n.day.increments <- sum( diff(sort(x$Date)) == 1 )
        n.2day.increments <- sum( diff(sort(x$Date)) >= 2 )
        can.have.3.dates <- n.day.increments >= 5 || n.2day.increments >= 2 || (n.day.increments >= 2 && n.2day.increments >= 1 )
        can.have.2.dates <- n.day.increments >= 2 || n.2day.increments >= 1


        repeat{

            if( can.have.3.dates ) {
                d <- x %>% sample_n(3)

                if( all(abs(diff(d$Date)) > 1 ) )
                    break

            } else if( can.have.2.dates ) {

                if( can.have.2.dates ) {
                    d <- x %>% sample_n(2)

                    if( all(abs(diff(d$Date)) > 1 ) )
                        break

                }

            } else {
                d <- x %>% sample_n(1)
                break
            }

        }
        cbind( y, d )
    })

sampled.data <- bind_rows(l)


【讨论】:

  • 现在出现错误。您能看到对问题的修改吗?
  • 即使只有一个日期与站点相关联,这也应该可以工作吧?
  • 不,绝对不是,您更新的问题说 2 个不连续的日期也可以,所以这是我的新最低要求
  • 我已经进一步编辑了这个问题 - 请参阅。
  • 你需要非常清楚这一点。当代码不能满足 3 个不连续的日期时应该怎么做。如果可能,请选择 3 连续?去 2 nonconsectuve 代替?如果它不能产生 2 个不连续但可以连续产生 2 个,它应该做这 2 个,还是只返回 1 个?
猜你喜欢
  • 1970-01-01
  • 2014-06-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-12-03
  • 1970-01-01
  • 1970-01-01
  • 2018-02-16
相关资源
最近更新 更多