【问题标题】:R - Optimizing loop operation on long table formatR - 优化长表格式的循环操作
【发布时间】:2016-09-02 14:12:04
【问题描述】:

我有一个包含大约 120 万行的长格式表格数据,格式如下

+-----------+-------+ |进程 ID |活动 | +-----------+-------+ | 111 |一个 | | 111 |乙| | 111 | C | | 111 | D | | 111 | E | | 112 |一个 | | 112 |乙| | 112 | D | | 112 | E | | 113 |一个 | | 113 |乙| | 113 | C | | 113 | D | | 113 | E | +-----------+-------+

事件已经按它们的时间戳排序,我想将每个进程 ID 的进程流字符串从长格式表生成到另一个表的单独列中,如下所示

流程 B->C->D->E' , 'A->B->D->E' ,'A->B->C->D->E ' ,..等等)

我尝试了以下代码行。但在我的核心 i3、4GB RAM 笔记本电脑中,它们每个都需要将近 850 秒。有什么替代方法可以更快地做到这一点? 任何指导都会有所帮助

版本 1 使用 dplyr 包

state_flow_identifier <- function(x){
y <-filter(data_longformat,process_id==x)
y_v <- as.vector(y$Event)
as.character(paste(y_v,collapse = '->'))
}

processflow_detection <- mutate(processflow_detection,processflow = apply(processflow_detection['process_id'],1,function(x)state_flow_identifier(x)))

版本 2 使用 foreach 包

processflow <- foreach(i=processflow_detection$process_id,.combine='c') %do% state_flow_identifier(i)

谢谢。

【问题讨论】:

    标签: r optimization foreach dplyr


    【解决方案1】:

    您可以使用dplyr 尝试类似的操作,它是group_by 函数:

    library(dplyr)
    df %>%
      group_by(ProcessId) %>%
      summarise(eventFlow = paste(Event, collapse = ' -> '))
    

    输出如下:

    Source: local data frame [3 x 2]
    
      ProcessId             eventFlow
          (dbl)                 (chr)
    1       111 A -> B -> C -> D -> E
    2       112 A -> B -> C -> D -> E
    3       113 A -> B -> C -> D -> E
    

    注意,我使用这个数据框作为输入,因为你的格式不是输入到 R 中的:

    df <- data.frame(ProcessId = c(rep(111, 5), rep(112, 5), rep(113, 5)), Event = rep(c('A', 'B', 'C', 'D', 'E'), 3))
    df
       ProcessId Event
    1        111     A
    2        111     B
    3        111     C
    4        111     D
    5        111     E
    6        112     A
    7        112     B
    8        112     C
    9        112     D
    10       112     E
    11       113     A
    12       113     B
    13       113     C
    14       113     D
    15       113     E
    

    【讨论】:

    • 非常感谢。您的回答帮助我将执行时间减少到不到 10 秒。
    【解决方案2】:

    您不需要任何库。

    df <- data.frame(ProcessId=c(rep(111,5),rep(112,4),rep(113,5)),Event=unlist(strsplit("ABCDEABDEABCDE","")))
    len <- nrow(df)
    new_process_id <- c(TRUE, df$ProcessId[-len] != df$ProcessId[-1])
    sym <- rep(" -> ", len)
    sym[new_process_id] <- ","
    str <- paste(sym, df$Event, sep="", collapse="")
    data.frame(ProcessId=rle(df$ProcessId)$val,EventFlow=unlist(strsplit(str,","))[-1])
    

    输出:

      ProcessId             EventFlow
    1       111 A -> B -> C -> D -> E
    2       112      A -> B -> D -> E
    3       113 A -> B -> C -> D -> E
    

    对于 125 万行,在我的笔记本电脑上执行时间约为 2 秒

    【讨论】:

    • 他的代码的实际执行时间不到一秒。整个 ETL 时间缩短到不到 10 秒。我的不好,我不明确。不过感谢您的投入。
    【解决方案3】:

    您还应该查看data.table 以提高效率,(使用@Gopala 的数据框)

    library(data.table)
    setDT(df)[, .(event_flow = paste(Event, collapse = '->')), by = ProcessId]
    #   ProcessId    event_flow
    #1:       111 A->B->C->D->E
    #2:       112 A->B->C->D->E
    #3:       113 A->B->C->D->E
    

    【讨论】:

    • 感谢您在 0.47 秒内得到 system.time 输出。对于@Gopala 的回答,命令运行时间或多或少相同(0.49)。因为我已经将他的回复标记为已回答.. 我就这样离开了:-)。
    猜你喜欢
    • 1970-01-01
    • 2020-10-09
    • 1970-01-01
    • 1970-01-01
    • 2022-01-24
    • 2020-10-22
    • 2020-05-20
    • 2016-02-18
    • 2020-06-03
    相关资源
    最近更新 更多