【问题标题】:Stack all columns into two columns with categorical column in R将所有列堆叠成两列,R中的分类列
【发布时间】:2015-01-15 18:53:01
【问题描述】:

首先让我创建一些测试数据:

dat <- data.frame(Model_A=rnorm(10, 10), Model_B=rnorm(10, 12), Data_A=rnorm(10, 11), 
Data_B=rnorm(10, 13))

# this produces the following
dat

     Model_A   Model_B    Data_A   Data_B
1  10.421684 13.201037 11.711313 13.18555
2   9.529258 11.086655 12.015787 14.13989
3   9.483633 10.697859 10.123176 15.50154
4  10.623490 11.171480  9.406222 12.56696
5  10.460739 10.925262 10.640612 11.98662
6   9.351494 10.276617 11.717629 13.00709
7  10.264206 11.587463 10.653878 13.33615
8  10.183569 13.187894 10.127552 13.87615
9   8.832003  9.739279 10.970686 13.26850
10 10.932207 11.974472 10.374939 12.11782

我想要做的是将所有列“堆叠”成两个列,称为“模型”和“数据”。列包含单个“模型”和“数据”列的每个唯一组合。我还想创建一个对数据进行分类的索引列。我要创建的数据集是:

Cat             Model       Data
Model_A_Data_A  10.421684   11.711313
Model_A_Data_A  9.529258    12.015787
Model_A_Data_A  9.483633    10.123176
Model_A_Data_A  10.62349    9.406222
Model_A_Data_A  10.460739   10.640612
Model_A_Data_A  9.351494    11.717629
Model_A_Data_A  10.264206   10.653878
Model_A_Data_A  10.183569   10.127552
Model_A_Data_A  8.832003    10.970686
Model_A_Data_A  10.932207   10.374939
Model_A_Data_B  10.421684   13.18555
Model_A_Data_B  9.529258    14.13989
Model_A_Data_B  9.483633    15.50154
Model_A_Data_B  10.62349    12.56696
Model_A_Data_B  10.460739   11.98662
Model_A_Data_B  9.351494    13.00709
Model_A_Data_B  10.264206   13.33615
Model_A_Data_B  10.183569   13.87615
Model_A_Data_B  8.832003    13.2685
Model_A_Data_B  10.932207   12.11782
Model_B_Data_A  13.201037   11.711313
Model_B_Data_A  11.086655   12.015787
Model_B_Data_A  10.697859   10.123176
Model_B_Data_A  11.17148    9.406222
Model_B_Data_A  10.925262   10.640612
Model_B_Data_A  10.276617   11.717629
Model_B_Data_A  11.587463   10.653878
Model_B_Data_A  13.187894   10.127552
Model_B_Data_A  9.739279    10.970686
Model_B_Data_A  11.974472   10.374939
Model_B_Data_B  13.201037   13.18555
Model_B_Data_B  11.086655   14.13989
Model_B_Data_B  10.697859   15.50154
Model_B_Data_B  11.17148    12.56696
Model_B_Data_B  10.925262   11.98662
Model_B_Data_B  10.276617   13.00709
Model_B_Data_B  11.587463   13.33615
Model_B_Data_B  13.187894   13.87615
Model_B_Data_B  9.739279    13.2685
Model_B_Data_B  11.974472   12.11782

我认为它必须能够使用 reshape 包中的一些工具来完成,但我无法理解如何使用“模型”和“数据”列的所有独特组合来获取索引列。

值得注意的是,我的实际数据集有 9 个“模型”列和 15 个“数据”列。

谢谢。

【问题讨论】:

  • 您想要的输出是否与提供的数据集相对应?
  • 啊,我刚刚意识到,在很长一段时间内我再次生成数据以创建所需的输出,这是我的错误。我现在会纠正这个问题。

标签: r reshape


【解决方案1】:

这也是一种可能的解决方案:

dat <- data.frame(Model_A=rnorm(10, 10), Model_B=rnorm(10, 12), Data_A=rnorm(10, 11), 
              Data_B=rnorm(10, 13))
model.names <- grep("Model",names(dat),value=TRUE)
data.names <- grep("Data",names(dat),value=TRUE)

new.dat <- 
lapply(model.names,function(m) {
  lapply(data.names,function(d) {
    md <- cbind(dat[,m],dat[,d])
    md.name <- rep(paste0(m,"_",d),nrow(md))
    data.frame(md.name,md)
  })
 })

new.dat <- do.call(rbind,lapply(new.dat,function(l) do.call(rbind,l)))
names(new.dat) <- c("Cat","Model","Data")

首先,它提取模型和数据列的名称。之后,使用 lapply 两次,它为模型和数据的每个组合创建一个数据框,将适当的名称放在第一列中。最后一步是将所有这些位于双重嵌套列表中的数据框放入单个数据框中。

【讨论】:

    【解决方案2】:

    你可以试试

    1. 创建“列名”组合 (combn(colnames...))
    2. 从“索引”中删除属于同一类型的名称(即 Data_A、Data_B 或 Model_A、Model_B)
    3. 子集“indx”以创建“indx2”
    4. split“indx2”通过“columns”创建列表(“lst”)
    5. 更改“lst”的名称以识别组(“Cat”)
    6. 根据“lst”名称对“dat”进行子集化,并使用tidyr 中的unnest 来绑定列表元素。

      library(tidyr)
      indx <- combn(colnames(dat),2)
      indx1 <- apply(indx, 2, function(x) length(unique(sub('_.*', '', x)))>1)
      indx2 <- indx[,indx1]
      lst <- split(indx2, col(indx2))
      names(lst) <- apply(indx2, 2, paste, collapse='_')
      
      res <-  unnest(lapply(lst,function(x) {
                     x1 <- dat[x] 
                     colnames(x1) <- c('Model', 'Data')
                     x1}), Cat)
      head(res,2)
      #           Cat     Model      Data
      #1 Model_A_Data_A  9.676133  9.491202
      #2 Model_A_Data_A 11.599942 10.446249
      

    或者您可以使用expand.grid 和来自data.tablerbindlist

        indx <- expand.grid(split(colnames(dat), 
                      sub("_.*", '', colnames(dat))))[2:1]
        indx1 <- transform(indx, Cat=paste(Model, Data, sep="_"))
    
        library(data.table)
        res1 <-  rbindlist(apply(indx1, 1, function(x) {
                    x1 <- unname(x)
                  data.frame(Cat=x1[3],dat[x1[1:2]])}))
    

    【讨论】:

    • 感谢您提供出色的解决方案。它几乎就在那里,但还没有提供分类的“Cat”列,我需要识别不同的列组合。
    • 谢谢,现在也可以了。我将给 @Stibu 答案,因为它仅适用于基本功能。
    • @Catchment_Jack 我用 expand.grid 更新,步骤更少。
    猜你喜欢
    • 2016-02-27
    • 1970-01-01
    • 1970-01-01
    • 2012-11-15
    • 2013-04-01
    • 1970-01-01
    • 2020-02-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多