R:将多个列合并为同一行中的列单元格对

R:将多个列合并为同一行中的列单元格对,r,dataframe,reshape,R,Dataframe,Reshape,我希望将数据帧中的多个列合并/配对为同一行中的列单元格对。例如,df1应转换为df2 df1 col1 col2 col3 1 2 3 0 0 1 df2 c1 c2 1 2 1 3 2 3 0 0 0 1 0 1 该解决方案应可扩展为df1s(方式)超过三列 我考虑过熔化/重塑/dcast,但还没有找到解决方案。数据帧中没有NAs。谢谢大家! 编辑:重塑刚刚产生了错误,所以我考虑 combn(df1[1,2] comb2您

我希望将数据帧中的多个列合并/配对为同一行中的列单元格对。例如,
df1
应转换为
df2

df1

col1 col2 col3
1    2    3   
0    0    1
df2

c1  c2
1    2
1    3
2    3
0    0
0    1
0    1
该解决方案应可扩展为
df1
s(方式)超过三列

我考虑过熔化/重塑/dcast,但还没有找到解决方案。数据帧中没有NAs。谢谢大家!

编辑:
重塑
刚刚产生了错误,所以我考虑

combn(df1[1,2]

comb2您的编辑与我下面的答案非常相似,您只需要在df1的行上每次迭代都返回结果。使用data.table是加速rbind的好方法

编辑:不幸的是,当我切换到data.table方法时,结果发现rbindlist()导致了答案错误(如下面的评论所指出的)。因此,尽管可能会稍微慢一点,但我认为预分配数据帧和使用rbind可能是最好的选择

EDIT2:将预先分配的df切换到更一般的行数

df1 = as.data.frame(matrix(c(1,2,3,4,0,0,1,1), byrow = TRUE, nrow = 2))
nrow_combn = nrow(t(combn(df1[1,], m = 2)))
nrow_df = nrow(df1) * nrow_combn
df2 = data.frame(V1 = rep(0, nrow_df), V2 = rep(0, nrow_df))
for(i in 1:nrow(df1)){
  df2[(((i-1)*nrow_combn)+1):(i*(nrow_combn)), ] = data.frame(t(combn(df1[i,], m = 2)))
}

以下是我将采取的方法

创建一个函数,该函数使用来自“data.table”的
rbindlist
和来自base R的
combn
。该函数如下所示:

lengthener <- function(indf) {
  temp <- rbindlist(
    combn(names(indf), 2, FUN = function(x) indf[x], simplify = FALSE),
    use.names = FALSE, idcol = TRUE)
  setorder(temp[, .id := sequence(.N), by = .id], .id)[, .id := NULL][]
}
在一些较大的数据上也进行测试:

set.seed(1)
M <- as.data.frame(matrix(sample(100, 100*100, TRUE), 100))
system.time(out <- lengthener(M))
#    user  system elapsed 
#    0.19    0.00    0.19 
out
#         V1 V2
#      1: 27 66
#      2: 27 27
#      3: 27 68
#      4: 27 66
#      5: 27 56
#     ---      
# 494996: 33 13
# 494997: 33 66
# 494998: 80 13
# 494999: 80 66
# 495000: 13 66
set.seed(1)

我对R不熟悉,因此不是很有文化,但我已经尝试重新塑造,将其转换为长格式。但是,我找不到一种方法在一点上只对两列。请在问题中包含您尝试的代码。谢谢-我已经包含了它。
重塑刚刚产生的错误
——但这不是代码。难道你不想理解为什么你所尝试的会产生错误吗?谢谢你的努力!我尝试过你的方法,但结果不是你想要的:它产生2行6列,只是复制每个单元格的元素。我不知道为什么,因为基本的
t(combn(…
解决方案产生了正确的结果,但一次只能生成一行。无论用户使用哪种工具,对象的增长速度都可能很慢。@RomanLuštrik您读过我发布的链接吗?在那个模拟中,这种方法比预分配数据帧更快。感谢您的编辑,@AndyMcKenzie!它适用于此示例,但事实并非如此可缩放
nrow_df=ncol(df1)*nrow(df1)的b/c
。例如,在初始样本中有四列将产生4个choose 2=6个组合,每行总共12个,而代码只创建了8个。编辑:修复可能是
nrow\u df5谢谢,@Ananda Mahto!我已经成功地处理了上面的另一个答案,但感谢您的努力!@user5835099,没问题。只是仅供参考,我已经在中添加了这一点。
lengther()
函数还允许您为
combn
指定“n”。我的答案主要是为了说明如果需要,如何实现更高的效率,因为Andy无法使代码与“data.table”一起工作。
set.seed(1)
M <- as.data.frame(matrix(sample(100, 100*100, TRUE), 100))
system.time(out <- lengthener(M))
#    user  system elapsed 
#    0.19    0.00    0.19 
out
#         V1 V2
#      1: 27 66
#      2: 27 27
#      3: 27 68
#      4: 27 66
#      5: 27 56
#     ---      
# 494996: 33 13
# 494997: 33 66
# 494998: 80 13
# 494999: 80 66
# 495000: 13 66
funAMK <- function(indf) {
  nrow_combn = nrow(t(combn(indf[1,], m = 2)))
  nrow_df = nrow(indf) * nrow_combn
  df2 = data.frame(V1 = rep(0, nrow_df), V2 = rep(0, nrow_df))
  for(i in 1:nrow(indf)){
    df2[(((i-1)*nrow_combn)+1):(i*(nrow_combn)), ] = data.frame(t(combn(indf[i,], m = 2)))
  }
  df2
}

> system.time(funAMK(M))
   user  system elapsed 
  16.03    0.16   16.37