如何确保我使用
根据我对动态作用域的理解,我下面的代码应该可以工作,但它没有。我做错了什么?
细节: 我有一个函数列表,我想将其应用于单个
1这里我在非科学意义上使用“非标准”一词,表示“不寻常”。我不知道什么算是非标准,但这是另一个(而且太广泛?)的问题。
data.table
进行非标准评估时,可以从父框架继承所需的变量?根据我对动态作用域的理解,我下面的代码应该可以工作,但它没有。我做错了什么?
细节: 我有一个函数列表,我想将其应用于单个
data.table
,返回布尔检查和消息(当检查为TRUE时)。例如,假设我正在审核一个帐户表。library(data.table)
#----- Example data -----------------------------------------------------------
n <- 100
set.seed(123)
df <- data.table( acct_id = paste0('ID',seq(n)),
acct_balance = round(pmax(rnorm(n,1000,5000),0)),
days_overdue = round(pmax(rnorm(n,20,20),0))
)
#----- Example list of rules to check (real case has more elements)------------
AuditRules <- list(
list(
msg_id = 1,
msg_cat = 'Balance',
cond_fn = function(d) d[, acct_balance > balance_limit ],
msg_txt =
function(d) d[, paste('Account',acct_id,'balance is',
acct_balance - balance_limit,
'over the limit.')]
),
list(
msg_id = 2,
msg_cat = 'Overdue',
cond_fn = function(d) d[, days_overdue > grace_period ],
msg_txt =
function(d) d[, paste('Account',acct_id,'is overdue',
days_overdue-grace_period,
'days beyond grace period.')]
)
)
我正在循环遍历规则列表,并在每个规则上检查数据集。
期望的输出
在全局环境中,这样做是有效的。
balance_limit <- 1e4
grace_period <- 14
audit <- rbindlist(
lapply(AuditRules, function(item){
with( item,
df[ cond_fn(df),
.(msg_id,
msg_cat,
msg_txt = msg_txt(.SD) )
]
)
} )
)
print(head(audit), row.names=FALSE)
#----------------- Result --------------------------------------
# msg_id msg_cat msg_txt
# 1 Balance Account ID44 balance is 1845 over the limit.
# 1 Balance Account ID70 balance is 1250 over the limit.
# 1 Balance Account ID97 balance is 1937 over the limit.
# 2 Overdue Account ID2 is overdue 11 days beyond grace period.
# 2 Overdue Account ID3 is overdue 1 days beyond grace period.
# 2 Overdue Account ID6 is overdue 5 days beyond grace period.
有哪些问题(需要解决)
rm(balance_limit, grace_period) # see "aside"
auditTheData <- function(d, balance_limit = 1e4, grace_period=14){
rbindlist(
lapply(AuditRules, function(item){
with( item,
d[ cond_fn(d),
.(msg_id,
msg_cat,
msg_txt = msg_txt(.SD) )
]
)
} )
)
}
auditTheData(df)
导致错误的原因是:
Error in eval(jsub, SDenv, parent.frame()) :
object 'balance_limit' not found
虽然我读过一些关于编程时应该避免使用 with()
的文章,但这并不是与 with()
有关的问题。以下代码也无法正常工作:
auditTheData2 <- function(d, balance_limit = 1e4, grace_period=14){
rbindlist(
lapply(AuditRules, function(item){
d[ item[['cond_fn']](d),
.(msg_id,
msg_cat,
msg_txt = item[['msg_txt']](.SD) )
]
} )
)
}
auditTheData2(df) # Same error
提示: 如果在“不起作用”的函数之前没有执行rm(balance_limit, grace_period)
-- 也就是说,把它们留在全局环境中 -- 你会得到期望的结果。因此,似乎被lapply
应用的function(item)
可以“看到”全局环境,但不能看到父环境(AuditTheData
)。
1这里我在非科学意义上使用“非标准”一词,表示“不寻常”。我不知道什么算是非标准,但这是另一个(而且太广泛?)的问题。