首页 > 解决方案 > R - 如何存储谓词(即,存储到变量中)

问题描述

我看到,如果您有数据框(列表)或向量(列表),则可以将 lapply 与谓词一起使用:

lapply(myDataframe, subset, x3 < 10)

但是我怎样才能将谓词存储到变量中,所以我可以以编程方式执行:

myPredicate = x3 < 10  # where x3 references a column name of whatever dataframe is applied later
lapply(myDataframe, subset, myPredicate)

标签: r

解决方案


假设你有一个这样的数据框:

df <- data.frame(x = 1:10,
                 y = 96:105, 
                 z = rep(c("A", "B", "C"), length.out = 10))

并且您想要存储可以应用的命名谓词列表。您可以简单地通过将谓词生成的逻辑向量存储在列表中来做到这一点:

p  <- list(x_is_even = df$x %% 2 == 0,
           y_gt_100  = df$y > 100,
           z_is_A    = df$z == "A")

这些可以像任何其他逻辑条件一样组合:

subset(df, p$x_is_even & p$z_is_A & p$y_gt_100)
#>     x   y z
#> 10 10 105 A

如果您想以一种可以传递“裸”谓词的方式进行操作(即那些命名列而不命名数据框的谓词),那么这要困难得多。

原因是您必须将谓词存储为语言对象。&当您开始使用这些时,将它们与诸如or之类的逻辑运算符组合起来是没有意义的|,因为这些操作不是为语言对象定义的。

可能的,但它需要对语言进行一些编程。我意识到你希望得到一些简单的东西,但是没有办法简单地在基础 R 中做到这一点。我将展示它是如何实现的,你可以决定是否值得麻烦。


首先,您需要一种创建引用谓词列表的方法:

make_subsets <- function(...)
{
  as.list(match.call()[-1])
}

所以你可以做

p  <- make_subsets(x_is_even = x %% 2 == 0,
                   y_gt_100  = y > 100,
                   z_is_A    = z == "A")
p
#> $x_is_even
#> x%%2 == 0
#> 
#> $y_gt_100
#> y > 100
#> 
#> $z_is_A
#> z == "A"

现在您需要能够将这些任意构建到一个调用中:

parse_subsets <- function(expr)
{
  expr <- as.list(match.call()$expr)
  this_call <- as.character(expr[[1]])
  if(this_call == "&" | this_call == "|")
  {
    l <- unlist(lapply(expr[-1], function(x) {
                 eval(as.call(list(parse_subsets, x)))}))
    as.call(append(l, as.symbol(this_call), 0))
  }
  else return(eval(as.call(expr)))
}

现在您需要一个可以获取谓词和过滤数据的函数:

subset2 <- function(data, subsets)
{
  ss <- match.call()$subsets
  ss <- eval(as.call(list(parse_subsets, ss)))
  eval(as.call(list(subset, data, ss)))
}

所以现在你可以做

subset2(df, p$x_is_even & p$y_gt_100 & p$z_is_A)
#>     x   y z
#> 10 10 105 A

请注意,但是,如果您想lapply在此上使用,则需要很长的路要走:

lapply(list(df, df), function(x) subset2(x, p$x_is_even & p$y_gt_100 & p$z_is_A))
#> [[1]]
#>     x   y z
#> 10 10 105 A
#>
#> [[2]]
#>     x   y z
#> 10 10 105 A

推荐阅读