【问题标题】:Creating all combinations of sampling from two groups of columns in R从R中的两组列创建所有采样组合
【发布时间】:2020-08-05 18:05:50
【问题描述】:

我在下面和这“两组”内有数据框,即 A&B 和 D&E 列。我想找到所有组合,然后按在 A&B 和 D&E 列应用不同过滤器的所有组合进行分组,但形式是当时只从每个组中选择 1 列。我不知道执行此操作的正确公式,而且实际上问题要大得多。

df=

     Size    A     B     D     E
       1     1     1     0     0
       5     0     0     1     0
       10    1     1     1     0
       3     1     0     0     0
       2     1     1     1     1
       55    0     0     0     1
       5     1     0     1     1
       2     0     0     1     1
       1     1     1     1     1
       4     1     1     1     0

所以要过滤的组合应该是

过滤器 1:A=1 和 D=1

过滤器 2:A=1 和 D=0

过滤器 3:A=1 和 E=1

过滤器 4:A=1 和 E=0

过滤器 5:A=0 和 D=1

过滤器 6:A=0 和 D=0

过滤器 7:A=0 和 E=1

过滤器 8:A=0 和 E=0

过滤器 9:B=1 和 D=1

过滤器 10:B=1 AND D=0

过滤器 11:B=1 和 E=1

过滤器 12:B=1 AND E=0

过滤器 13:B=0 和 D=1

过滤器 14:B=0 和 D=0

过滤器 15:B=0 AND E=1

过滤器 16:B=0 和 E=0

我想找到一种方法来有效地创建这些过滤器组(始终从 A&B 或 D&E 列中抽取 1 个过滤器),然后找到每个过滤器设置的 Size 列的平均值和计数。我只是设法在没有不同组的情况下做到这一点来对过滤器进行采样。

我尝试的是这样的形式:

groupNames <- names(df)[2:5]

myGroups <- Map(combn,list(groupNames),seq_along(groupNames),simplify = FALSE) %>% unlist(recursive = FALSE)

results = lapply(myGroups, FUN = function(x) {do.call(what = group_by_, args = c(list(df), x)) %>% summarise( n = length(Size), avgVar1 = mean(Size))})

它平等对待四列,不考虑从 2 组中抽样。我可以对代码做些什么来完成这项工作?

非常感谢。

【问题讨论】:

    标签: r dataframe group-by combinations permutation


    【解决方案1】:
    library(tidyverse)
    df <- tribble(~Size, ~A, ~B, ~D, ~E,
                  1, "1", "1", "0", "0",
                  5, "0", "0", "1", "0",
                  10, "1", "1", "1", "0",
                  3, "1", "0", "0", "0",
                  2, "1", "1", "1", "1",
                  55, "0", "0", "0", "1",
                  5, "1", "0", "1", "1",
                  2, "0", "0", "1", "1",
                  1, "1", "1", "1", "1",
                  4, "1", "1", "1", "0")
    p <- function(...) paste0(...) # for legibility, should rather use glue
    
    all_filtering_groups <- list(c("A", "B"), c("D", "E")) # assuming these are known
    all_combns <- map(1:length(all_filtering_groups), ~ combn(all_filtering_groups, .))
    res <- list(length(all_combns))
    
    #microbenchmark::microbenchmark({
    for(comb_length in seq_along(all_combns)){
      res[[comb_length]] <- list(ncol(all_combns[[comb_length]]))
      for(col_i in seq_len(ncol(all_combns[[comb_length]]))){
        
        filtering_groups <- all_combns[[comb_length]][,col_i]
        group_names <- as.character(seq_along(filtering_groups))
        
        
        # prepare grid of all combinations
        filtering_combs <- c(filtering_groups, rep(list(0:1), length(filtering_groups)))
        names(filtering_combs) <- c(p("vars_", group_names), p("vals_", group_names))
        full_grid <- expand.grid(filtering_combs)
        
        for(ll in 1:nrow(full_grid)){ # for each line in the full_grid
          # find df lines that correspond
          cond <- as.logical(rep(TRUE, nrow(df)))
          for(grp in group_names){
            cond <- cond & df[[full_grid[p("vars_", grp)][ll,]]] == full_grid[p("vals_", grp)][ll,]
          }
          # and compute whatever
          full_grid$lines[ll] <- paste(which(cond), collapse = ", ") #for visual verification
          full_grid$n[ll] <- length(df$Size[cond])
          full_grid$sum[ll] <- sum(df$Size[cond])
          full_grid$mean[ll] <- mean(df$Size[cond])
        }
        res[[comb_length]][[col_i]] <- full_grid
        
      }
    }
    #}, times = 10) #microbenchmark
    
    bind_rows(res) %>% relocate(starts_with("vars") | starts_with("vals"))
    

    【讨论】:

    【解决方案2】:

    根据 cmets 中的讨论,我认为我们可以将组视为变量。所以我们需要重塑数据框,使每个因子有一列,然后我们可以使用标准的 tidyverse 方法。我假设这些组是由列名(A1...Ak,B1...Bk,...)定义的。

    library(tidyverse)
    df <- tribble(~Size, ~A1, ~A2, ~B1, ~B2,
                  1, "1", "1", "0", "0",
                  5, "0", "0", "1", "0",
                  10, "1", "1", "1", "0",
                  3, "1", "0", "0", "0",
                  2, "1", "1", "1", "1",
                  55, "0", "0", "0", "1",
                  5, "1", "0", "1", "1",
                  2, "0", "0", "1", "1",
                  1, "1", "1", "1", "1",
                  4, "1", "1", "1", "0")
    
    get_levels <- function(col){
      paste(names(col)[col == "1"], collapse = ",")
    }
    # Rewrite with groups as factors
    df_factors <- df %>%
      mutate(id = row_number()) %>%  #to avoid aggregating same Size
      nest(A = starts_with("A"), B = starts_with("B")) %>%
      mutate(A = factor(map_chr(A, get_levels)),
             B = factor(map_chr(B, get_levels)))
    
    # Now look at factor combinations
    df_factors %>%
      group_by(A, B) %>%
      summarize(n = n(),
                mean = mean(Size))
    
    # A tibble: 8 x 4
    # Groups:   A [3]
    #   A       B           n  mean
    #   <fct>   <fct>   <int> <dbl>
    # 1 ""      "B1"        1   5  
    # 2 ""      "B1,B2"     1   2  
    # 3 ""      "B2"        1  55  
    # 4 "A1"    ""          1   3  
    # 5 "A1"    "B1,B2"     1   5  
    # 6 "A1,A2" ""          1   1  
    # 7 "A1,A2" "B1"        2   7  
    # 8 "A1,A2" "B1,B2"     2   1.5
    

    我明确地调用了“A”和“B”。使用 6 组似乎仍然可行。如果您有更多,则有必要进行自动化,但我不确定如何轻松做到这一点。

    【讨论】:

    • 谢谢 Alexlok。我尝试使用 6 个组和每组 3 个过滤器运行它,但计算时间很长。我意识到它还测试了过滤器设置为 0 的情况(例如,A1=1、B1=0、C3=0、D1=0、E2=0、F=0。我怎样才能删除它以便仅测试过滤器为 1 的所有过滤器组合(当然还有根本不使用相应过滤器的 NA)?
    • 我不知道为什么它仍然很慢。你能找出一条更慢的线吗?要删除设置为 0 的过滤器,您可以在重新编码后使用 filter(str_length(A) &gt; 1)。要删除所有过滤器为 0 的行,您可以使用 df_factors %&gt;% rowwise() %&gt;% filter(sum(across(A:B, str_length)) &gt; 1)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-20
    • 2020-02-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多