R-自动堆叠数据帧的第n列并将其另存为新对象

Han*_*x70 4 stack r subset dataframe

我有一个称为DF的日期框架,其中有三个循环重复的变量:

      A      B      C      A      B      C 
1    a1     b1     c1     a5     b5     c5
2    a2     b2     c2     a6     b6     c6
3    a3     b3     c3     a7     b7     c7
4    a4     b4     c4     a8     b8     c8
Run Code Online (Sandbox Code Playgroud)

我想将第一列A堆叠在第二列A上(如果存在,则堆叠在第三列和第四列上,依此类推),然后对其他变量进行相同的操作,然后将结果另存为新对象(作为矢量) , 例如)。所以我想要获得的是

V_A <- c(a1,a2,a3,a4,a5,a6,a7,a8)
V_B <- c(b1,b2,b3,b4,b5,b6,b7,b8)
V_C <- c(c1,c2,c3,c4,c5,c6,c7,c8)
Run Code Online (Sandbox Code Playgroud)

尽管手动操作非常容易,但是这样

V_A <- DF[,seq(1, ncol(DF), 3]
V_A <- stack(DF)
V_B <- DF[,seq(2, ncol(DF), 3]
V_B <- stack(DF)
V_C <- DF[,seq(3, ncol(DF), 3]
V_C <- stack(DF)
Run Code Online (Sandbox Code Playgroud)

我正在寻找的是一种自动执行此操作的代码,因此它将适用于具有各种变量的数据帧,而不必每次都编写临时代码。总而言之,代码应:1)选择数据帧中的第n列2)堆叠此列3)将结果保存在自动创建的新对象中

我觉得一定有办法做到这一点,但到目前为止我还没有成功。首先十分感谢。

编辑假设我处在稍微不同的情况下,在这些情况下,列重复但名称不完全相同,我仍然想做同样的事情。所以我有:

     A1      B1      C1      A2      B2      C2 
1    a11     b11     c11     a25     b25     c25
2    a12     b12     c12     a26     b26     c26
3    a13     b13     c13     a27     b27     c27
4    a14     b14     c14     a28     b28     c28
Run Code Online (Sandbox Code Playgroud)

而且我要:

V_A <- c(a11,a12,a13,a14,a25,a26,a27,a28)
V_B <- c(b11,b12,b13,b14,b25,b26,b27,b28)
V_C <- c(c11,c12,c13,c14,c25,c26,c27,c28)
Run Code Online (Sandbox Code Playgroud)

我该怎么做?

G. *_*eck 5

这里有一些选择。不使用任何软件包。

1)aperm创建一个3d数组a,排列尺寸并将其重塑为矩阵m,然后将其转换为数据框。仅当所有值均为相同类型时,此选项才有效。(2)和(3)没有此限制。

k <- 3
nr <- nrow(DF)
nc <- ncol(DF)
unames <- unique(names(DF))

a <- array(as.matrix(DF), c(nr, k, nc/k))
m <- matrix(aperm(a, c(1, 3, 2)),, k, dimnames = list(NULL, unames))
as.data.frame(m, stringsAsFactors = FALSE)
Run Code Online (Sandbox Code Playgroud)

给予:

   A  B  C
1 a1 b1 c1
2 a2 b2 c2
3 a3 b3 c3
4 a4 b4 c4
5 a5 b5 c5
6 a6 b6 c6
7 a7 b7 c7
8 a8 b8 c8
Run Code Online (Sandbox Code Playgroud)

如果我们处于问题的EDIT中给出的情况,请替换unames为以下内容,其中DF2是DF,其名称按照注释末尾进行了修改:

unames <- unique(sub("\\d*$", "", names(DF2)))
Run Code Online (Sandbox Code Playgroud)

2)lapply 这将问题中的代码概括化。unames在上面定义:

L <- lapply(split(as.list(DF), names(DF)), unlist)
as.data.frame(L, stringsAsFactors = FALSE)
Run Code Online (Sandbox Code Playgroud)

给予:

   A  B  C
1 a1 b1 c1
2 a2 b2 c2
3 a3 b3 c3
4 a4 b4 c4
5 a5 b5 c5
6 a6 b6 c6
7 a7 b7 c7
8 a8 b8 c8
Run Code Online (Sandbox Code Playgroud)

通过问题的EDIT中显示的输入,可以像这样完成操作DF2,该操作在末尾的Note 中可重复地给出。

names0 <- sub("\\d*$", "", names(DF2))   # names without the trailing digits
L <- lapply(split(as.list(DF2), names0), unlist)
as.data.frame(L, stringsAsFactors = FALSE)
Run Code Online (Sandbox Code Playgroud)

3)重塑 nc并且unames从上方。varying是具有k诸如ith分量包含索引向量的分量的列表c(i, i+k, ...)。似乎reshape不喜欢重复的名称,因此我们将其setNames(DF, 1:nc)作为输入。该解决方案确实具有还生成索引向量time并且id将输出与输入数据相关联的优点。

varying <- split(1:nc, names(DF))
reshape(setNames(DF, 1:nc), dir = "long", varying = varying, v.names = unames)
Run Code Online (Sandbox Code Playgroud)

给予:

    time  A  B  C id
1.1    1 a1 b1 c1  1
2.1    1 a2 b2 c2  2
3.1    1 a3 b3 c3  3
4.1    1 a4 b4 c4  4
1.2    2 a5 b5 c5  1
2.2    2 a6 b6 c6  2
3.2    2 a7 b7 c7  3
4.2    2 a8 b8 c8  4
Run Code Online (Sandbox Code Playgroud)

通过问题的EDIT中显示的输入,它实际上得到了简化。我们不再需要使用,setNames(DF, 1:nc)而可以直接使用数据框作为输入。另外,我们可以使用varying=TRUE(另请参阅@thelatemail的注释)代替计算的复杂参数varying。输入DF2如末尾的注释所示,并且与names0上面的(2)相同。

reshape(DF2, dir = "long", varying = TRUE, v.names = unique(names0))
Run Code Online (Sandbox Code Playgroud)

注意:

Lines <- "      A      B      C      A      B      C 
1    a1     b1     c1     a5     b5     c5
2    a2     b2     c2     a6     b6     c6
3    a3     b3     c3     a7     b7     c7
4    a4     b4     c4     a8     b8     c8"
DF <- read.table(text = Lines, as.is = TRUE, check.names = FALSE)

DF2 <- setNames(DF, c("A1", "B1", "C1", "A2", "B2", "C2")) # test input
Run Code Online (Sandbox Code Playgroud)

Upate: 许多简化。DF2在末尾的注释中还添加了注释,并讨论了每种方法中如何修改代码以对其进行处理。(一种通用的方法可能只是将DF2减少为DF,正如我在下面的评论中所讨论的。)