基于字符串条件对数据框进行子集筛选

4

我希望能按照一个未知的条件(例如下面的示例中随机定义的条件)对 df 进行子集筛选:

df <- data.frame(a=1:10, b = 10:1)
condition <- paste0(sample(letters[1:2],1), sample(c("<",">"),1), sample(1:10,1))

我可以使用eval完成此操作,但众所周知,这种方法并不是最佳选择:

subset(df, eval(parse(text=condition)))

有没有替代eval(parse)的方法?


1
“未知条件”是什么意思? - amonk
通过“未知条件”,我猜这是一种说法:“我在一个变量condition中编写了一个条件,然后将此条件应用于数据集”? - Mbr Mbr
1
“unknown”被程序定义为:无法事先知道。这就是sample所要表达的意思。 - InspectorSands
3
一个小的简化可以是subset(df, eval(parse(text=condition)))(尽管subset应该只在交互模式下使用)。 - talat
1
值得一读:https://dev59.com/ZXI-5IYBdhLWcg3wpqMK#40164111 - Cath
显示剩余2条评论
4个回答

2

如果稍作调整,你的脚本就更加可行:

condition  <- list(value1 = sample(letters[1:2], 1),
                   comp =   sample(c(`<`, `>`), 1)[[1]],
                   value2 = sample(1:10, 1))

subset(df, condition$comp(df[, condition$value1], condition$value2))

因此,它取决于对条件传递的限制。

(请注意,使用subset可能不是一个好主意)


那么,“aaa-sin(2pib)<0”这个条件是如何处理的呢?我们是在谈论线性组合吗? - amonk
1
我假设 OP 使用该方法来创建一个可重现的示例,实际上他们可能直接将条件作为字符串获取。也许 OP 可以澄清一下。 - Ronak Shah
@Axeman,非常有用。实际上,我只是举了一个例子,将条件作为字符串提供。 - InspectorSands
1
实际上,这并不起作用,因为 condition$comp(condition$value1, condition$value2) 返回一个单一的布尔值。subset(df, condition$comp(df[,condition$value1], condition$value2)) 可能是一个替代方案。 - InspectorSands
@Axeman,如果您更改此内容以使其正常工作,我将很高兴接受答案。 - InspectorSands

1
如果可以引入一些限制,比如数据框只有数字列,并且只有线性条件,那么您可以将决策条件表示为点积:
# a > b
condition.mat <- c(1, -1)
condition.const <- 0

# b > 4
# condition.mat <- c(0, 1)
# condition.const <- 4

dec <- as.matrix(df) %*% condition.mat - condition.const
sel <- dec > 0

print(df[sel,])

谢谢,Surak。这是个好消息。不幸的是,我的例子有误导性,因为我 df 的列实际上是字符类型。 - InspectorSands

1

除了基本的subset函数外,还可以使用dplyr中的filter函数:

df <- data.frame(a=1:10, b = 10:1)
condition <- paste0(sample(letters[1:2],1), sample(c("<",">"),1), sample(1:10,1))

library(dplyr)
df %>% filter(eval(parse(text=condition))

2
我实际上是想完全绕过eval(parse) - InspectorSands

1

只是一个想法。有其他方法使代码保持动态,而不需要(讨厌的)“字符表达式”,例如:

df <- data.frame(a=1:10, b = 10:1)

mysubset <- function (f,x1,x2) {
  df[f(df[[x1]],x2),]
}

mycol <- sample(letters[1:2],1) 
myfun <- sample(c("<",">"),1)
mylimit <- sample(1:10,1)

mysubset(.Primitive(myfun),mycol,mylimit) # in my mind just as dynamic as eval-parse ..

mysubset(`<`,"a",4) 

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