【问题标题】:Randomly subset each group to satisfy conditions随机对每个组进行子集以满足条件
【发布时间】:2017-06-23 19:12:13
【问题描述】:

希望通过遍历每个资源的名称来减少资源分配,并查看分配给该人姓名的帐户,随机选择一个并将该人的姓名替换为 NA。

可重现的例子:

Accts <- paste0("Acc", 1:200)
Value <- c(500, 2000, 5000, 1000)
AccountDF <- data.frame(Accts, Value)
AccountDF$Owner[1:200] <- NA
AccountDF$Owner[1:23] <- "Jeff"
AccountDF$Owner[24:37] <- "Alex"
AccountDF$Owner[38:61] <- "Steph"
AccountDF$Owner[62:111] <- "Matt"
AccountDF$Owner[112:141] <- "David"

library(dplyr)
OwnerDF <- AccountDF %>%
  group_by(Owner) %>%
  summarise(Count = n(),
            TotalValue = sum(Value)) %>%
  filter(!is.na(Owner))

到目前为止我在哪里:

for (p in 1:nrow(OwnerDF)){
  while (AccountDF$Count[p] > 22){
    AccountDF %>%
      filter(Owner == OwnerDF$Owner[p]) %>%
      sample_n(1)


  }
}

我听说 for 循环是不必要的。我确信这可以通过 purr 包和 pmap 或类似的东西来完成。我仍然在学习。

我想遍历 OwnerDF 并查看该人是否“拥有”太多帐户。如果是,请查看原始帐户列表并随机选择一个并将所有者的姓名替换为 NA,从其计数中删除 1,然后继续。

最后,在弄清楚这一点之后,我想看看它是否可以在多个条件下完成。比如 While(Count > 22 & Value > $40,000),或者两个 while 循环。目标是将每个人的“拥有”账户减少到某个阈值以下,并将 $$ 减少到某个阈值以下。

【问题讨论】:

    标签: r for-loop while-loop dplyr


    【解决方案1】:

    要选择随机帐户,只需创建一个随机变量并对其进行排序,取前 N 个满足您条件的帐户:

     set.seed(1)
     res = AccountDF %>% 
       mutate(r = runif(n())) %>% 
       arrange(r) %>% 
       group_by(Owner) %>% 
       mutate(newOwner = replace(Owner, cumsum(Value) > 40000 | row_number() > 22, NA)) %>% 
       select(-r)
    
    # Test that it worked...
    res %>%
      filter(!is.na(newOwner)) %>%
      group_by(newOwner) %>%
      summarise(Count = n(), TotalValue = sum(Value))
    
    # A tibble: 5 x 3
    #   newOwner Count TotalValue
    #      <chr> <int>      <dbl>
    # 1     Alex    14      27000
    # 2    David    18      37000
    # 3     Jeff    18      39500
    # 4     Matt    18      39500
    # 5    Steph    17      36500
    

    OP 在评论中提到的扩展:

    你的另一个问题。假设我对每个值和计数都有一个阈值,如果有人计数低但值高,我想从他们的高值帐户中随机取一个帐户,如果他们的计数和值低,我想取低远离他们的价值账户。我怎么能从随机的角度做到这一点?

    我可能会为每个观察分配一个实值分数,例如...

    s = scale(f(x))
    

    f 是基于您提到的条件(高计数、高值或两者兼有)的某个函数,当您想要偏向低值时可能像 x 和想要偏向低值时像 -x 一样简单偏向高值。

    然后,添加一些噪音并使用上述结果进行排序:

    r = s + rnorm(length(s))
    

    【讨论】:

    • 太棒了。非常感谢弗兰克。工作完美。我从来没有想过这样的解决方案。我对随机生成了解不多。再问你一个问题。假设我对每个值和计数都有一个阈值,如果有人计数低但值高,我想从他们的高值帐户中随机取一个帐户,如果他们的计数和值低,我想取低远离他们的价值账户。我怎么能从随机的角度做到这一点?
    • @MattW。有趣的问题。您几乎肯定会想要滚动一个自定义函数来处理它。我在答案中添加了一些。
    • 你解释的最后一部分让我有点不知所措哈哈。另外-我尝试将您的解决方案应用于我的数据集,但无法正常工作。它随着 mutate 替换而分裂。我不知道我做错了什么。
    • @MattW。如果您在Value 中有缺失值,那可能会破坏它。否则,什么都不会想到。基本思想是:分配一个分数进行排序,但在排序之前添加一些噪音,因为你想要“高价值账户”而不是“最高价值账户”(或者至少听起来是这样)。
    • 我想通了。 facepalm 我正在变异的“NewOwner”列,实际上我碰巧已经将它作为一个列,所以它只是更新了以前的列,我没有注意到它,因为 df 有 60 列。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-12-09
    • 1970-01-01
    • 2020-03-02
    • 1970-01-01
    • 1970-01-01
    • 2023-01-26
    • 1970-01-01
    相关资源
    最近更新 更多