STEM:在 R 中创建每一行的顺序组合

STEM: Create sequential combinations of each row in R

想在 R 中创建一个新的数据框,它采用一组行,并以 nrow * nrow * ncol 格式组合每个变体。

library(dplyr)
dat <- read.table(text =
        " Animal Color Size
          Cat Orange 10
          Dog Black 20", header=TRUE)

想要这样的输出:

Animal  Color   Size 
Cat     NA      NA
Cat     Orange  NA
Cat     Orange  10
Dog     NA      NA
Dog     Black   NA
Dog     Black   20

R 中是否有可以执行此操作的函数 -- 类似于 expand.grid

expand.grid(dat$Animal, dat$Color, dat$Size) %>% arrange(Var1, Var2, Var3) #Note: this does not give the correct answer.

我可以使用以下方法创建数据第一行的第一块:

dat <- c("Cat", "Orange", 10)

counter <- 1
datInner <- list()
for(i in 1:length(dat)){ # loops through 3x

  # i <- 3
   datInner[[i]] <- dat[1:i]
   counter <- counter + 1

}

library(plyr)
# Adapted from 
plyr::rbind.fill(lapply(datInner, function(y){as.data.frame(t(y),
            stringsAsFactors = FALSE)}))

    # V1     V2   V3
    # 1 Cat   <NA> <NA>
    # 2 Cat Orange <NA>
    # 3 Cat Orange   10

注意:将此函数类型称为顺序树扩展矩阵 (STEM)。它需要一个 table 和一棵节点深度不同的树,仅列出端节点,并将其转换为 table 和树的所有顺序组合。

dplyr 解决方案 - 不是很通用。

library(dplyr)
rbind(
  dat  %>%  
    group_by(Animal) %>%
    summarize(Color = NA, Size = NA) %>%
    ungroup(),
  dat %>%
    group_by(Animal, Color) %>%
    summarize(Size = NA) %>%
    ungroup(),
  dat) %>% arrange(Animal)

#  Animal  Color  Size
#1    Cat   <NA>    NA
#2    Cat Orange    NA
#3    Cat Orange    10
#4    Dog   <NA>    NA
#5    Dog  Black    NA
#6    Dog  Black    20

应该有比这更有效的答案,这只是一个尝试!

m <- t(sapply(1:ncol(dat), function(i) c(1:i, rep(NA, (ncol(dat)-i)))))
m
#     [,1] [,2] [,3]
#[1,]    1   NA   NA
#[2,]    1    2   NA
#[3,]    1    2    3

#2. now i apply each row to original data (dat) Basically performing subset
m1 <- apply(dat, 1, function(i) apply(m, 1, function(j) i[j]))
data.frame(matrix(m1, byrow = T, ncol = ncol(dat)))
#   X1     X2   X3
#1 Cat   <NA> <NA>
#2 Cat Orange <NA>
#3 Cat Orange   10
#4 Dog   <NA> <NA>
#5 Dog  Black <NA>
#6 Dog  Black   20

注意:最后一列是 factor 因为它在 matrix

事实证明,for 循环可以用列表解决这个问题比我最初想象的要容易得多,而且它可以推广到具有不同节点深度的 nrows。这与乔尔对两行示例的出色回答的速度相同。但是,目前可以将其并行化,以便在使用 Matrix 之外更快地读取。注意:如果节点深度不同,Joel 和我自己的回答都需要 unique——例如,NA 代替 dat table.

中的 20 值
library(dplyr)
datInner <- list()
for(i in 1:ncol(dat)){ datInner[[i]] <- dat[1:i] }; # foreach %dopar% for parallel
datInner %>% bind_rows