8

这对我来说非常有用。我可以ls()按日期(上次修改或类似的东西)对输出进行排序吗?

背景:我有一个非常凌乱的工作区,里面装满了各种data.frames,variablesplots. 我需要找到一个data.frame,但我不记得我叫它什么了,只记得我最近正在研究它。因此ls()按修改日期排序将帮助我弄清楚我所说的。

澄清一下:这不是关于使用history(). 我经常使用历史记录,并且经常在我认为可能需要时保存它。在这种情况下,历史记录不涵盖所需的时间,所以我找不到data.frameusing history().

附加:除了查找最近创建的既定任务之外data.frame,一般来说,能够ls()根据日期进行排序将非常有用。我工作了 2 年多的工作空间中有 100 多个对象(搜索 2 年history听起来也不好玩)。如果可以将这些对象按时间顺序排序,那么我就会知道哪些是较新的(可能是经过编辑的),哪些是较旧的(可能是原始的)。

我试图通过将单个对象缓慢移动到较小的相关工作区来改进我的工作流程。但是这个过程需要时间,而且基本上没有意义(因为我已经接近数据分析的尾声了)。

4

6 回答 6

4

您可能会尝试使用该makeActiveBinding函数自动记录对感兴趣变量的修改。然后,您可以使用日志ls()按修改时间对输出进行排序。

需要注意的是,使用这种方法,必须在首次使用变量之前设置跟踪。

.change.log <- list()
track <- function(variable) {
    makeActiveBinding(variable,
        function(v) 
            if (! missing(v)) 
            .change.log[[variable]] <<- c(.change.log[[variable]], 
                                           as.list(Sys.time())),
        .GlobalEnv)
}

track('x')
x <- 1
.change.log
x <- 2
.change.log

每次x修改时,提供给的匿名函数makeActiveBinding都会被调用为v等于新值。这个函数在x被引用时也会被调用,但在这种情况下没有提供任何东西v,因此条件与missing(v)--- 我们只想在值更改时更新日志。


编辑

经过进一步考虑,更好的替代方法makeActiveBinding是通过函数安装修改记录器addTaskCallback。下面的代码创建了一个自动记录器,每次<-在顶层使用运算符时,它都会按变量名记录时间戳。

# define a log maker function. This returns a new logger function
# bound with a fresh log.
mk.log <- function() {
    log <- list()
    # handler functions have to have these four args, but we only use the first.
    function(expr, value, ok, visible) {
        if (class(expr) == '<-') {
            # convert the assignment call to a list, so the 
            # variable name can be extracted
            call.list <- as.list(expr)
            # extract the name of the variable being affected, and 
            # convert it to character, so we can use it as a list name
            variable <- as.character(call.list[[2]])
            # append a timestamp to the log for this variable
            log[[variable]] <<- c(log[[variable]], list(Sys.time()))
        }
        # callback handlers need to return a bool
        return(TRUE)
    }
}

# assign the handler to .log, and install it.
addTaskCallback(.log <- mk.log(), name='log')

x <- 5
x <- 10
y <- 4

# read the log
environment(.log)$log

# $x
# $x[[1]]
# [1] "2013-01-25 10:24:26.581 EST"
# 
# $x[[2]]
# [1] "2013-01-25 10:24:26.585 EST"
# 
# 
# $y
# $y[[1]]
# [1] "2013-01-25 10:24:26.589 EST"
于 2013-01-23T14:44:44.910 回答
3

好吧,通过一点创造性的黑客攻击,您可以为变量编写自己的方法。例如:

datedmatrix<-function(data,nrow,ncol,...) {
    output <- matrix(data, nrow=nrow,ncol=ncol,...)
    attr(output,'create') <- date()
    return(output)
}
于 2013-01-23T14:10:28.767 回答
2

不,但您应该使用该history函数通过您运行的最新命令找到它的名称。

默认情况下,history将显示最后 25 行代码,但您可以通过以下方式请求更多:

history(max.show = 100)

您可以显示的行数也有硬性限制。它等于R_HISTSIZE默认为 512 的环境变量的值。但正如文档所述:

会话期间保留的历史记录行数没有限制 [...]

所以你可以这样做:

Sys.setenv("R_HISTSIZE" = 10000)
history(max.show = 10000)

并且您应该能够看到自您开始会话以来的所有历史记录(假设您运行的代码少于 10000 行。)

于 2013-01-23T11:59:50.037 回答
1

你可以使用ls.str(mode="list").

示例输出:

b : 'data.frame':   1 obs. of  1 variable:
 $ test: Factor w/ 1 level "a": 1
c : 'data.frame':   1 obs. of  1 variable:
 $ x: num 1

我不认为创建时间与任何 R 对象一起存储。

于 2013-01-23T12:15:19.930 回答
1

这是一个想法,我们创建一个日志,所有使用的操作:=都将存储在那里:

`:=` <- function(e1,e2){
  log <- data.frame(
    var = paste(collapse="\n",deparse(substitute(e1))),
    call=  paste(collapse="\n",deparse(substitute(e2))),
    time = Sys.time()
  )
  if(exists(".log",envir = .GlobalEnv)){
    assign(".log", 
           rbind(get(".log", envir = .GlobalEnv), log), 
           envir = .GlobalEnv)
  } else {
    assign(".log", log, envir = .GlobalEnv)
  }  
  eval.parent(do.call(
    substitute, list(match.call(), list(`:=` = quote(.Primitive("<-"))))))
}

x := 1
x := x+2
x
# [1] 3
.log
#   var  call                time
# 1   x     1 2019-02-26 12:17:24
# 2   x x + 2 2019-02-26 12:17:25

通过一些调整,我们还可以记录<-在全局环境中所做的每个分配,但它会减慢 R。

`<-` <- function(e1,e2){
  if(identical(parent.frame(), .GlobalEnv)){
    log <- data.frame(
      var = paste(collapse="\n",deparse(substitute(e1))),
      call=  paste(collapse="\n",deparse(substitute(e2))),
      time = Sys.time()
    )
    if(exists(".log",envir = .GlobalEnv)){
      assign(".log", 
             rbind(get(".log", envir = .GlobalEnv), log), 
             envir = .GlobalEnv)
    } else {
      assign(".log", log, envir = .GlobalEnv)
    }    
  } 

  eval.parent(do.call(substitute, list(
    match.call(), list(`<-` = quote(.Primitive("<-"))))))
}

rm(.log)
var <- 1
var <- var +1
var
fun <- function(x) {y <- x+1; y}
var2 <- fun(var)
var
# [1] 2
var2
# [1] 3
.log
#    var                                    call                time
# 1  var                                       1 2019-02-26 12:52:13
# 2  var                                 var + 1 2019-02-26 12:52:13
# 3  fun function(x) {\n    y <- x + 1\n    y\n} 2019-02-26 12:52:14
# 4 var2                                fun(var) 2019-02-26 12:52:14
于 2019-02-26T11:54:35.360 回答
0

这不是一个直接的答案,但我个人使用 RStudio。

Rstudio 有一个选项卡历史记录(主要使用历史 R 命令)和一个非常好的搜索选项。

在这里,我在我的历史中搜索“源”这个词。 在此处输入图像描述

要获得更多详细信息,我可以查看这段历史中每一行的上下文。例如这里第一行的细节。 在此处输入图像描述

于 2013-01-23T12:06:03.500 回答