我有一个名为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
我想在第二个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)
虽然手动操作很容易,但是这样
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)
我正在寻找的是一个自动执行此操作的代码,因此它可以用于包含每个变量数的数据帧,而无需每次都编写特殊代码。 总而言之,代码应该: 1)选择数据帧中的每第n列 2)堆叠此列 3)将结果保存在自动创建的新对象中
我觉得必须有办法做到这一点,但到目前为止我还没有成功。非常感谢提前。
EDIT 假设我的情况略有不同,其中列重复但名称不完全相同,我仍然想做同样的事情。所以我有:
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
我希望:
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)
我该怎么做?
答案 0 :(得分:5)
以下是一些替代方案。没有包使用。
1)精子创建一个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)
,并提供:
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
如果我们处于问题编辑中给出的情况,则将unames
替换为DF2为DF的以下内容,并根据结尾处的注释修改名称:
unames <- unique(sub("\\d*$", "", names(DF2)))
2)lapply 这概括了问题中的代码。 unames
定义如上:
L <- lapply(split(as.list(DF), names(DF)), unlist)
as.data.frame(L, stringsAsFactors = FALSE)
,并提供:
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
根据问题的编辑中显示的输入,可以这样完成,其中DF2
在最后的注释中可重复给出。
names0 <- sub("\\d*$", "", names(DF2)) # names without the trailing digits
L <- lapply(split(as.list(DF2), names0), unlist)
as.data.frame(L, stringsAsFactors = FALSE)
3)重塑 nc
和unames
来自上方。 varying
是一个包含k
组件的列表,例如第i个组件包含索引向量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)
,并提供:
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
问题的编辑中显示的输入实际上简化了。我们不再需要使用setNames(DF, 1:nc)
,但可以直接使用数据框作为输入。此外,我们可以使用varying=TRUE
(也参见@ thelatemail的评论),而不是计算varying
的复杂参数。输入DF2
如末尾的注释所示,names0
与上面的(2)相同。
reshape(DF2, dir = "long", varying = TRUE, v.names = unique(names0))
注意:强>
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
Upate:一些简化。最后在Note中添加了DF2
,并在每个备选方案中讨论如何修改代码来处理它。 (正如我在下面的评论中讨论的那样,一般方法可能只是将DF2减少到DF。)
答案 1 :(得分:1)
stack
和unstack
NEWDF=stack(DF)
NEWDF$ind=as.character(NEWDF$ind)
NEWDF$ind=rep(NEWDF$ind[1:(dim(NEWDF)[1]/2)],2)
unstack(NEWDF)
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
答案 2 :(得分:1)
我们可以按列拆分然后行绑定(using G. Grothendieck's example data, DF and DF2):
library(data.table) #rbindlist for binding columns with different names.
k <- 3
nr <- nrow(DF)
nc <- ncol(DF)
rbindlist(split.default(DF, rep(1:(nc/k), each = k)))
# 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
rbindlist(split.default(DF2, rep(1:(nc/k), each = k)), use.names = FALSE)
# A1 B1 C1
# 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
答案 3 :(得分:0)
这使您可以将第n列堆叠成分隔的data.frames,存储在列表中:
library(tidyr)
cols <- ncol(dat)
set_width <- 3
result <- dat %>%
gather(key, value) %>%
split(., rep(rep(1:set_width, each = nrow(dat)), ncol(dat)/set_width))
数据:强>
dat <- read.table(text = " 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", check.names = TRUE)
(如果您的变量名称是非唯一的,即它们完全重复,请将janitor::clean_names()
插入管道中。
答案 4 :(得分:0)
我们可以使用 bind_rows
包中的 dplyr
:
df1 <- df[,1:3]
df2 <- df[,4:6]
colnames(df2) <- colnames(df1) # for differing colnames
bind_rows(df1, df2)
输出:
A B C
<chr> <chr> <chr>
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