得到match.call()与* apply& plyr? (re:递归引用数据帧)

时间:2012-11-29 08:18:14

标签: r plyr apply assign sapply

以下功能的目的是允许更容易地进行自引用分配。 (如此处所示:Referencing a dataframe recursively

所以不是

 # this  
 myDataFrame$variable[is.na(myDataFrame$variable)] <- 0

 # we can have this: 
 NAto0(myDataFrame$variable)

这些函数适用于向量,但在* ply'ing

时效果较差

我遇到了关于函数match.call()的{​​{1}}部分的两个问题(代码如下)。问题是:

  1. 如何从函数中确定是否调用了它 来自* apply-type函数?
  2. 如何追踪电话会议 到正确的变量环境?
  3. 我已将参数selfAssign()添加到n,这最终适用于selfAssign(.)语句。我想知道我是否可以某种方式使用eval类似于

    的东西
    n

    也许在selfAssign中有类似 sapply(df, NAto0, n=2) 的东西(我试过,要么我没有把它弄好,要么它不起作用)

    任何建议都会非常感谢。

    <小时/> <小时/>

    功能

    这些函数是selfAssign的包装器,是sys.parent(n)调用中使用的函数。

    *apply

    NAtoNULL <- function(obj, n=1) { # replace NA's with NULL selfAssign(match.call()[[2]], is.na(obj), NULL, n=n+1) } NAto0 <- function(obj, n=1) { # replace NA's with 0 selfAssign(match.call()[[2]], is.na(obj), 0, n=n+1) } NAtoVal <- function(obj, val, n=1) { selfAssign(match.call()[[2]], is.na(obj), val, n=n+1) } ZtoNA <- function(obj, n=1) { # replace 0's with NA # TODO: this may have to be modified if obj is matrix ind <- obj == 0 selfAssign(match.call()[[2]], ind, NA, n=n+1) } 是执行工作的函数,错误来自哪里

    selfAssign

1 个答案:

答案 0 :(得分:1)

注意,我并不赞同这种类型的东西,但是支持理解R如何工作的愿望,以便你可以根据需要做这些事情。

以下仅适用于sapply,因此它只能部分回答您的问题,但它确实列出了您可以采取的策略。正如我在之前的评论中所指出的那样,很难做到这一点,但我可以在sapply电话的具体情况下回答1和2

  1. 使用sys.calls获取跟踪堆栈
  2. 使用sys.framesys.parents获取适当的评估环境
  3. 一种非强大的说明性实现,使用您想要的策略类型将列表中的所有向量转换为NA:

    get_sapply_call <- function(x) get_sapply_call_core(x)  # To emulate your in-between functions
    get_sapply_call_core <- function(x) {
      if((c.len <- length(s.calls <- sys.calls())) < 4L) return("NULL")
      if(s.calls[[c.len - 2L]][[1L]] == quote(lapply) &     # Target sapply calls only
         s.calls[[c.len - 3L]][[1L]] == quote(sapply) &
         s.calls[[c.len - 1L]][[1L]] == quote(FUN)) {
        mc.FUN <- s.calls[[c.len - 1L]]
        mc.sa <- match.call(definition=sapply, s.calls[[c.len - 3L]])  # only need to match sapply b/c other calls are not user calls and as such structure is known
        call.txt <- paste0(
          as.character(mc.sa[[2L]]), "[[", mc.FUN[[2L]][[3L]], 
          "]] <- rep(NA, length(", as.character(mc.sa[[2L]]), "[[", mc.FUN[[2L]][[3L]], 
          "]]))"
        )
        call <- parse(text=call.txt)
        eval(call, envir=sys.frame(sys.parents()[c.len - 3L]))
        return(call.txt)
      }
      return("NULL")
    }
    df <- data.frame(a=1:10, b=letters[1:10])
    sapply(df, get_sapply_call)
    #                                     a                                     b 
    # "df[[1]] <- rep(NA, length(df[[1]]))" "df[[2]] <- rep(NA, length(df[[2]]))" 
    df
    #     a  b
    # 1  NA NA
    # 2  NA NA
    # 3  NA NA
    # 4  NA NA
    # ...
    

    对于不同的*apply函数,您将需要不同的逻辑,如果以某种其他方式间接调用函数,则需要更多不同的逻辑。此外,这绝对是一个快速而又脏的实现,因此即使对于sapply,您也可能需要添加内容以使其更加健壮。并且无法保证sapply实施在将来不会改变以上所有内容。

    编辑:请注意,您完全可以回避match.call

    带来的问题