【问题标题】:split apply combine w/ function or purr package pmap?split apply combine w/function or purr package pmap?
【发布时间】:2017-06-24 23:21:00
【问题描述】:

这是我要解决的一个大问题。如果我有足够的声望来奖励赏金,我会的!

希望平衡销售代表的客户区域。我的流程被打破了,我真的不知道如何在每个地区进行。

在此示例中,有 1000 个帐户,跨 4 个区域,每个区域有 2 个子联盟,然后是帐户的不同所有者 -- 一些帐户是无主的。每个帐户都有一个介于 1,000 和 100,000 之间的随机值。

可重现的例子:

帐户列表:

set.seed(1)
Accounts <- paste0("Acc", 1:1000)
Region <- c("NorthEast", "SouthEast", "MidWest", "West")
League <- sample(c("Majors", "Minors"), 1000, replace = TRUE)
AccValue <- sample(1000:100000, 1000, replace = TRUE)
Owner <- sample(c("Chad", NA, "Jimmy", "Adrian", NA, NA, "Steph", "Matt", "Jared", "Eric"), 1000, replace = TRUE)
AccDF <- data.frame(Accounts, Region, League, AccValue, Owner)
AccDF$Accounts <- as.character(AccDF$Accounts)
AccDF$Region <- as.character(AccDF$Region)
AccDF$League <- as.character(AccDF$League)
AccDF$Owner <- as.character(AccDF$Owner)

地区所有权摘要:

Summary <- AccDF %>%
  group_by(Region, League, Owner) %>%
  summarise(Count = n(),
            TotalValue = sum(AccValue))

按地区、联赛汇总:

Summary2 <- AccDF %>%
  group_by(Region, League) %>%
  summarise(Count = n(),
            TotalValue = sum(AccValue),
            AccountsPerRep = round(Count / 7, 0),
            ValuePerRep = TotalValue / 7)

这就是所有的起始数据,我想对Summary2表的每个分组做以下处理。

西部未成年人示例:

西部未成年人账户总数:120

#break out into owned and unowned

WestMinorsOwned <- AccDF %>%
  filter(Region == "West",
         League == "Minors",
         !is.na(Owner))

WestMinorsUnowned <- AccDF %>%
  filter(Region == "West",
         League == "Minors",
         is.na(Owner))

#unassign accounts until threshold is hit

New.WestMinors <- WestMinorsOwned %>% 
  mutate(r = runif(n())) %>% 
  arrange(r) %>% 
  group_by(Owner) %>% 
  mutate(NewOwner = replace(Owner, cumsum(AccValue) > 600000 | row_number() > 14, NA)) %>% 
  ungroup(Owner) %>%
  mutate(Owner = NewOwner) %>%
  select(-r, -NewOwner)

在所有者更新后,我们将各个部分重新绑定在一起,以使 WestMinors 帐户库具有更新的所有者,希望平衡。

AssignableWestMinors <- bind_rows(filter(AccDF, Region == "West" & League == "Minors" & is.na(Owner)), 
                                  filter(New.WestMinors, is.na(Owner))) %>%
  arrange(desc(AccValue))

#check work
OwnerSummary <- New.WestMinors %>%
  filter(!is.na(Owner)) %>%
  group_by(Region, League, Owner) %>%
  summarise(Count = n(), TotalValue = sum(AccValue))

没有人拥有超过 14 个帐户或 600,000 个帐户,因此我们可以开始重新分配无主帐户以尝试平衡所有人。下面的 for 循环查看 OwnerSummary 中的每个名称,找出分配给他们的 $$ 最小的人并分配最有价值的帐户,然后遍历每个帐户,尝试平衡每个所有者的份额。

#Balance Unassigned

for (i in 1:nrow(AssignableWestMinors)){
  idx <- which.min(OwnerSummary$TotalValue)
  OwnerSummary$TotalValue[idx] <- OwnerSummary$TotalValue[idx] + AssignableWestMinors$AccValue[i]
  OwnerSummary$Count[idx] <- OwnerSummary$Count[idx] + 1
  AssignableWestMinors$Owner[i] <- as.character(OwnerSummary$Owner[idx])}

现在我们只需将先前拥有的和新分配的绑定在一起,我们就完成了平衡的 West Minors 领土。

WestMinors.Final <- bind_rows(filter(New.WestMinors, !is.na(Owner)), AssignableWestMinors)

WM.Summary <- WestMinors.Final %>%
  group_by(Region, League, Owner) %>%
  summarise(Count = n(),
            TotalValue = sum(AccValue))

每个人的帐户数量都差不多,总的 $$ 区域都在合理范围内。

现在我正在尝试对最初的 4 个地区、2 个联赛的每个分组进行此操作。所以这样做8次,然后把它们缝合在一起。每个子组都有不同的 $$ 价值阈值,以及帐户数量。如何将原始帐户库拆分为 8 个部分,应用所有这些部分,然后将其重新组合在一起?

【问题讨论】:

  • 也许尝试将其全部包装在split(AccDF, paste(AccDF$Region, AccDF$League, sep = ".")) %&gt;% lapply({ # Here goes your code }) %&gt;% bind_rows()

标签: r for-loop purrr split-apply-combine pmap


【解决方案1】:

您应该利用?dplyr::do 对Region-League 的子集执行您想要的split-apply-combine 操作。首先,使您的逻辑功能化,以便它可以在数据帧dta 上运行,该数据帧表示主数据帧AccDF 的子集版本。

reAssign <- function(dta) {
  other_acct <- dta %>% 
    filter(!is.na(Owner)) %>% 
    mutate(r = runif(n())) %>% 
    arrange(r) %>% 
    group_by(Owner) %>% 
    mutate(NewOwner = replace(Owner, cumsum(AccValue) > 600000 | row_number() > 14, NA)) %>% 
    ungroup(Owner) %>%
    mutate(Owner = NewOwner) %>%
    select(-r, -NewOwner)

  assignable_acct <- other_acct %>% 
    filter(is.na(Owner)) %>% 
    bind_rows( filter(dta, is.na(Owner)) ) %>% 
    arrange(desc(AccValue))

  acct_summary <- other_acct %>%
    filter(!is.na(Owner)) %>%
    group_by(Owner) %>%
    summarise(Count = n(), TotalValue = sum(AccValue))

  # I have a feeling there's a much better way of doing this, but oh well...  
  for (i in seq(nrow(assignable_acct))) {
    idx <- which.min(acct_summary$TotalValue)
    acct_summary$TotalValue[idx] <- acct_summary$TotalValue[idx] + assignable_acct$AccValue[i]
    acct_summary$Count[idx] <- acct_summary$Count[idx] + 1
    assignable_acct$Owner[i] <- as.character(acct_summary$Owner[idx])
  }
  final <- other_acct %>% 
    filter(!is.na(Owner)) %>% 
    bind_rows(assignable_acct)

  return(final)
}

然后简单地将其应用于已按地区、联赛分组的 AccDF。

new_master <- AccDF %>% 
  group_by(Region, League) %>% 
  do( reAssign(.) ) %>% 
  ungroup() 

检查以确保它完成了它的工作......

new_master %>% 
  group_by(Region, League, Owner) %>%
  summarise(Count = n(),
          TotalValue = sum(AccValue)) %>% 
  as.data.frame()

【讨论】:

  • 我会试试这个。非常感谢!
  • 所以我认为我唯一的另一个问题是如何在 ReAssign 函数的第一部分更新单个 $$ 和计数阈值。我将能够从完整的 dta 中获得一个汇总表,其中显示每个区域联赛分组的计数和 $$ 阈值。我可以通过函数的每次应用以某种方式引用它吗?
猜你喜欢
  • 2014-12-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-03-12
  • 1970-01-01
  • 1970-01-01
  • 2017-12-14
相关资源
最近更新 更多