【问题标题】:How can I write an efficient code that creates a calendar in R?如何编写在 R 中创建日历的高效代码?
【发布时间】:2018-09-05 14:45:34
【问题描述】:

我的目标是编写一个更高效的代码,创建一个日历,将经销商的客户分配到不同的日子,以便:

  1. 每天至少有min 客户和(min 取决于经销商)
  2. 所有日子每天最多有max 客户和(max 取决于经销商)
  3. 每当客户被转移到不同的日子时,他都应该被转移到可能的最近的那一天(不要担心关系 - 如果距离相同,那么前 1 天或后 1 天是相同的)李>

例子:

dealer_id  <- rep(c("ABC123","DEF234","GHJ456"), each = 4)
date       <- as.Date(rep(c("2018-01-01", "2018-01-02", "2018-01-03", "2018-01-04"), times = 3))
cust_pos_1 <- c("MCA1", "MCA2", "MCA3", "MCA4", "MCA5", "MCA6", NA, NA, "MCA9", "MCA10", "MCA11", "MCA12")
cust_pos_2 <- c("MCB1", "MCB2", NA, NA, "MCB5", NA, NA, NA, "MCB9", NA, "MCB11", NA)
cust_pos_3 <- c("MCC1", "MCC2", NA, NA, NA, NA, NA, NA, "MCC9", NA, NA, NA)

df         <- data.frame(dealer_id, date, cust_pos_1, cust_pos_2, cust_pos_3)

settings   <- data.frame(dealer_id = c("ABC123","DEF234","GHJ456"), min_daily = c(2, 0, 1), max_daily = c(3, 1, 2))

为我们提供输入数据和经销商设置:

dealer_id date       cust_pos_1 cust_pos_2 cust_pos_3
ABC123    2018-01-01 MCA1       MCB1       MCC1
ABC123    2018-01-02 MCA2       MCB2       MCC2
ABC123    2018-01-03 MCA3       NA         NA
ABC123    2018-01-04 MCA4       NA         NA
DEF234    2018-01-01 MCA5       MCB5       NA
DEF234    2018-01-02 MCA6       NA         NA
DEF234    2018-01-03 NA         NA         NA
DEF234    2018-01-04 NA         NA         NA
GHJ456    2018-01-01 MCA9       MCB9       MCC9
GHJ456    2018-01-02 MCA10      NA         NA
GHJ456    2018-01-03 MCA11      MCB11      NA
GHJ456    2018-01-04 MCA12      NA         NA

dealer_id min_daily max_daily
ABC123    2         3
DEF234    0         1
GHJ456    1         2

代码运行后的输出数据应该是这样的:

dealer_id date       cust_pos_1 cust_pos_2 cust_pos_3
ABC123    2018-01-01 MCA1       MCB1       NA
ABC123    2018-01-02 MCA2       MCB2       NA
ABC123    2018-01-03 MCA3       MCC1       NA
ABC123    2018-01-04 MCA4       MCC2       NA
DEF234    2018-01-01 MCA5       NA         NA
DEF234    2018-01-02 MCA6       NA         NA
DEF234    2018-01-03 MCB5       NA         NA
DEF234    2018-01-04 NA         NA         NA
GHJ456    2018-01-01 MCA9       MCB9       NA
GHJ456    2018-01-02 MCA10      MCC9       NA
GHJ456    2018-01-03 MCA11      MCB11      NA
GHJ456    2018-01-04 MCA12      NA         NA

由于设置 - 必须根据上述规则重新分配客户。

设置表也有规则! minmax 之间的差值始终为 1。

可以说有不止一种方法可以解决这个问题,因为我们不在乎客户是否在 x 天前或 x 天后移动,这意味着我们可以变得不同(而且更好! ) 解决方案。

现在。话虽如此,我已经使用一个需要很长时间才能运行的循环解决了这个问题(我的数据框很大——我必须为 150 个经销商和数百个客户创建这个日历 5 年)。

我的问题是:有没有办法使用 dplyrdata.table 或其他方法来加快运行速度?

谢谢。

【问题讨论】:

  • 请分享您的工作代码并要求改进,而不是要求某人提供临时解决方案。
  • 我不能真正分享代码,因为它很长。我应该重新表述问题以询问如何解决,还是应该分享代码的想法,人们可以对此发表评论?
  • 根据设置,ABC123最多可以处理3个,那你为什么要下移MCC1和MCC2呢?
  • 因为 ABC123 的最小值为 2。代码必须首先处理满足最小值,然后不违反最大值

标签: r performance dplyr data.table


【解决方案1】:

下面的代码将填充超出 max_daily 设置范围的客户可接受单元格内的空白区域。但是,一个潜在的问题可能是代码将客户重新定位到远离其原始日期的位置。 提供的代码与 dplyr 管道运算符兼容,速度非常快。

calendar_sort <- function(df){ 


    df <- as.data.frame(df)
    # 
    nr <- nrow(df)
    nc <- ncol(df)
    nc_p <- nc - 2 #if you have more than 2 col for DealerID and Date, change this 

    ttl_cn <- sum(!is.na(df[,3:nc])) # total count of non_NAs 
    mx <- ceiling(ttl_cn / nr)
    rng_nnac <- sum(!is.na(df[,3:(2+mx)])) # count of non-NAs within the range

    left_overs <- df[,(mx+3):nc]
    left_overs <- left_overs[!is.na(left_overs)]

    lo_c <- length(left_overs) # leftover non-NA count
    ttl_s <-  (nr*nc_p) # total number of cells (total space)

    df[,(mx+3):nc] <- NA
    A <- c(left_overs, rep(NA, ttl_s - rng_nnac -lo_c))
    df[is.na(df)] <- A

    B <- df[,3:nc]
    B <- B[!is.na(B)] 
    B <- c(B, rep(NA, ttl_s - length(B)))
    df[,3:nc] <- B

    return(df)
}

result <- df %>% dplyr::group_by(Dealer) %>% do(calendar_sort(.))

【讨论】:

    猜你喜欢
    • 2011-04-04
    • 2021-06-01
    • 2021-05-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-19
    • 2020-01-18
    • 2021-05-24
    相关资源
    最近更新 更多