【问题标题】:Rearrange a matrix in R using two factors使用两个因子重新排列 R 中的矩阵
【发布时间】:2013-02-07 07:12:56
【问题描述】:

这就是问题所在。有一个N行C列的矩阵,有两个因子:idsgroup,长度均为N。例如:

m <- matrix( 1:25, nrow= 5, byrow= T )
id <- factor( c( "A", "A", "A", "B", "B" ) )
group <- factor( c( "a", "b", "c", "a", "c" ) )

并非所有因素组合都存在,但每个因素组合仅存在一次。任务是转换矩阵m,使其具有length( levels( id ) ) 行和length( levels( group ) ) * C 列。换句话说,创建一个矩阵,其中每个变量对应于原始列和因子group 的所有可能水平之间的组合。缺失值(对于不存在的 id 和 group 组合)由 NA 替换。这是上述示例的所需输出:

  a.1 a.2 a.3 a.4 a.5 b.1 b.2 b.3 b.4 b.5 c.1 c.2 c.3 c.4 c.5
A   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15
B  16  17  18  19  20  NA  NA  NA  NA  NA  21  22  23  24  25

我编写了自己的函数,但它非常无效,而且我确信它复制了一些极其简单的函数。

matrixReshuffle <- function( m, ids.row, factor.group ) {

  nr <- nrow( m )
  nc <- ncol( m )
  if( is.null( colnames( m ) ) ) colnames( m ) <- 1:nc

  ret <- NULL
  for( id in levels( ids.row ) ) {

    r <- c()

    for( fg in levels( factor.group ) ) {

      d <- m[ ids.row == id & factor.group == fg,, drop= F ]
      if( nrow( d ) > 1 )
        stop( sprintf( "Too many matches for ids.row= %s and factor.group= %s", id, fg ) )
      else if( nrow( d ) < 1 ) {
        r <- c( r, rep( NA, nc ) )
      } else {
        r <- c( r, d[1,] )
      }

    }

    ret <- rbind( ret, r )

  }

  colnames( ret ) <- paste( rep( levels( factor.group ), each= nc ), rep( colnames( m ), length( levels( factor.group ) ) ), sep= "." )
  rownames( ret ) <- levels( ids.row )

  return( ret )
}

【问题讨论】:

    标签: r matrix reshape reshape2


    【解决方案1】:

    遵循@Aaron 的建议:

    使用来自reshape2meltacast

    require(reshape2)
    df <- as.data.frame(m)
    names(df) <- seq_len(ncol(df))
    df.m <- melt(df)
    df.m$id <- rep(id, nrow(df.m)/length(id))
    df.m$group <- rep(group, nrow(df.m)/length(group))
    
    o <- acast(df.m, id ~ group+variable, value.var="value")
    colnames(o) <- sub("_", ".", colnames(o))
    
    #   a.1 a.2 a.3 a.4 a.5 b.1 b.2 b.3 b.4 b.5 c.1 c.2 c.3 c.4 c.5
    # A   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15
    # B  16  17  18  19  20  NA  NA  NA  NA  NA  21  22  23  24  25
    

    您可以将其转换回矩阵。

    【讨论】:

    • +1 不错的解决方案;正如我在对自己的回答的评论中所说,这是我更喜欢的。您可能会考虑使用acast 直接给出矩阵,并让名称匹配,可能是在熔化之前names(df) &lt;- 1:5 和在铸造之后colnames(out) &lt;- sub("_", ".", colnames(out))(其中out 是铸造的结果)。
    • @Aaron,是的,我应该使用acast。感谢那。我想给出一个总体想法,并将其余的编辑留给 OP。但是现在,根据您的评论,我已对其进行了完整的编辑。
    • 我花了一些时间浏览手册页 :-) melt() 和 [ad]cast 是很好的发现函数。
    【解决方案2】:

    对于所有的矩阵索引爱好者...

    C <- ncol(m)
    to.row <- matrix(rep(as.numeric(id), C), ncol=C)
    to.col <- sweep(col(m),1,(as.numeric(group)-1)*C,`+`)
    out <- array(dim=c(nlevels(id), nlevels(group)*C),
                 dimnames=list(levels(id), as.vector(t(outer(levels(group), 1:C, paste, sep=".")))))
    out[cbind(as.vector(to.row), as.vector(to.col))] <- m
    out
    #   a.1 a.2 a.3 a.4 a.5 b.1 b.2 b.3 b.4 b.5 c.1 c.2 c.3 c.4 c.5
    # A   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15
    # B  16  17  18  19  20  NA  NA  NA  NA  NA  21  22  23  24  25
    

    【讨论】:

    • 我很欣赏这张支票,但老实说,@Arun 使用reshape2 的解决方案是我更喜欢的;这是一个更简单的解决方案,并且这些想法更容易推广到其他重塑需求。
    【解决方案3】:

    这是@Arun 回复的一个版本,稍作修改以便(对我而言)更容易理解。另外,我总是对复制群体因素持谨慎态度。我发现在实践中,这是系统错误的潜在来源之一。最好直接接管 id 和 group 并让 melt() 完成复制因子的工作。但这些只是小事。

    # add the aggregating variables to the matrix, converted to data frame
    df <- data.frame( m )
    df$id <- id
    df$group <- group
    
    # reshape the data frame
    require( reshape2 )
    df.m <- melt( df, c( "id", "group" ) )
    df <- dcast( df.m, id ~ group + variable )
    
    # df has the required shape, but convert it back to a matrix
    rownames( df ) <- df$id
    df$id <- NULL
    m.reshaped <- as.matrix( df )
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-03-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-06-09
      • 2018-05-14
      • 2014-01-27
      相关资源
      最近更新 更多