数据框不随rbind而改变

时间:2017-06-13 18:24:30

标签: r dataframe rbind

这看起来应该很简单。我想我会做一个小时间表功能,这样我就可以跟踪我的工作时间。以下是代码:

timesheet <- data.frame(matrix(nrow = 0, ncol = 3))
varn <- c("date", "project", "status")
colnames(timesheet) <- varn

timesheet[1,] <- c(date(), "test", "test") 
#The above line exists because rbind was renaming the columns otherwise

new.task <- function(project){
  timesheet <- append(time, c(date(), project, "started"))
}

new.task("Name of task")

但是数据框保持不变而不会抛出错误。这是怎么回事?

1 个答案:

答案 0 :(得分:1)

原因在于词汇范围的概念和&#34;环境&#34;在R中作为存储空间:

&#34;时间表&#34;对象在全球环境中声明。但是&#34;时间表&#34;您的代码尝试追加的对象是在&#34; new.task&#34;范围内声明的。功能。所以&#34;追加&#34;命令只是附加到本地&#34;时间表&#34;而不是全局的。

为了说明范围和环境,我在您的代码中添加了一些信息行:

library(pryr)

timesheet <- data.frame(matrix(nrow = 0, ncol = 3)) 
varn <- c("date", "project", "status")
colnames(timesheet) <- varn

timesheet[1,] <- c(date(), "test", "test") 
#The above line exists because rbind was renaming the columns otherwise

print(environment())
print(ls(environment()))
sprintf("address of timesheet object is %s", pryr::address(timesheet))

new.task <- function(project){
    timesheet <- append(time, c(date(), project, "started"))
    print(environment())
    print(ls(environment()))
    sprintf("address of timesheet object is %s", pryr::address(timesheet))
}

new.task("Name of task")

&#34; pryr&#34;加载库以获取对象的内存地址。 当我们获取代码时,首先:

  • 全球环境的名称/地址
  • 全球环境中的对象列表
  • 和&#34;时间表&#34;的内存地址全球环境中的对象
打印

由于最后一行运行&#34; new.task&#34;函数,后来三个信息都在new.task函数中打印。看到差异:

<environment: R_GlobalEnv>
[1] "new.task"  "timesheet" "varn"     
[1] "address of timesheet object is 0x365b8e8"
<environment: 0x32ef750>
[1] "project"   "timesheet"
[1] "address of timesheet object is 0x365dbb8"

为了纠正这个问题,你应该使用&#34;&lt;&lt; - &#34;来超级签名(一种修改全局环境中存在的对象的方法)。运算符如下:

new.task <- function(project){
  timesheet <<- append(time, c(date(), project, "started"))
}

但您的代码中还有两个错误:

  • 你试图追加到&#34;时间&#34;不是时间表,而是&#34;时间&#34;本身就是一个闭包,一个内置函数。
  • 追加适用于矢量或列表。但是当您尝试追加到数据帧时,它会转换为列表。

所以正确的形式应该是这样的(你也可以使用rbind):

timesheet[nrow(timesheet)+1,] <<- c(date(), project, "started")

另一种修改没有超级赋值运算符的全局对象的方法是用它的环境引用它,如下所示:

timesheet <- data.frame(matrix(nrow = 0, ncol = 3))
varn <- c("date", "project", "status")
colnames(timesheet) <- varn

timesheet[1,] <- c(date(), "test", "test")
#The above line exists because rbind was renaming the columns otherwise

envg <- environment()

new.task <- function(project, env = envg){
    env$timesheet[nrow(env$timesheet)+1,] <- c(date(), project, "started")
}

new.task("Name of task")