有没有一种方法可以在 i 中自我引用 data.table?

3
考虑标准的data.table语法DT[i, j, ...]。由于.SD仅在j中定义,并且在i中定义为NULL,是否有任何方法可以隐式地(期望)或显式地(通过类似.SD的东西)在i中引用当前data.table?

使用案例

我想编写一个过滤标准列的函数。列名称在多个表格中相同且有些冗长。为了减少键入,加快我的编码速度,我想编写这样一个函数:
library(data.table)
dt <- data.table(postal_code   = c("USA123", "SPEEDO", "USA421"),
                 customer_name = c("Taylor", "Walker", "Thompson"))
dt
#>    postal_code customer_name
#> 1:      USA123        Taylor
#> 2:      SPEEDO        Walker
#> 3:      USA421      Thompson

# Filter all customers from a common postal code 
# that surname starts with specific letters
extract <- function(x, y, DT) {
  DT[, startsWith(postal_code, x) & startsWith(customer_name, y)]
}


# does not work
dt[extract("USA", "T", .SD)]
#> Error in .checkTypos(e, names_x): Object 'postal_code' not found.
#>    Perhaps you intended postal_code

# works but requires specifying the data.table explicitly
# plus the drawback that it cannot be called upon, e.g. a grouped .SD
# in a nested call
dt[extract("USA", "T", dt)]
#>    postal_code customer_name
#> 1:      USA123        Taylor
#> 2:      USA421      Thompson

期望的(伪代码)

dt[extract("USA", "T")]
#>    postal_code customer_name
#> 1:      USA123        Taylor
#> 2:      USA421      Thompson

# but also
# subsequent steps in j
dt[extract("USA", "T"), relevant := TRUE][]
#>    postal_code customer_name relevant
#> 1:      USA123        Taylor     TRUE
#> 2:      SPEEDO        Walker       NA
#> 3:      USA421      Thompson     TRUE

# using other data.tables
another_dt[extract("USA", "T")]
yet_another_dt[extract("USA", "T")]

似乎 fcase 可以处理您的第二个用例: dt[, relevant := fcase(extract("USA", "T", dt), TRUE, default = NA)][]。您还有其他想法需要 fcase 无法处理的吗? - jblood94
感谢您的评论。我知道在 j 中有多种方法可以产生所需的结果。然而,我真的很想在 i 中触发所有操作,因为它更加灵活和方便。通常我会先检查过滤后的行,然后随后更新它们。此外,dt[extract("USA", "T"), relevant := TRUE]dt[, relevant := fcase(extract("USA", "T", dt), TRUE, default = NA)] 更容易阅读。这不是关于“如何获得这个结果”,而是非常具体地关于“如何在 i 中使用这样的函数”。 - mnist
承认这种方法不够易读,但是这个答案中的方法难道不会给出所需的多样性吗?https://stackoverflow.com/a/57091155/9463489 - jblood94
2
仅供参考,我认为这可能是一个相关的(公开)问题:New symbol .D to refer to x in i - Henrik
@jblood94 不完全是这样,因为我会再次输入“dt”,而我尽量避免这样做。 - mnist
2个回答

1
我不是一个 data.table 专家,但你可以尝试以下解决方法。
> dt[,.SD[extract("USA", "T", .SD)]]
   postal_code customer_name
1:      USA123        Taylor
2:      USA421      Thompson

.SD 中,您可以使用自我引用的方式来操作 j


谢谢您的回答。然而,仅仅过滤并不是唯一的用例。我还想将其用于各种i操作,例如更新。抱歉没有表述得够清楚。我已经相应地更新了我的问题。 - mnist

0

这里是一个可能的方法...

#create named vector
mystr <- c(postal_code = "USA", customer_name = "T")
#build query text
query <- paste0("grepl(\"^", mystr, "\", ", names(mystr), ")", collapse = " & ")
#eval/parse dynamic text
dt[eval(parse(text = query)), ]
#    postal_code customer_name
# 1:      USA123        Taylor
# 2:      USA421      Thompson

使用eval(parse(...))的想法很好。但是,有没有可能将其“隐藏”在extract()内部?在顶层代码中使用eval-parse是不可取的。 - mnist

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接