【问题标题】:How to reshape tabular data to one row per group如何将表格数据重塑为每组一行
【发布时间】:2016-06-20 21:53:54
【问题描述】:

我是一名 R(和编码新手),我正在寻找一种方法将下面的表 A 重新配置为表 B。

表 A:

type   x1  x2  x3  
A      4   6   9  
A      7   4   1  
A      9   6   2   
B      1   3   8  
B      2   7   9

我正在寻找可以转换为以下内容的代码

表 B:

type   x1  x2  x3  x1'  x2'  x3'  x1'' x2'' x3''  
A      4    6   9   7    4   1    9     6   2  
B      1    3   8   2    7   9   

真正的表 A 超过 150000 行和 36 列。具有 2100 个独特的“类型”值。

感谢您的帮助。

-肖恩

【问题讨论】:

  • 欢迎来到 StackOverflow!我注意到向量 B 是多维的,所以它就是我们所说的 R 语言中的 data.frame 或矩阵。你是这个意思吗?还是您想要 3 个独立的向量?
  • 我们也可以将向量 B 称为矩阵。我编辑了原始问题以使其更清晰。谢谢!
  • 当然。我做了一个临时解决方案,然后我们受到了不加评论的不投票巨魔怪物的攻击,所以我不得不删除它。如果您的数据很大,或者如果您需要经常这样做,我们无论如何都应该找到一个更加程序化的解决方案。唯一真正的困难是,在这种格式中,我们需要为 B 的缺失单元格添加 NA。所以我认为使用 fill = Tfor 循环、cbindrbind 是一种方法.
  • 真正的表A超过150000行36列。具有 2100 个独特的“类型”值。
  • @Hack-R 这不是一个怪物,我喜欢它,因为它是对示例的文字提取,并且不适用于任何真实数据。照原样,答案对社区没有帮助。请随时改进帖子。

标签: r reshape


【解决方案1】:

对我来说,这个解决方案似乎很简单

# split the data frame by type and use unlist, which will provide names
ld <- lapply(split(d[-1], d[["type"]]), unlist)

# gather all the unique names in the list
ldNames <- Reduce(unique, lapply(ld, names))

# use the names to index each list element, which makes them
# all of equal length and suitable for row binding.  
do.call(rbind, lapply(ld, function(x) x[ldNames]))
#   x11 x12 x13 x21 x22 x23 x31 x32 x33
# A   4   7   9   6   4   6   9   1   2
# B   1   2  NA   3   7  NA   8   9  NA

如果上面的输出顺序不满意,可以重新排列:

# save the output from above
d2 <- do.call(rbind, lapply(ld, function(x) x[ldNames]))
# reorder the names
ldNames_sorted <- c(matrix(ldNames, ncol = (ncol(d) - 1), byrow = TRUE))

# apply the new order.
d2 <- d2[, ldNames_sorted]
#  x11 x21 x31 x12 x22 x32 x13 x23 x33
#A   4   6   9   7   4   1   9   6   2
#B   1   3   8   2   7   9  NA  NA  NA

要为类型添加一列而不是使用行名,一种方法是:

data.frame(type = row.names(d2), d2)

【讨论】:

  • 喜欢lapplysplit结合的方法。伟大的! (+1)。但是,B 的最终输出与问题不匹配,您可以更新解决方案;)
  • 最后一个问题。我们需要带有“类型”的列有一个列标题。
  • @SDM1212 我在末尾添加了最后一行以添加type 列。希望有帮助!
  • @Jota - 完美!感谢您的帮助。
【解决方案2】:

聚会有点晚了,但这也可以通过data.table 包的dcast 函数轻松完成,因为您可以在其中使用多个value.var

library(data.table)

dcast(setDT(d), type ~ rowid(type), value.var = c('x1','x2','x3'), sep = '')

给出:

   type x11 x12 x13 x21 x22 x23 x31 x32 x33
1:    A   4   7   9   6   4   6   9   1   2
2:    B   1   2  NA   3   7  NA   8   9  NA

你也可以在基础 R 中这样做:

d$num <- ave(d$x1, d$type, FUN = seq_along)
reshape(d, idvar = 'type', direction = 'wide', timevar = 'num', sep = '')

【讨论】:

    【解决方案3】:
    a <- data.frame(type=c("A", "A","A", "B", "B"), x1 = c(4,7,9,1,2),x2=c(6,4,6,3,7),
                   x3 = c(9,1,2,8,9))
    
    library(dplyr)
    tmp <-
    a %>% 
      group_by(type) %>%
      summarise(no_rows = length(type))
    
    for(i in unique(a$type)){
      n <- max(tmp$no_rows) - nrow(a[a$type == i,])
      nn <- nrow(a)
      if(n > 0){
        for(ii in 1:n){
          a[nn+ii,] <- c(i,NA,NA,NA)
        }    
      }
    
    }
    
    a <- a[order(a$type),]
    a$timevar <- seq(1:max(tmp$no_rows) )
    
    b<-reshape(a,timevar="timevar",idvar="type",direction="wide",drop = F)
    b
    
      type x1.1 x2.1 x3.1 x1.2 x2.2 x3.2 x1.3 x2.3 x3.3
    1    A    4    6    9    7    4    1    9    6    2
    4    B    1    3    8    2    7    9 <NA> <NA> <NA>
    

    【讨论】:

    • 我认为你的逻辑是合理的,但它可以简化一点。请参阅我认为做同样事情的答案(我认为 - 这是一个看似困难的问题)
    • @thelatemail 我毫不怀疑你是对的。我会 +1 你的答案
    【解决方案4】:

    @Hack-R 答案的变化:

    A$num <- with(A, ave(as.character(type), type, FUN=seq_along) )
    tmp <- cbind(A[c(1,5)], stack(A[2:4]))
    tmp$time <- paste(tmp$ind, tmp$num, sep=".")
    
    reshape(tmp[c("type","time","values")], idvar="type", timevar="time", direction="wide")
    
    #  type values.x1.1 values.x1.2 values.x1.3 values.x2.1 values.x2.2 values.x2.3 values.x3.1 values.x3.2 values.x3.3
    #1    A           4           7           9           6           4           6           9           1           2
    #4    B           1           2          NA           3           7          NA           8           9          NA
    

    还有一个有趣的 dplyr 版本:

    library(dplyr)
    library(tidyr)
    
    A %>%
      gather(var, value, -type) %>%
      group_by(type,var) %>%
      mutate(time=seq_along(var)) %>% 
      ungroup() %>%
      unite(grpvar, c(time,var) ) %>%
      spread(grpvar, value )
    
    #Source: local data frame [2 x 10]
    #
    #   type  1_x1  1_x2  1_x3  2_x1  2_x2  2_x3  3_x1  3_x2  3_x3
    #  (chr) (int) (int) (int) (int) (int) (int) (int) (int) (int)
    #1     A     4     6     9     7     4     1     9     6     2
    #2     B     1     3     8     2     7     9    NA    NA    NA
    

    【讨论】:

    • 嗨 - 我不确定如何将它与@Hack-R 的答案一起使用。
    • @SDM1212 - 根据 Hack-R 的逻辑,它本身就是一个完整的答案。您不必将它与其他任何东西一起使用。
    • 好的,我开始明白了,我得到了运行示例。因此,对于真实数据,obs 的数量。会改变,但总会有 22 个变量。我不确定如何更改此示例以使用我的真实数据。
    【解决方案5】:

    试一试,解决方案不是那么简洁,只是给你一个提示。我认为很多事情都可以改进。

    但最后我们必须在这里介绍 NA :(

    zz <- "type   x1  x2  x3  
    A      4   6   9  
    A      7   4   1  
    A      9   6   2   
    B      1   3   8  
    B      2   7   9"
    
    dA <- read.table(text=zz, header=T)
    
    
    tmp<-(sapply(unique(dA$type), FUN=function(x) as.vector(t(dA[dA$type == x, -1]))))
    
    t(sapply(tmp, '[', seq(max(sapply(tmp, length)))))
          [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9]
    [1,]    4    6    9    7    4    1    9    6    2
    [2,]    1    3    8    2    7    9   NA   NA   NA
    

    【讨论】:

      猜你喜欢
      • 2019-09-23
      • 2017-07-19
      • 2018-12-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-04-04
      • 2018-07-27
      • 2017-07-20
      相关资源
      最近更新 更多