【问题标题】:How to use expand.grid with conditions?如何在有条件的情况下使用 expand.grid?
【发布时间】:2020-07-18 17:53:11
【问题描述】:

我使用的是一系列变量的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 到 e 或知道有多少集合或集合的大小。 a 可以是文件夹列表,b 可以是子文件夹列表,c 文件。但是如果文件是小空或其他,我不需要做e和f。

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

expand.grid(list_of_variables, key_variables = key_values, list_of_dependents)

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

希望这能澄清一些事情,而不仅仅是提出更多问题。

【问题讨论】:

  • 你就不能df &lt;- df[df$c != 0,]吗?
  • 如果c = 0,它不只是删除行吗,我需要c = 0,只是为了它只出现一次,对于其他每个变量。
  • 当然。如果您提供较小的样本(不是5*5*4*5*3 行)和您的预期输出,这将有很大帮助。而且既然你提到了“100个条件变量”,那就有点模糊了,你能不能也说清楚?

标签: r


【解决方案1】:

我们可以使用crossing

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

【讨论】:

    【解决方案2】:

    这是另一种基本的 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
    

    【讨论】:

    • 我喜欢f2先找条件再用。是否可以仅在一个命令中设置,例如: X[i,c("d","e")] 选择有效,但应该抓取矢量元素的 get 无效。谢谢
    • @MichaelE 是的,这是可能的,但在我的测试中f2 变得比问题的解决方案f1 慢。
    猜你喜欢
    • 1970-01-01
    • 2013-05-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-10
    • 2021-05-16
    • 1970-01-01
    相关资源
    最近更新 更多