R Error - cannot change value of locked binding for 'df'

前端 未结 4 1252
日久生厌
日久生厌 2021-02-14 06:00

I\'m trying to filter some data, with functions in R relatives to data frames. But in the second function, it gives me the following error: cannot change the value of locked bin

相关标签:
4条回答
  • 2021-02-14 06:32

    Sometimes, one does want to violate the spirit of functional languages.

    I am not sure why, in R, a locked function prevents you from creating a variable at the same level, but the problem the OP has is because the function df() is locked in an environment above that of the current environment (which <<- finds).

    Here is some code (probably not the best) to find the environment in which df is (already) bound (i.e., already exists), and then check to see if it is, in fact, locked in that environment.

    > x <- environment(); while(TRUE) { print(exists("df", x)); x <- parent.env(x) }
    [1] TRUE
    [1] TRUE
    [1] TRUE
    [1] FALSE
    [1] FALSE
    [1] FALSE
    [1] FALSE
    [1] FALSE
    [1] FALSE
    [1] FALSE
    [1] FALSE
    Error in parent.env(x) : the empty environment has no parent
    > bindingIsLocked("df", parent.env(parent.env(environment())))
    [1] TRUE
    > 
    

    In this case, creating a variable df in the "global" context should solve the problem. i.e.,

    df <- NULL
    
    filter.data = function(x, dir = ".") {
        load.data(x, dir)
        df <<- dados_reais[,c(1,2,3,4,9,10,12)]
    }
    

    Alternatively, changing the name of the variable (from df, say, to myveryowndf) should also fix the problem.

    0 讨论(0)
  • 2021-02-14 06:33

    Answer:

    The reason is that <<- and <- work differently.

    x <- val means "assign the value val to the name x in the current scope." That's the assignment operator you should usually use.

    x <<- val means "go search for a name x in the current scope and its enclosing scopes. As soon as you find it, assign the value val to it and stop. If you don't find it, create a new variable x in the broadest scope (global) and assign it the value val."

    In your case, your name choice of df was somewhat unlucky: there's a built-in function df (in the stats namespace) for computing the density of Snedecor's F distribution function. Your <<- assignment found that, tried to change its value to dados_reais[,c(1,2,3,4,9,10,12)], and refused (because the built-in df function is "locked", i.e. immutable). An easier example showing the issue is this:

    df <<- 5
    # Error: cannot change value of locked binding for 'df'
    

    Incidentally:

    As demonstrated, R's variables and functions share the same namespaces (or, more accurately: R's functions are typically stored in the same symbol tables [environments] that all the other variables are, they're not "special" like in many other languages). So does that mean that you shouldn't ever use a variable like df or min or q or t, that clashes with a built-in function's name? No, generally it's not a big deal, because when you do min(x), R knows to look for a function called min, not any old symbol table entry called min, so it uses something like get("min", mode="function") to make sure it doesn't accidentally find some variable you've defined that happens to be called min.

    That said, sometimes you do get some name collisions that are a little sneaky. For example, if you think you have a data.frame called df, but you forgot to actually create it, you might see an error like this:

    df[1, 5]
    # Error in df[1, 5] : object of type 'closure' is not subsettable
    

    It's saying that the function df (a function in R is an "object of type 'closure'") can't be indexed with square brackets like that. File that somewhere in your brain, because if you work with R long enough, you're bound to see that error once in a while.

    0 讨论(0)
  • 2021-02-14 06:48

    You should be avoiding <<-. That creates function with side-effects which run contrary to the spirit of functional languages. Try

    load.data <- function(x,dir = ".") {
        read.csv(paste(dir,x,sep="/"), header = FALSE, sep = "\t", dec = ".", col.names = c("Seq","Allele","Peptide","Identity","Pos","Core","Core-Rel", "Um-log50k(aff)","Affinity(nM)","Rank","Exp_Bind","Binding Level"))
    }
    
    filter.data <- function(x, dir = ".") {
        load.data(x, dir)[,c(1,2,3,4,9,10,12)]
    }
    
    df <- filter.data("mypath.csv")
    
    0 讨论(0)
  • 2021-02-14 06:53

    I had this problem when creating function inside a package, and I was using <<- inside exported function to overwrite some functions from different package. I've created hack with env <- parent.env() and adding this to parent env instead since the function was always called at top level. So env will be scope of the code that call the function not the package.

    here is complete code of this function, it overwrite shiny and current package functions:

    #' @export
    useMocks <- function() {
      observeEvent <- battery::observeEventMock
      assignInNamespace("observeEvent", observeEvent, "battery")
      assignInNamespace("observeEvent", observeEvent, "shiny")
      isolate <- battery::isolate
      assignInNamespace("isolate", isolate, "shiny")
      makeReactiveBinding <- battery::makeReactiveBinding
      assignInNamespace("makeReactiveBinding", makeReactiveBinding, "shiny")
      renderUI <- battery::renderUI
      assignInNamespace("renderUI", renderUI, "shiny")
      ## we modify the parent frame so it update environment when function is called not the package
      env <- parent.frame()
      env$observeEvent <- observeEvent
      env$isolate <- isolate
      env$renderUI <- renderUI
    
    }
    

    using <<- throw this error here because you can't modify the package scope.

    observeEvent <<- battery::observeEventMock
    

    this don't work

    0 讨论(0)
提交回复
热议问题