How to monitor progress of an apply function?
我需要计算出一个 2886*2886 的相关矩阵,问题是构建中间数据表 (
这里是代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | SOURCE=data.table(NAME=rep(paste0("NAME", as.character(1:2889)), each=600), VALUE=sample(c(TRUE,FALSE), 600, TRUE) ) > SOURCE NAME VALUE 1: NAME1 TRUE 2: NAME1 TRUE 3: NAME1 TRUE 4: NAME1 TRUE 5: NAME1 TRUE --- 1733396: NAME999 TRUE 1733397: NAME999 TRUE 1733398: NAME999 TRUE 1733399: NAME999 TRUE 1733400: NAME999 FALSE setkey(SOURCE,NAME) a=SOURCE[,unique(NAME)] COMB=data.table(expand.grid(a,a, stringsAsFactors=FALSE)) > COMB Var1 Var2 1: NAME1 NAME1 2: NAME10 NAME1 3: NAME100 NAME1 4: NAME1000 NAME1 5: NAME1001 NAME1 --- 8346317: NAME995 NAME999 8346318: NAME996 NAME999 8346319: NAME997 NAME999 8346320: NAME998 NAME999 8346321: NAME999 NAME999 append <- function(X) { data.table(NAME1=X[1], VALUE1=SOURCE[X[1], VALUE], NAME2=X[2], VALUE2=SOURCE[X[2], VALUE] ) } RESULT=rbindlist(apply(COMB, 1, append)) |
有什么想法吗?
您还知道是否有更快的方法从
带有
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | SOURCE=SOURCE[sample(1:nrow(SOURCE), 3)] setkey(SOURCE,NAME) a=SOURCE[,unique(NAME)] COMB=data.table(expand.grid(a,a, stringsAsFactors=FALSE)) RESULT=rbindlist(apply(COMB, 1, append)) > RESULT NAME1 VALUE1 NAME2 VALUE2 1: NAME1859 TRUE NAME1859 TRUE 2: NAME768 FALSE NAME1859 TRUE 3: NAME795 TRUE NAME1859 TRUE 4: NAME1859 TRUE NAME768 FALSE 5: NAME768 FALSE NAME768 FALSE 6: NAME795 TRUE NAME768 FALSE 7: NAME1859 TRUE NAME795 TRUE 8: NAME768 FALSE NAME795 TRUE 9: NAME795 TRUE NAME795 TRUE |
稍后我将执行
所以也许整个过程可以更有效地完成,谁知道呢。
您可以使用库
就您的问题而言:
1 2 3 4 | library(pbapply) library(data.table) result <- data.table::rbindlist( pbapply(COMB, 1, append) ) |
ps。这个答案解决了你的两个初始点。关于第三点,我不确定是否可以暂停该功能。无论如何,您的操作确实花费了太长时间,因此我建议您发布一个单独的问题,询问如何优化您的任务。
您可以使用
1 2 3 4 5 6 7 | total <- 50 pb <- txtProgressBar(min = 0, max = total, style = 3) lapply(1:total, function(i){ Sys.sleep(0.1) setTxtProgressBar(pb, i) }) |
或使用
中的
1 2 | library(plyr) laply(1:100, function(i) {Sys.sleep(0.05); i}, .progress ="text") |
查看
试试这个:
1 2 3 4 | setkey(SOURCE, NAME) SOURCE[, CJ(NAME, NAME, unique = T)][ , mean(SOURCE[V1, VALUE] == SOURCE[V2, VALUE]), by = .(V1, V2)] |
Fwiw,全大写的名字在 imo 中是一个糟糕的选择——让编写和阅读代码变得更加困难。
对于花哨的进度条(不在基础/标准库中),还有
1 2 3 4 5 6 7 8 9 | pb <- progress_bar$new( format =" downloading [:bar] :percent eta: :eta", total = 100, clear = FALSE, width= 60) for (i in 1:100) { pb$tick() Sys.sleep(1 / 100) } #> downloading [========----------------------] 28% eta: 1s |
所以这满足要求 (1) 和 (2),而不是 (3)。对于缓存中间结果,不时将内容写入磁盘可能是最简单的。对于快速序列化,您可以尝试
-
fst :方便序列化data.tables 等列式数据结构 -
qs 用于更一般的对象序列化
我希望这会有所帮助。
我刚刚编写了自己的文本进度线实现。我不知道
我在解决这个问题时学到了一些非常有用的东西。我最初计划依靠 terminfo 进行光标控制。具体来说,我打算使用
预先计算当前终端的代码以向左移动光标
1 | tc_left <- system2('tput','cub1',stdout=T); |
然后我将重复打印该代码以在每次更新后将光标重置到进度行的开头。此解决方案有效,但仅适用于安装了正确 terminfo 数据库的 Unix 终端;它不适用于其他平台,尤其是 Windows 上的 RStudio。
然后,当我查看
');
这是我的解决方案。它涉及一个名为
开头的名称简单地转储到全局环境中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | progInit <- function(N,dec=3L) { progStart <<- Sys.time(); progI <<- 1L; progN <<- N; progDec <<- dec; }; ## end progInit() prog <- function() { rem <- unclass(difftime(Sys.time(),progStart,units='secs'))*(progN/progI-1); days <- as.integer(rem/86400); rem <- rem-days*86400; hours <- as.integer(rem/3600); rem <- rem-hours*3600; minutes <- as.integer(rem/60); rem <- rem-minutes*60; seconds <- as.integer(rem); rem <- rem-seconds; millis <- as.integer(rem*1000); over <- paste(collapse='',rep(' ',20L)); pct <- progI/progN*100; if (days!=0L) { msg <- sprintf(' %.*f%% %dd/%02d:%02d:%02d.%03d%s', progDec,pct,days,hours,minutes,seconds,millis,over); } else { msg <- sprintf(' %.*f%% %02d:%02d:%02d.%03d%s', progDec,pct,hours,minutes,seconds,millis,over); }; ## end if cat('\ '); cat(msg); cat('\ '); progI <<- progI+1L; }; ## end prog() |
1 2 3 4 5 6 7 8 9 10 11 | library(data.table); SOURCE <- data.table(NAME=rep(paste0("NAME", as.character(1:2889)), each=600), VALUE=sample(c(TRUE,FALSE), 600, TRUE) ); setkey(SOURCE,NAME); a <- SOURCE[,unique(NAME)]; COMB <- data.table(expand.grid(a,a, stringsAsFactors=FALSE)); append <- function(X) { prog(); data.table(NAME1=X[1],VALUE1=SOURCE[X[1],VALUE],NAME2=X[2],VALUE2=SOURCE[X[2],VALUE]); }; ## end append() ##x <- COMB; progInit(nrow(x)); rbindlist(apply(x,1,append)); ## full object x <- COMB[1:1e4,]; progInit(nrow(x)); rbindlist(apply(x,1,append)); ## ~30s |
我使用一个简单的算法来估计剩余时间:我基本上将总经过时间除以到目前为止完成的迭代次数(得到时间/迭代),然后将其乘以剩余迭代次数。
不幸的是,当我在完整的
您是否要进行交叉连接?请参阅此示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | #dummy data set.seed(1) SOURCE = data.frame( NAME = sample(paste0("Name", 1:4),20, replace = TRUE), VALUE = sample(c(TRUE,FALSE), 20, replace = TRUE) ) #update colnames for join d1 <- SOURCE colnames(d1) <- c("NAME1","VALUE1") d2 <- SOURCE colnames(d2) <- c("NAME2","VALUE2") #cross join merge(d1, d2, all = TRUE) |