在 R 中,如何根据函数内部的值列表正确地对数据框进行子集化?

In R, how can I properly subset a data frame based on a list of values inside of a function?

我有一个函数试图 select 基于值列表的数据框中的行。

例如,某些值可能是:

> subset_ids
[1] "JUL_0003_rep1" "JUL_0003_rep2"
[3] "JUL_0003_rep3" "JUL_0007_rep1"
[5] "JUL_0007_rep2" "JUL_0007_rep3" 

我有一个名为 "targets" 的数据框,其中有一列名为 "LongName"。它有许多其他专栏,但没什么大不了的。当 LongName 在子集 ID 中时,我想 select 来自目标的行。

我可以用以下任何一个来做这件事:

targets[is.element(targets$LongName, subset_ids),]

targets[targets$LongName %in% subset_ids,]

问题是我想在一个函数里做这件事,不知道会提前调用什么列。

所以我尝试使用 eval/parse 方法,根据最近的阅读,这可能不是最好的方法。当我执行以下操作时:

sub1 <- paste("targets[is.element(targets$", column_name, ", subset_ids),]", sep="")
targets_subset <- as.character(eval(parse(text = sub1)))

它 returns 一些奇怪的行号连接。它看起来像这样:

[1] "c(5, 6, 7, 17, 18, 19, 26, 27, 28, 35, 36, 46, 47, 48, 54, 55, 61, 62, 63, 64, 73, 74, 75, 76, 77, 78, 91, 92, 93, 102, 103, 104, 114, 117, 118, 129, 136, 137, 140, 141, 151, 152, 153, 157, 158, 159, 169, 172, 173, 183, 187, 188, 199, 200, 201, 208, 209, 210, 232, 233, 241, 242, 243, 252, 253, 254, 264, 265, 270, 271, 285, 286, 296, 297, 298)"
[2] "c(5, 6, 7, 17, 18, 19, 26, 27, 28, 35, 36, 46, 47, 48, 54, 55, 61, 62, 63, 64, 73, 74, 75, 76, 77, 78, 91, 92, 93, 102, 103, 104, 114, 117, 118, 129, 136, 137, 140, 141, 151, 152, 153, 157, 158, 159, 169, 172, 173, 183, 187, 188, 199, 200, 201, 208, 209, 210, 232, 233, 241, 242, 243, 252, 253, 254, 264, 265, 270, 271, 285, 286, 296, 297, 298)"
[3] "c(3, 3, 3, 7, 7, 7, 11, 11, 11, 15, 15, 19, 19, 19, 22, 22, 26, 26, 27, 27, 31, 31, 31, 32, 32, 32, 39, 39, 39, 43, 43, 43, 47, 49, 49, 53, 57, 57, 59, 59, 63, 63, 63, 65, 65, 65, 70, 72, 72, 76, 78, 78, 83, 83, 83, 86, 86, 86, 97, 97, 100, 100, 100, 104, 104, 104, 108, 108, 111, 111, 117, 117, 121, 121, 121)" 

所以 5、6、7、17 ... 似乎是我要选择的目标的正确行,但我不明白为什么它首先发回了这个,或者什么项目 [3] 根本没有。

如果我手动执行上述 "sub1 <- ..." 生成的行,那么它 returns 正确的数据。如果我要求函数来做,它 returns 这个垃圾。

我的问题有两个方面。 1:为什么要这样返回数据? 2:有没有比 eval/parse 更好的方法来做我想做的事情?

我怀疑存在一些奇怪的范围或环境级别问题,但目前我还不清楚。我感谢任何人的任何建议。

数据以这种方式返回,因为您将数据帧强制转换为字符对象。尝试

as.character(head(targets))

看一个简短的例子。

因此,如果您消除了 as.character(),您的方法就有效了。这是一个 MWE:

targets <- data.frame(LongName = sample(letters, 1000, replace = TRUE),
                      SeqNum= 1:1000,
                      X = rnorm(1000))
subset_ids <- c("a","f")

targets[is.element(targets$LongName, subset_ids),]

targets[targets$LongName %in% subset_ids,]

testfun <- function(targets, column_name, subset_ids){
  sub1 <- paste("targets[is.element(targets$", column_name, ", subset_ids),]", sep="")
  targets_subset <- eval(parse(text = sub1))

  return(targets_subset)
}

testfun(targets, column_name = "LongName", subset_ids)