2

我正在尝试实现一个函数,该函数基于任意长度的列名列表获取动态子集

静态代码是:

s <- c("s0","s1","s2")
d.subset <- d[ d$s0 > 0 | d$s1 > 0 | d$s2 > 0,] 

但是,我想生成d$s0 > 0 | d$s1 > 0 | d$s2 > 0基于 s 的部分。我尝试使用 as.formula() 来生成它,但它给了我一个“无效的公式”错误。

4

4 回答 4

5

一个示例数据框:

d <- data.frame(s0 = c(0,1,0,0), s1 = c(1,1,1,0), s2 = c(0,1,1,0))

s <- c("s0","s1","s2")

这是一个简单的解决方案rowSums

d[as.logical(rowSums(d[s] > 0)), ]

结果:

  s0 s1 s2
1  0  1  0
2  1  1  1
3  0  1  1
于 2013-01-17T16:33:41.590 回答
2

你的代码是不可重现的,所以这是你想要的,我认为你想使用索引而不是$运算符:

s <- c("s0","s1","s2")
d.subset <- d[ d[, s[1]] > 0 | d[, s[2]] > 0 | d[, s[3]] > 0,] 
于 2013-01-17T16:30:48.440 回答
1

受@sven-hohenstein 的回答启发,这里是一个通用函数,它将基于谓词列表进行过滤,以形式指定column=list(binary_operator, rhs)(例如x=list(`<=`, 3)for x <= 3)。

#' Filter a data frame dynamically
#'
#' @param df data frame to filter
#' @param controls list of filters (with optional operators)
filter_data = function(df, controls) {

  evaluate = function(predicate, value) {
    if (is.list(predicate)) {
      operator = predicate[[1L]]
      rhs = predicate[[2L]]
    } else {
      operator = `==`
      rhs = predicate
    }
    return(operator(value, rhs))
  }

  index = apply(
    mapply(evaluate, predicate=controls, value=df[names(controls)]), 1L, all
  )

  return(df[index, ])

}

这是一个使用过滤功能来应用条件的示例x == 2 & y <= 2.5 & z != 'C'

# create example data
df = data.frame(
  x=sample(1:3, 100L, TRUE),
  y=runif(100L, 1, 5),
  z=sample(c('A', 'B', 'C'), 100L, TRUE)
)

controls = list(x=2L, y=list(`<=`, 2.5), z=list(`!=`, 'C'))

filter_data(df, controls)
于 2014-07-18T01:17:32.673 回答
0

(编辑:强烈不推荐此解决方案。有关详细信息,请参阅评论和此 Stack Overflow 问题。)

我刚刚学会了这个技巧:把它全部写成一个字符串并使用eval(parse(text=. 也许对于这个例子来说不是最好的,但它可以更普遍地使用。

s <- c("s0","s1","s2")
s.1 <- paste0("d$",s," > 0",collapse=" | ")
d.subset <- eval(parse(text=paste0("d[",s.1,",]")))
于 2013-01-17T16:48:47.277 回答