【问题标题】:expand.grid function for data.frames in RR中data.frames的expand.grid函数
【发布时间】:2015-07-17 02:33:12
【问题描述】:

我有 2 个带有以下列的 data.frames。

1) A,B,C,D 2) E,F,G,H

我想做的是创建一个新的 data.frame,它为 expand.grid(1[,B]2[,F]) 的每个元素都有一行,并将保留所有其他列和值与原始 data.frames 中 col B 和 col F 的值相关联

我目前正在使用 2 个 for 循环来执行此操作,这会产生相当长的运行时间,因为我正在处理的 data.frames 相当大。

这是我正在寻找的屏幕截图:

> aa
  A B C D
1 1 x 3 5
2 2 y 4 6
> bb
  E F  G  H
1 7 j  9 11
2 8 k 10 12
> cc
  A B C D E F  G  H
1 1 x 3 5 7 j  9 11
2 2 y 4 6 7 j  9 11
3 1 x 3 5 8 k 10 12
4 2 y 4 6 8 k 10 12

【问题讨论】:

  • 你确定你想要的输出是正确的吗?在cc 中,您有两组相同的行 (1, 3) 和 (2, 4)。
  • 我不确定你的例子对你问题的措辞是否有意义。您最终会在 cc 中得到重复的行,从您的解释看来,您希望 B 和 F 的值充当这些 data.frames 的键,但它们本身可以通过 expand.grid 组合?
  • 是的,你们是对的,我的输出是错误的。我编辑了这个问题,感谢您指出这一点。

标签: r dataframe


【解决方案1】:

我想,你正在寻找:

merge(aa,bb)

  A B C D E F  G  H
1 1 x 3 5 7 j  9 11
2 2 y 4 6 7 j  9 11
3 1 x 3 5 8 k 10 12
4 2 y 4 6 8 k 10 12

【讨论】:

  • 因为没有公共列,你基本上只是在做一个完整的外连接。不错。
  • 谢谢,由于我的表格的格式,我需要对此进行一些更改(它们实际上共享一些公共列,但没有我想要成对扩展的列)但是这样做了技巧和运行时间现在显着降低。
【解决方案2】:

在某一时刻,我修改了expand.grid 中的代码,以便更轻松地对列块进行分组。这是代码

#available from
#https://gist.github.com/MrFlick/00e2c589a2fa4b6d91f2

Expand.Grid<-function (..., stringsAsFactors = TRUE) 
{
    nargs <- length(args <- list(...))
    if (!nargs) 
        return(as.data.frame(list()))
    if (nargs == 0L) 
        return(as.data.frame(list()))
    Names <- function(x) {if(!is.null(names(x))) names(x) else rep("",length(x))}
    Paste <- function(...) {a<-list(...); r<-do.call("paste", c(list(sep="."),
        a[sapply(a, function(x) !is.character(x) || any(nzchar(x)))]));
        nx <- max(sapply(a, length))
        if (length(r)) return(rep(r, length.out=nx)) else return(rep("", nx))
    }
    contribcols <- sapply(args, function(x) ifelse(class(x)=="data.frame", ncol(x), 1))
    outargs <- sum(contribcols)
    cargs <- vector("list", outargs)
    nmc <- paste0("Var", seq.int(sum(contribcols)))
    nm <- unlist(lapply(seq_along(args), function(x) if(class(args[[x]])=="data.frame") {
        Paste(Names(args)[x], Names(args[[x]])) } else {Names(args)[x]}))
    if (is.null(nm)) 
        nm <- nmc
    else if (any(ng0 <- !nzchar(nm))) 
        nm[ng0] <- nmc[ng0]
    names(cargs) <- make.unique(make.names(nm))
    rep.fac <- 1L
    d <- sapply(args, function(x) ifelse(class(x)=="data.frame", nrow(x), length(x)))
    orep <- prod(d)
    if (orep == 0L) {
        i<-1
        for (a in seq_along(args)) {
            if (contribcols[a]==1) {
                args[[a]]=list(a)
            }
            for(j in seq_len(contribcols[a])) {
                cargs[[i]] <- args[[a]][[j]][FALSE]
                i <- i+1
            }
        }
    } else {    
        i<-1
        for (a in seq_along(args)) {
            nx <- d[a]
            orep <- orep/nx
            x<-args[[a]]
            if (contribcols[a]==1) {
                x<-list(x)
            }
            for(j in seq_len(contribcols[a])) {
                y <- x[[j]]
                y <- y[rep.int(rep.int(seq_len(nx), rep.int(rep.fac, 
                    nx)), orep)]
                if (stringsAsFactors && !is.factor(y) && is.character(y)) 
                    y <- factor(y, levels = unique(y))
                cargs[[i]] <- y
                i <- i+1
            }
            rep.fac <- rep.fac * nx
        }
    }
    rn <- .set_row_names(as.integer(prod(d)))
    structure(cargs, class = "data.frame", row.names = rn)
}

然后你可以像这样使用它

aa<-read.table(text="  A B C D
1 1 x 3 5
2 2 y 4 6", header=T)

bb<-read.table(text="  E F  G  H
1 7 j  9 11
2 8 k 10 12", header=T)

Expand.Grid(aa,bb)
#   A B C D E F  G  H
# 1 1 x 3 5 7 j  9 11
# 2 2 y 4 6 7 j  9 11
# 3 1 x 3 5 8 k 10 12
# 4 2 y 4 6 8 k 10 12

它还允许其他不直接适用于该问题的组合,例如

#combine any number of data.frames and atomic vectors
Expand.Grid(aa,other=1:2, bb)
#give columns a prefix
Expand.Grid(x=aa,y=aa)

【讨论】:

  • 很酷的东西。如果它像data.frame 那样消除列名的歧义,那就太好了。我的意思是,比较:data.frame(aa,aa)Expand.Grid(aa,aa)
  • 好建议弗兰克。我在里面扔了一个make.unique() 来清理名字。
【解决方案3】:

你可以expand.grid行号:

myg <- expand.grid(aa=1:nrow(aa),bb=1:nrow(bb))
cbind(aa[myg$aa,],bb[myg$bb,])

结果中的行名有点难看:

    A B C D E F  G  H
1   1 x 3 5 7 j  9 11
2   2 y 4 6 7 j  9 11
1.1 1 x 3 5 8 k 10 12
2.1 2 y 4 6 8 k 10 12

【讨论】:

    【解决方案4】:

    复制上面的示例,tidyr 包中的交叉函数现在也可以解决问题。

    aa <- read.table(text = "  A B C D
                 1 1 x 3 5
                 2 2 y 4 6", header = T)
    
    bb <- read.table(text = "  E F  G  H
                 1 7 j  9 11
                 2 8 k 10 12", header = T)
    
    
    crossing(aa, bb)
    

    给予

    Source: local data frame [4 x 8]
    
            A      B     C     D     E      F     G     H
          (int) (fctr) (int) (int) (int) (fctr) (int) (int)
      1     1      x     3     5     7      j     9    11
      2     1      x     3     5     8      k    10    12
      3     2      y     4     6     7      j     9    11
      4     2      y     4     6     8      k    10    12
    

    【讨论】:

      猜你喜欢
      • 2012-08-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-04-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多