如何在条件下使用expand.grid?

时间:2020-04-06 16:46:05

标签: r

我正在使用一系列变量的expand.grid,但是有些特殊情况可以排除。 搜索显示expand.grid无法做到这一点,但是可以添加过滤器,因此这是我的尝试。

a = 1:5
b = 1:5
c = 0:3
d = 1:5
e = 1:3
df = expand.grid(a,b,c,d,e)
colnames(df)[c(1:5)] <- c("a","b","c","d","e");
df$d = ifelse(df$c == 0, d[[1]], df$d);
df$e = ifelse(df$c == 0, d[[1]], df$e);
df = unique(df)

在这种情况下,如果c为0,则不使用变量d和e,因此我使用ifelse将d和e设置为d和e的第一个值(如果c = 0),然后删除具有唯一性的重复行。

上面的代码确实有效,所以出了什么问题。太具体了。

我不喜欢针对特定变量的2条ifelse语句。如果我有100个条件变量,该怎么办。如何压缩语句,并可能仅在一行中写出依赖于任一条件的所有条件或变量。

我也欢迎任何其他优化以复杂场景的最少编码来完成所需任务。谢谢。

更新

到目前为止,在运行时之前我根本不知道变量的数量。我的例子是一个非常基本的例子。通常,我会得到很好的解决方案,但这些解决方案仅适用于特定示例,而并非真正的问题。

我没有从头到尾的集合,或者直到运行时才知道有多少集合或集合的大小。 a可能是文件夹列表,b是子文件夹列表,c文件。但是如果文件很小或者是空的,我就不需要做e和f了。

理想的解决方案不考虑任何静态值,例如:

expand.grid(变量列表,键变量=键值,依赖列表)

是的,这超出了此问题的范围,但是我只是想说解决方案需要处理编码时未知的数据集。

希望这可以解决一些问题,而不仅仅是提出更多问题。

2 个答案:

答案 0 :(得分:2)

我们可以使用crossing

library(tidyr)
library(dplyr)
crossing(a, b, c, d, e) %>% 
    mutate_at(vars(d, e), ~ replace(., c == 0, first(.))) %>%
    distinct

答案 1 :(得分:1)

这是另一种基本的R方式。它使用逻辑索引来修改列de,其余代码与问题类似。下面的测试表明这是最快的选择。

f1 <- function(a, b, c, d, e){
  X <- expand.grid(a, b, c, d, e)
  names(X) <- c("a","b","c","d","e")
  X$d <- ifelse(X$c == 0, X$d[1], X$d)
  X$e <- ifelse(X$c == 0, X$d[1], X$e)
  unique(X)
}

f2 <- function(a, b, c, d, e){
  X <- expand.grid(a, b, c, d, e)
  names(X) <- c("a","b","c","d","e")
  i <- X$c == 0
  X$d[i] <- X$d[1]
  X$e[i] <- X$e[1]
  unique(X)
}

library(tidyr)
library(dplyr)

f3 <- function(a, b, c, d, e){
  crossing(a, b, c, d, e) %>% 
    mutate_at(vars(d, e), ~ replace(., c == 0, first(.))) %>%
    distinct
}

a = 1:5
b = 1:5
c = 0:3
d = 1:5
e = 1:3

library(microbenchmark)

mb <- microbenchmark(
  op = f1(a,b,c,d,e),
  rui = f2(a,b,c,d,e),
  akrun = f3(a,b,c,d,e)
)

print(mb, unit = "relative", order = "median")
#Unit: relative
#  expr       min       lq     mean   median       uq      max neval cld
#   rui 1.0000000 1.000000 1.000000 1.000000 1.000000 1.000000   100  a 
#    op 0.8147996 1.035322 1.018649 1.026295 1.038269 1.096384   100  a 
# akrun 1.7580304 1.815582 1.836061 1.827887 1.872767 1.107545   100   b