以data.table为轴心,类似于rehape melt函数

以data.table为轴心,类似于rehape melt函数,r,data.table,reshape,R,Data.table,Reshape,我在这里已经阅读了一些关于类似问题的参考资料,但是还没有找到解决方案,我想知道是否有任何方法可以仅使用data.table完成以下操作 我将使用一个简化的示例,但实际上,我的数据表有>1000列,类似于var1、var2、。。。var1000等 dt <- data.table(uid=c("a","b"), var1=c(1,2), var2=c(100,200)) 也就是说,除了uid之外的所有列都列在一列下,相应的值在相邻列中。我试过结合列表等,但可能遗漏了一些显而易见的东西 dt

我在这里已经阅读了一些关于类似问题的参考资料,但是还没有找到解决方案,我想知道是否有任何方法可以仅使用data.table完成以下操作

我将使用一个简化的示例,但实际上,我的数据表有>1000列,类似于var1、var2、。。。var1000等

dt <- data.table(uid=c("a","b"), var1=c(1,2), var2=c(100,200))
也就是说,除了uid之外的所有列都列在一列下,相应的值在相邻列中。我试过结合列表等,但可能遗漏了一些显而易见的东西

dt中的所有UID都是唯一的


提前感谢。

有关data.table重塑,请尝试以下操作:

dt[, list(variable = names(.SD), value = unlist(.SD, use.names = F)), by = uid]

语法的成本是值得的;该功能运行非常快

stack
通常优于
melt

使用
堆栈
解决此问题的简单方法是:

dt[, stack(.SD), by = "uid"]
当然,如果需要,您可以指定
.SDcols
。然后,使用
setnames()


(自我宣传提醒)

我编写了一些函数,并将它们放在一个名为“splitstackshape”的包中。其中一个函数名为
Stacked()
,而“splitstackshape”包的函数应该运行得非常快

这与仅仅将
data.table
中的所有剩余列堆叠有点不同。它更类似于基本R的
restrape()
,而不是“restrape2”中的
melt()
。下面是一个运行中的
Stacked()
示例

我已经创建了一个相当大的
data.table
来做这个测试。有50个数字列需要堆叠,50个因子列需要堆叠。我还进一步优化了@Andreas的答案

数据 ^^我不知道为什么安德烈亚斯现在的回答这么慢。我所做的“优化”基本上是
unlist
,而不使用
by
,这对“varB”(factor)列产生了巨大的影响

手动方法仍然比“splitstackshape”中的函数快,但这些都是毫秒,还有一些非常紧凑的单行代码

样本输出 以下是
Stacked()
的输出,仅供参考。这是一个“堆叠的”
数据的
列表。表
s,每个堆叠的变量有一个列表项

test1()
# $varA
#           uid .time_1       varA
#      1:     1      01 -0.6264538
#      2:     1      02 -0.8043316
#      3:     1      03  0.2353485
#      4:     1      04  0.6179223
#      5:     1      05 -0.2212571
#     ---                         
# 499996: 10000      46 -0.6859073
# 499997: 10000      47 -0.9763478
# 499998: 10000      48  0.6579464
# 499999: 10000      49  0.7741840
# 500000: 10000      50  0.5195232
# 
# $varB
#           uid .time_1 varB
#      1:     1      01    D
#      2:     1      02    A
#      3:     1      03    S
#      4:     1      04    L
#      5:     1      05    T
#     ---                   
# 499996: 10000      46    A
# 499997: 10000      47    W
# 499998: 10000      48    H
# 499999: 10000      49    U
# 500000: 10000      50    W
下面是
merged.stack
输出的样子。它类似于从基本R使用
restrape(…,direction=“long”)
时得到的结果

test2()
#           uid .time_1       varA varB
#      1:     1      01 -0.6264538    D
#      2:     1      02 -0.8043316    A
#      3:     1      03  0.2353485    S
#      4:     1      04  0.6179223    L
#      5:     1      05 -0.2212571    T
#     ---                              
# 499996: 10000      46 -0.6859073    A
# 499997: 10000      47 -0.9763478    W
# 499998: 10000      48  0.6579464    H
# 499999: 10000      49  0.7741840    U
# 500000: 10000      50  0.5195232    W
无耻的自我推销 您可能想从我的软件包
Kmisc
中尝试
melt\uuu
melt
本质上是对
reforme2:::melt.data.frame
的重写,大部分繁重的工作都是用C语言完成的,它尽可能避免了大量的复制和类型强制,以便快速实现

例如:

## devtools::install_github("Kmisc", "kevinushey")
library(Kmisc)
library(reshape2)
library(microbenchmark)
n <- 1E6
big_df <- data.frame( stringsAsFactors=FALSE,
  x=sample(letters, n, TRUE),
  y=sample(LETTERS, n, TRUE),
  za=rnorm(n),
  zb=rnorm(n),
  zc=rnorm(n)
)
all.equal(
  melt <- melt(big_df, id.vars=c('x', 'y')),
  melt_ <- melt_(big_df, id.vars=c('x', 'y'))
)
## we don't convert the 'variable' column to factor by default
## if we do, we see they're identical
melt_$variable <- factor(melt_$variable)
stopifnot( identical(melt, melt_) )
microbenchmark( times=5,
  melt=melt(big_df, id.vars=c('x', 'y')),
  melt_=melt_(big_df, id.vars=c('x', 'y'))
)

如果运气好的话,这对于您的数据来说已经足够快了。

我应该补充一点,使用melt不是一个选项,因为在一个大小为几GB的数据集上运行该操作需要花费时间。您是否尝试过将
堆栈
作为
melt
的替代方法?或者可能是
unlist
(但我认为
stack
更快)。请参阅中的答案以了解一些可能的线索。是的,这很有效…cbind(stack(dt,select=-uid),enrolid=dt$uid)我一直在思考
dt[,stack(.SD),by=“uid”]
,假设其他所有内容都包含
.SDCols
未列出的
通常会通过
use.names=FALSE
获得速度提升。不确定这是否适用于本例,但可能适用。刚刚尝试过这一方法,速度比前两种方法快(几乎是堆栈的2倍)。非常感谢两位!刚刚检查了1000x1000
数据表
。将
use.names=FALSE
粘贴到
unlist
中比仅使用
unlist
快约3倍。这非常酷——我想知道您是否有兴趣请求将您的改进合并到一起,以便您可以更快地烹饪?@Arun请执行!另外,我没有充分的理由使用
STRING\u PTR
而不是
SET\u STRING\u ELT
;车祸与此有关吗?我可以请你把代码发到吗?@Arun,我已经更新了函数。谢谢你提醒我。期待数据。表1.8.12(我猜
melt
方法将在这里可用)。
library(microbenchmark)
microbenchmark(Stacked = test1(), merged.stack = test2(),
               unlist.namesT = test3(), unlist.namesF = test4(),
               AndreasAns = test5(), times = 3)
# Unit: milliseconds
#           expr        min         lq     median         uq        max neval
#        Stacked   391.3251   393.0976   394.8702   421.4185   447.9668     3
#   merged.stack   764.3071   769.6935   775.0799   867.2638   959.4477     3
#  unlist.namesT  1680.0610  1761.9701  1843.8791  1881.9722  1920.0653     3
#  unlist.namesF   215.0827   242.7748   270.4669   270.6944   270.9218     3
#     AndreasAns 16193.5084 16249.5797 16305.6510 16793.3832 17281.1154     3
test1()
# $varA
#           uid .time_1       varA
#      1:     1      01 -0.6264538
#      2:     1      02 -0.8043316
#      3:     1      03  0.2353485
#      4:     1      04  0.6179223
#      5:     1      05 -0.2212571
#     ---                         
# 499996: 10000      46 -0.6859073
# 499997: 10000      47 -0.9763478
# 499998: 10000      48  0.6579464
# 499999: 10000      49  0.7741840
# 500000: 10000      50  0.5195232
# 
# $varB
#           uid .time_1 varB
#      1:     1      01    D
#      2:     1      02    A
#      3:     1      03    S
#      4:     1      04    L
#      5:     1      05    T
#     ---                   
# 499996: 10000      46    A
# 499997: 10000      47    W
# 499998: 10000      48    H
# 499999: 10000      49    U
# 500000: 10000      50    W
test2()
#           uid .time_1       varA varB
#      1:     1      01 -0.6264538    D
#      2:     1      02 -0.8043316    A
#      3:     1      03  0.2353485    S
#      4:     1      04  0.6179223    L
#      5:     1      05 -0.2212571    T
#     ---                              
# 499996: 10000      46 -0.6859073    A
# 499997: 10000      47 -0.9763478    W
# 499998: 10000      48  0.6579464    H
# 499999: 10000      49  0.7741840    U
# 500000: 10000      50  0.5195232    W
## devtools::install_github("Kmisc", "kevinushey")
library(Kmisc)
library(reshape2)
library(microbenchmark)
n <- 1E6
big_df <- data.frame( stringsAsFactors=FALSE,
  x=sample(letters, n, TRUE),
  y=sample(LETTERS, n, TRUE),
  za=rnorm(n),
  zb=rnorm(n),
  zc=rnorm(n)
)
all.equal(
  melt <- melt(big_df, id.vars=c('x', 'y')),
  melt_ <- melt_(big_df, id.vars=c('x', 'y'))
)
## we don't convert the 'variable' column to factor by default
## if we do, we see they're identical
melt_$variable <- factor(melt_$variable)
stopifnot( identical(melt, melt_) )
microbenchmark( times=5,
  melt=melt(big_df, id.vars=c('x', 'y')),
  melt_=melt_(big_df, id.vars=c('x', 'y'))
)
Unit: milliseconds
  expr       min        lq    median         uq       max neval
  melt 916.40436 931.60031 999.03877 1102.31090 1160.3598     5
 melt_  61.59921  78.08768  90.90615   94.52041  182.0879     5