【问题标题】:Re-organizing the data set based on all possible combinations根据所有可能的组合重新组织数据集
【发布时间】:2018-03-09 13:54:44
【问题描述】:

假设我有一个包含三个人ABC的数据,他们每个人都有两个特征,“学年”(YS)和“兄弟姐妹数量”(@ 987654325@)。因此,数据集X 如下所示:

id <- c("A", "B", "C")
YS <- c(6, 9, 8)
NS <-c(1, 0, 3)
X <- data.frame(id, YS, NS)

现在我必须根据ABC 的所有可能组合重新组织数据集,这意味着将有 2^3-1 个组合。更准确地说,这些组合是:ABCABACBCABCnull 组合(即 2^3-1 组合)。除了组合个体之外,我还必须计算每个组合的每个特征的值。例如,AB 组合的 YSNS 的值为 15 和 1。再例如,ABC 组合的YSNS 的值为 23 和 4。 /p>

我有点理解使用代码expand.grid 来生成可能的组合,但我不知道如何同时组合特征的值。任何人都可以帮忙吗?谢谢。

【问题讨论】:

    标签: r


    【解决方案1】:

    这是combn 的另一个选项

    all_combn <- function(x, ...)
        unlist(sapply(seq_along(x), combn, x=x, ...))
    
    data.frame(
       id=all_combn(id, paste, collapse=''),
       YS=all_combn(YS, sum),
       NS=all_combn(NS, sum)
    )
    
    #    id YS NS
    # 1   A  6  1
    # 2   B  9  0
    # 3   C  8  3
    # 4  AB 15  1
    # 5  AC 14  4
    # 6  BC 17  3
    # 7 ABC 23  4
    

    【讨论】:

    • 感谢您的回答 Matthew(当然还有所有提供帮助的人)。我在这段代码中有另一个问题。第二行中的x=x 是什么意思?谢谢。
    • 对不起@MatthewPlourde。你介意解释一下sapply的部分吗?我有点迷路了,因为对我来说,sapply 的第一个元素似乎是一个列表的名称,但在这里你使用seq_along(x),我不太明白它的意思。另外,x=x 是如何工作的?它似乎用于告诉combn m 是什么。无论如何,如果你能解释这个sapply 部分,我将不胜感激。
    • sapply 迭代 id 长度。首先,它生成 1 个 id、2 个 id、3 个 id 等的所有组合。你是对的,seq_along(x) 的值被传递给combnm 参数,因为第一个参数@987654335 @,在 sapply 调用中指定。
    【解决方案2】:

    不是很漂亮,也不是像 R 一样,但它确实有效。它包括根据问题设置的 NULL。

    # function to create the combinations and sum the elements
    reorgCombs <- function(data) {
        ids <- rownames(data)
        newdata <- data.frame(comb = c("NULL", id), YS = c(0, data[, "YS"]), 
                              NS = c(0, data[, "NS"]), row.names = NULL)
        for (i in 2:nrow(data)) {
            theseCombs <- t(combn(ids, i))
            newdata <- rbind(newdata, 
                             data.frame(comb = apply(theseCombs, 1, paste0, collapse=""),
                                        YS = apply(theseCombs, 1, function(x) sum(data[x, "YS"])),
                                        NS = apply(theseCombs, 1, function(x) sum(data[x, "NS"]))))
        }
        newdata
    }
    
    # make this a numeric matrix with named dimensions
    # the names will be used for lookup
    X2 <- cbind(YS, NS)
    rownames(X2) <- id
    
    reorgCombs(X)
    ##   comb YS NS
    ## 1 NULL  0  0
    ## 1    A  6  1
    ## 2    B  9  0
    ## 3    C  8  3
    ## 4   AB 15  1
    ## 5   AC 14  4
    ## 6   BC 17  3
    ## 7  ABC 23  4
    

    使用新基准进行编辑:

    也许是因为查找表的原因,尽管循环它相对较快——但被 Matthew 的解决方案所吸引

    ## Unit: relative
    ##    expr      min       lq     mean   median       uq       max neval
    ##    jota  4.479829  4.408874  4.304705  4.455843  4.335172  3.730202   100
    ##  pierre 11.606636 11.623717 12.743089 12.078027 11.761123 19.271072   100
    ##     ken  3.034247  3.015091  2.978181  3.040916  2.914744  2.755357   100
    ## matthew  1.000000  1.000000  1.000000  1.000000  1.000000  1.000000   100
    ##   frank  4.572867  4.615341  4.590244  4.719418  4.516317  3.978101   100
    

    【讨论】:

    • 感谢您进行基准测试。我对 Matthew 的胜利感到惊讶,因为它为每一列分别调用 combn
    • 感谢您的帮助@KenBenoit
    • 我也想知道是否有人能告诉我x=xsapply 函数中代表什么。谢谢!
    【解决方案3】:

    这是在基础 R 中执行此操作的一种方法。首先,识别组合:

    n = nrow(X)
    combos = do.call(rbind, lapply(seq(n), function(x){
      r = combn(n, x)
      data.frame( r = c(r), g = paste(x, c(col(r)), sep=".") )
    }))
    

    然后,为每个组合选择 X 行:

    Xc    = X[combos$r,]
    Xc$id = as.character(Xc$id)
    Xc$g  = ave(Xc$id, combos$g, FUN = function(x) paste0(x,collapse=''))
    

    最后,为每个组合聚合:

    aggregate(cbind(YS,NS)~g, Xc, sum)
    
    #     g YS NS
    # 1   A  6  1
    # 2  AB 15  1
    # 3 ABC 23  4
    # 4  AC 14  4
    # 5   B  9  0
    # 6  BC 17  3
    # 7   C  8  3
    

    这样你就错过了空集,但如果需要,rbind 很容易。

    【讨论】:

    • 感谢您的帮助@Frank!
    【解决方案4】:

    看起来很多,但我碰巧使用splitstackshape 获得另一个答案,并在这里看到了应用的可能性。第一个电话是lst1 &lt;- do.call(c, "all combinations")。正如您提到的所有可能性,这将创建列表。如果您愿意,您可以稍后添加像 NULL 这样的边缘案例。我们从lst1 创建一个数据框来组织信息。函数 cSplitdf 重塑为 long。我们合并以添加数字值。最后,使用dplyr,我们按我们创建的索引列分组,将任何因子输入integer,然后求和:

    library(dplyr)
    library(splitstackshape)
    
    lst1 <- do.call(c, lapply(1:3, function(i) combn(id, i, simplify=F)))
    df <- data.frame(indx=seq_along(lst1), combs=sapply(lst1, toString))
    df.long <- cSplit(df, 'combs', direction="long")
    
    m <- merge(X, df.long, by.x='id', by.y='combs')
    m %>% group_by(indx) %>%
      mutate_each(funs(as.integer(as.character(.))), -id) %>%
      summarise(id=toString(id), YS=sum(YS), NS=sum(NS))
    # Source: local data frame [7 x 4]
    # 
    #    indx      id    YS    NS
    #   (int)   (chr) (int) (int)
    # 1     1       A     6     1
    # 2     2       B     9     0
    # 3     3       C     8     3
    # 4     4    A, B    15     1
    # 5     5    A, C    14     4
    # 6     6    B, C    17     3
    # 7     7 A, B, C    23     4
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-12-15
      • 1970-01-01
      • 1970-01-01
      • 2022-07-08
      • 1970-01-01
      • 2022-11-12
      • 1970-01-01
      • 2012-03-27
      相关资源
      最近更新 更多