如何创建一个带有列名的空数据表,然后将其他数据表附加到它上面?

39

首先我想创建一个带有列名的空数据表,但它失败了:

data <- data.table(va, vb, vc)

> Error in data.table(va, vb, vc) : object 'va' not found

其次,我想将数据表附加到它上面,但它也失败了:

data2 <- data.table(va=c(-1,0,1), vb=c(-1,0,1), vc=c(-1,0,1))
data2
   va vb vc
1: -1 -1 -1
2:  0  0  0
3:  1  1  1
merge(data2,data2)

> Error in merge.data.table(data2, data2) : 
      Can not match keys in x and y to automatically determine appropriate `by` parameter. Please set `by` value explicitly.

看起来该函数无法识别具有两个相同数据表的by参数。有什么思路吗?


"object va" 未找到是因为 R 假定它是一个变量名,而你的工作空间中没有名为 va 的现有变量。 - R Yoda
1
创建一个空的 data.table,使用以下代码(假设所有列都是数值型):data=data.table(va=numeric(), vb=numeric(), vc=numeric()) - R Yoda
在R中,动态地在循环中增长东西(这似乎是你正在做的事情)是一个不好的想法。 - Frank
这个问题已经过时了,在data.table v1.11.x中,merge(data2,data2)默认可以很好地处理所有(共享)的键。我想这在v1.9.6 (2016)版本中没有实现。 - smci
@Frank: 你能帮我找一篇解释为什么不应该动态增加表格的文章吗?我找不到好的。 - tamara d
1
@tamarad R地狱的第二章(免费下载链接:https://www.burns-stat.com/pages/Tutor/R_inferno.pdf)通常是人们指出的,其中提到了“内存碎片化”和速度缓慢作为副作用。这适用于向量、数组和表格。我认为唯一的例外是在此处的评论中提到的,即增长列表是可以的:https://dev59.com/W2Uq5IYBdhLWcg3wF8hQ - Frank
3个回答

45

使用以下代码创建一个空的data.table(假设所有列都是数字):

library(data.table)    
data <- data.table(va=numeric(), vb=numeric(), vc=numeric())
data

导致如下结果:

> data
Empty data.table (0 rows) of 3 cols: va,vb,vc

要进行自我连接(self join),可使用以下语法(虽然结果相同):

data2 <- data.table(va=c(-1,0,1), vb=c(-1,0,1), vc=c(-1,0,1))
data2
merge(data2, data2,by=names(data2))

您需要指定by参数的原因是因为merge的文档语义规定如此:

by:

在x和y中共享的列名称向量以进行合并。这默认为两个表之间的共享键列。如果y没有键列,则默认为x的键。

由于您没有设置任何键来合并数据表,因此合并的“连接”列不明确。
如果省略by参数,则不存在隐含的“使用所有列”的语义(正如上面引用的那样,会采取共享键列)。
要将一个数据表的所有行附加到另一个数据表中,请使用rbind(“行绑定”),而不是merge
data3 <- rbind(data2, data2)
data3

导致结果如下:

> data3
   va vb vc
1: -1 -1 -1
2:  0  0  0
3:  1  1  1
4: -1 -1 -1
5:  0  0  0
6:  1  1  1

1
在1.11.x中,merge现在尽可能使用共享键列。如果省略merge(..., by)参数,则不再存在隐式的“使用所有列”语义;我猜这在2016年(v1.9.6)时没有实现。你能否更正你的答案? - smci

28

要创建一个空的data.table,您可以从一个空的矩阵开始:

library(data.table)
data <- setNames(data.table(matrix(nrow = 0, ncol = 3)), c("va", "vb", "vc"))
data
Empty data.table (0 rows) of 3 cols: va,vb,vc

然后您可以使用rbindlist将新的data.table附加到其中:

data2=data.table(va=c(-1,0,1), vb=c(-1,0,1), vc=c(-1,0,1))
data2
   va vb vc
1: -1 -1 -1
2:  0  0  0
3:  1  1  1
rbindlist(list(data, data2))
   va vb vc
1: -1 -1 -1
2:  0  0  0
3:  1  1  1

或者更简单的是,以下内容也可以使用:

data <- data.table()
data <- rbindlist(list(data, data2))
data
   va vb vc
1: -1 -1 -1
2:  0  0  0
3:  1  1  1

应该是被接受的答案...这个有很多灵活性... - John Smith
1
为了使其成为完整的data.table方式,您可以使用setnames而不是setNames - yuskam

8

另一种创建空的data.table的方法是定义列名,但不需要定义数据类型:

data <- data.table(1)[,`:=`(c("va", "vb", "vc"),NA)][,V1:=NULL][.0]

以下是操作步骤:

  1. data.table(1):创建一个非NULL的数据表,您可以向其中添加列
    • 有一列V1,只有一个行。值为1
    • 您可以在1的位置使用任何值(除NULL外)
  2. [,`:=`(c("va", "vb", "vc"),NA)]:添加列vavbvc
    • 现在有四列(从V1开始)和一行。值为1,NA,NA,NA
    • 任何非NULL值都可以替换为NA
  3. [,V1:=NULL]:删除V1
  4. [.0]:返回一个空白行
    • 实际上,您可以使用[.n],其中n是任何整数。

如果您不喜欢[.0]的黑魔法,也可以使用

data <- data.table(1)[,`:=`(c("va", "vb", "vc"),NA)][,V1:=NULL][!is.na(va)]

若干年后的编辑: 请注意,这些列最初被分类为logical(例如上面的NA示例)。列类通常会强制转换为附加数据的列类,但是当涉及到日期数据时似乎会出现问题。

> alldata[,lapply(.SD,class)] # 0-row data seeded with NA in each column as above
        va      vb      vc       vd
1: logical logical logical  logical
> filedata[,lapply(.SD,class)] # lines of real data that you are trying to merge
          va        vb      vc   vd
1: character character integer Date
> rbindlist(list(alldata,filedata))
Error in rbindlist(list(alldata, filedata), use.names = FALSE) : 
  Class attribute on column 4 of item 2 does not match with column 4 of item 1.

要解决这个错误,一个解决方案是使用@R Yoda的答案,并将该列声明为例如vd=as.Date(character(0), origin = "1970-01-01")
请注意,这个错误已经在data.table的github库这里针对这个特定的用例被报告。之前通常会报道这里

有趣的黑魔法。你是怎么想到使用“.0”的?我以前从未见过。 - David Arenburg

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接