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)
我该怎么做?
这里有一些选择。不使用任何软件包。
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,正如我在下面的评论中所讨论的。)