r - 锁定 data.table 表的内容
问题描述
是否可以将 data.table 设为静态(即不可更新)?使用 lockBinding() 函数可以防止重新分配变量,但是仍然可以编辑数据表的列。例子:
> dt = data.table( x = 1:5 )
> lockBinding( "dt", env = environment() )
> dt = 1
Error: cannot change value of locked binding for 'dt'
> dt[ , x := 1 ]
> dt[ , x ]
[1] 1 1 1 1 1
我想这与如何引用数据表有关,但是,能够锁定数据表的内容也会很有用。(我经常有不想意外更新的共享参考表。)
解决方案
这有点棘手。一种方法是劫持[
函数以禁止在:=
对象上使用。如果我们想绑定一个 data.table,我们可以给它添加一个类,像这样:
boundDT <- function(dt){
class(dt) <- c("bound.data.table", class(dt))
dt
}
结果:
library(data.table)
dt = data.table( x = 1:5 )
bound <- boundDT(dt)
class(bound)
[1] "bound.data.table" "data.table" "data.frame"
如果我们然后创建一个新的索引函数来处理这个bound.data.table
类,我们可以做我们的事情:
`[.bound.data.table` <- function(dt, ...){
if(any(unlist(sapply(match.call()[-(1:2)], function(x) if(length(x) > 1)as.character(x[1]) == ":=")))){
stop("Can't use `:=` on this object.")
}
class(dt) <- class(dt)[-1]
dt[...]
}
这将检查该函数是否在:=
调用中使用,如果使用则抛出错误。否则它会删除 data.table 内部副本上的绑定类,并调用常规[
函数。
bound[, x := 1]
Error in `[.bound.data.table`(bound, , `:=`(x, 1)) :
Can't use `:=` on this object.
bound[, x]
[1] 1 2 3 4 5
这很丑陋,但似乎有效。
一个警告:
在连接中使用:=
时,如果绑定表不是基表,则此方法不起作用:
dt = data.table( x = 1:5 , y = 5:1)
bound <- boundDT(dt)
dt[bound, y := 1, on = .(x = x)]
bound
x y
1: 1 1
2: 2 1
3: 3 1
4: 4 1
5: 5 1
然而:
bound[dt, y := 1, on = .(x = x)]
Error in `[.bound.data.table`(bound, dt, `:=`(y, 1), on = .(x = x)) :
Can't use `:=` on this object.
防止使用set*
解决了运算符周围的大多数问题:=
,我们可以专注于防止set*
在我们的对象上使用。
set*
当使用绑定的data.table时,我们可以在提供data.table之前检查调用堆栈是否有任何函数。
bindDT <- function(dt){
bound <- boundDT(dt)
function(){
calls <- sys.calls()
forbidden <- c("set", "set2key", "set2keyv", "setattr", "setcolorder", "setdiff", "setDT",
"setDTthreads", "setequal", "setindex", "setindexv", "setkey", "setkeyv",
"setnames", "setNumericRounding", "setorder", "setorderv")
matches <- unlist(lapply(calls, function(x) as.character(x)[1] %in% forbidden))
if(any(matches)){
stop(paste0("Can't use function ", calls[[which(matches)[1]]][1], " on bound data.table."))
}
bound
}
}
此函数像以前一样绑定 data.table,但它不是返回 this,而是返回一个函数。此函数在调用时会检查调用堆栈中的set*
函数,如果找到则抛出错误。我从 data.table 帮助页面得到了这个列表,所以这应该是完整的。
您可以使用主动绑定来避免每次使用都必须调用 data.table 作为函数,使用pryr
:
library(data.table)
library(pryr)
dt = data.table( x = 1:5 , y = 5:1)
bound %<a-% (bindDT(dt))()
setkey(bound, x)
Error in (bindDT(dt))() : Can't use function setkey on bound data.table.
推荐阅读
- angular - Angular:“AbstractControl”缺少“FormControl”类型的以下属性:registerOnChange、registerOnDisabledChange、_applyFormState
- php - 为什么“未定义的偏移量”在一台机器上引发异常,但在另一台机器上显示通知?
- excel - VB中更改字体的if语句
- java - 用于 Map 的 Jackson 自定义 KeyDeserializer,不包括 key 为 null 的条目
- javascript - keycloak-js 适配器手动添加令牌
- reactjs - 是的,使用 Formik 进行条件验证
- c++ - 固定,设置精度函数
- python - 从大字符串列表中创建新的字符串列表
- python - Python/机器学习 - 线性回归,TypeError:'list' 对象不可调用
- schema.org - 如何在 JSON-LD 中向网站添加几个潜在操作?