【问题标题】:R algorithm to count days lapsed between phases in a nonlinear processR算法计算非线性过程中各个阶段之间的天数
【发布时间】:2017-04-07 22:18:23
【问题描述】:

这是我第一次发帖,但我想我已经遵守了所有规则。如果没有,请告诉我。

我正在尝试创建一个数据框,其中包含从名为 changelist 的列表中的每个元素(唯一 ECO #)推断出来的信息。举个例子:

> changelist[560] $E149914 ECO STATUS Timestamp 25014 E149914 Material Disposition 2017-01-24 25015 E149914 Released 2016-12-20 25016 E149914 CCB 2016-12-20 25017 E149914 Submitted 2016-12-16 25018 E149914 Technical Review 2016-12-14 25019 E149914 Pending 2016-12-15 25020 E149914 CCB 2016-12-14 25021 E149914 Submitted 2016-12-13 25022 E149914 Technical Review 2016-12-12 25023 E149914 Pending 2016-12-13 25024 E149914 Technical Review 2016-12-13 25025 E149914 Pending 2016-12-13 25026 E149914 Hold 2016-12-13 25027 E149914 CCB 2016-11-30 25028 E149914 Submitted 2016-11-30 25029 E149914 Technical Review 2016-11-30 25030 E149914 Pending 2016-11-24 25031 E149914 Unassigned 2016-10-19

生成的数据框(我们称之为“data.frame”)将有 5 列:

  1. ECO:独特的 ECO #

  2. TRCount: ECO 经过了多少次技术审查

  3. CCBCount:ECO在CCB下经历了多少次

  4. TRDays:在技术审查中花费的总天数(在每个 TRCount 中花费的所有天数的总和)

  5. CCBDays:在 CCB 中花费的总天数(在每个 CCBCount 中花费的所有天数的累计总和)

这是我目前所拥有的:

for (i in 1:length(changelist)){
ECO[i] = as.character(changelist[[i]]$ECO[1])
TRCount[i] = length(which(changelist[[i]]$STATUS == "Technical Review"))
CCBCount[i] = nrow(subset(changelist[[i]], grepl(paste("CCB", collapse="|"), changelist[[i]]$STATUS)))}

这让我明白了:

> data.frame[560,] ECO TRCount CCBCount 560 E149914 4 3

我在使用 TRDays 和 CCBDays 时遇到了问题。变更列表中的每个 ECO 都会经历类似的过程(从技术评审开始,到 CCB,然后发布)。然而,这个过程的执行方式并不总是线性的。流程中的每个点之间都有滞后期(称为待处理/已提交)。有时,技术审查或 CCB 可能会被拒绝,流程将重新开始,或者该流程将在技术审查或 CCB 处循环几次,然后再进入下一阶段。所有这些变化都可以在上面的 ECO149914 示例中看到。

我认为代码可能是这样写的:

从数据框底部开始搜索

  1. 在更改列表[[560]]$STATUS 中查找“技术审查”的第一次出现。存储索引 (a)。

  2. 在行索引 (a) 上方的行中搜索更改列表 [[560]]$STATUS 中下一次出现的“技术审查”或“CCB”。存储下一次出现的索引 (b)。

  3. 那么在技术评审中花费的时间长度就是 TRDays = abs(changelist[[560]]$Timestamp[b]-changelist[[560]]$Timestamp[a])。

  4. 在 changelist[[560]]$STATUS 的行索引 (b) 上方的行中查找“技术审查”、“CCB”或“已发布”的下一个匹配项。存储索引 (c)。

    • 如果 changelist[[560]]$STATUS[b] 给出“技术审查”,TRDays = TRDays + abs(changelist[[560]]$Timestamp[c]-changelist[[560]]$Timestamp [b])

    • 如果 changelist[[560]]$STATUS[b] 给出“CCB”,CCBDays = abs(changelist[[560]]$Timestamp[c]-changelist[[560]]$Timestamp[b] )

  5. 在行索引 (c) 上方的行中搜索 changelist[[560]]$STATUS 中下一次出现的“Technical Review”、“CCB”或“Released”。将此索引存储为 (d)。

    • 如果 changelist[[560]]$STATUS[c] 给出“技术审查”,TRDays = TRDays + abs(changelist[[560]]$Timestamp[d]-changelist[[560]]$Timestamp [c])

    • 如果 changelist[[560]]$STATUS[c] 给出“CCB”,CCBDays = CCBDays + abs(changelist[[560]]$Timestamp[d]-changelist[[560]]$Timestamp[ c])

    • 如果 changelist[[560]]$STATUS[c] 给出“已发布”,CCBDays = CCBDays + abs(changelist[[560]]$Timestamp[d]-changelist[[560]]$Timestamp[ c]) 并终止循环。

    • 如果 changelist[[560]]$STATUS[c] 没有给出“已发布”,请重复步骤 5。

问题是我不确定这是最有效的逻辑。如果它有效,我不知道如何将它翻译成 R 代码。我首先在逻辑中寻找建议,然后在 R 中寻找可能有助于翻译逻辑的函数/包。也欢迎其他 cmets。

感谢您的帮助。

【问题讨论】:

    标签: r algorithm time


    【解决方案1】:

    这可以使用data.table 而不是for 循环来完成,以产生以下输出:

    #        ECO           STATUS number_of_times total_days
    # 1: E149914              CCB               3     6 days
    # 2: E149914 Technical Review               4    14 days
    

    我已经尝试在以下代码中添加 cmets 以方便理解,建议您检查中间对象以了解逻辑:

    library(data.table)
    dt <- structure(list(eco = c("E149914", "E149914", "E149914", "E149914", 
    "E149914", "E149914", "E149914", "E149914", "E149914", "E149914", 
    "E149914", "E149914", "E149914", "E149914", "E149914", "E149914", 
    "E149914", "E149914"), status = c("Unassigned", "Pending", "CCB", 
    "Submitted", "Technical Review", "Technical Review", "Submitted", 
    "Pending", "Technical Review", "Pending", "Hold", "Technical Review", 
    "CCB", "Pending", "Submitted", "Released", "CCB", "Material Disposition"
    ), timestamp = structure(c(17093, 17129, 17135, 17135, 17135, 
    17147, 17148, 17148, 17148, 17148, 17148, 17149, 17149, 17150, 
    17151, 17155, 17155, 17190), class = "Date")), .Names = c("ECO", 
    "STATUS", "Timestamp"), row.names = c(NA, -18L), class = "data.frame", index = structure(integer(0), "`__status`" = c(3L, 
    13L, 17L, 11L, 18L, 2L, 8L, 10L, 14L, 16L, 4L, 7L, 15L, 5L, 6L, 
    9L, 12L, 1L)))
    setDT(dt)
    
    # Set Timestamp to Date class and order by Timestamp (ascending)
    dt[, Timestamp := as.Date(Timestamp, format = "%Y-%m-%d")]
    setorder(dt, Timestamp)
    
    # Count number of rows with these status names
    status_names <- c("Technical Review", "CCB")
    dt_count <- dt[STATUS %in% status_names,
      .(number_of_times = .N), by = .(ECO, STATUS)]
    
    #        ECO           STATUS number_of_times
    # 1: E149914              CCB               3
    # 2: E149914 Technical Review               4
    
    # Sum time/days by adding an end day (Timestamp frow row below)
    time_break_names <- c(status_names, "Released")
    dt_time <- dt[STATUS %in% time_break_names]
    dt_time[, end := shift(Timestamp, 1, type = "lead")]
    dt_time[, days := end - Timestamp]
    
    #        ECO           STATUS  Timestamp        end    days
    # 1: E149914              CCB 2016-11-30 2016-11-30  0 days
    # 2: E149914 Technical Review 2016-11-30 2016-12-12 12 days
    # 3: E149914 Technical Review 2016-12-12 2016-12-13  1 days
    # 4: E149914 Technical Review 2016-12-13 2016-12-14  1 days
    # 5: E149914 Technical Review 2016-12-14 2016-12-14  0 days
    # 6: E149914              CCB 2016-12-14 2016-12-20  6 days
    # 7: E149914         Released 2016-12-20 2016-12-20  0 days
    # 8: E149914              CCB 2016-12-20       <NA> NA days
    
    dt_time <- dt_time[STATUS %in% status_names,
      .(total_days = sum(days, na.rm = TRUE)), by = .(ECO, STATUS)]
    
    #        ECO           STATUS total_days
    # 1: E149914              CCB     6 days
    # 2: E149914 Technical Review    14 days
    
    # Merge counts and time
    dt_out <- dt_count[dt_time, on = c("ECO", "STATUS")]
    

    请注意,例如2016-11-30 至 2016-11-30 的第一次建行审核计为 0 天。如果您希望它计为 1 天,则需要修改此行:

    dt_time[, days := 1 + end - Timestamp]
    

    【讨论】:

    • 感谢您的回答。这个特定 ECO(更改列表中的第 506 个)的解决方案非常明确。但是,我有 5003 个 ECO 的列表。我如何概括您编写的内容以迭代更改列表中的每个 ECO?
    • 首先使用dt &lt;- rbindlist(changelist, use.names = TRUE, fill = TRUE)从您的列表中创建一个data.table。然后只需运行答案中的代码。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-29
    • 1970-01-01
    相关资源
    最近更新 更多