data.table将`by`中的因子转换为基础整数?

时间:2014-04-29 13:37:31

标签: r data.table

考虑:

dt <- data.table(a=factor(rep(c("a", "b"), 5)), b=1:10)
dt[, list(mean(b), a), by=a]

产地:

   a V1 a
1: a  5 1
2: b  6 2

此外:

Classes 'data.table' and 'data.frame':  2 obs. of  3 variables:
 $ a : Factor w/ 2 levels "a","b": 1 2
 $ V1: num  5 6
 $ a : int  1 2
 - attr(*, ".internal.selfref")=<externalptr> 

请注意最后一栏。实际的by列本身很好,当您尝试在by中明确重复使用j列时会出现问题。我也相信.BY变量有同样的问题。这是在1.9.2中使用R 3.0.2和R 7在Win 7上(尽管在Mac OS 10.8上观察到)。这曾经用于早期版本(不确定哪些,从内存中可能出错)。

首先在这里发布,以防我做一些愚蠢的事情。

此外,似乎未分组的by变量不再可用。例如:

dt[, list(mean(b), a[[2]]), by=a]

产生一个越界错误,尽管可能总是如此。我希望aj的{​​{1}}能够在dt中得到全面评估,所以a[[2]]应该有效(无论如何,我的脑子里也许永远不会这样做)

会话信息:

R version 3.0.2 (2013-09-25)
Platform: x86_64-pc-linux-gnu (64-bit)

locale:
[1] C

attached base packages:
[1] graphics  grDevices utils     datasets  stats     methods   base     

other attached packages:
[1] data.table_1.9.2

loaded via a namespace (and not attached):
[1] Rcpp_0.11.1    functional_0.4 plyr_1.8.1     reshape2_1.2.2
[5] stringr_0.6.2  tools_3.0.2   

1 个答案:

答案 0 :(得分:4)

您的帖子中有三个问题。我会按顺序回答。

参考j中的因子列,不保留该类在1.9.3中修复(错误#5437 IIRC)。由于1.9.0中的各种增强(以及R3.1.0 IIRC的一些变化),这是一个微小的回归。现在添加测试以捕获它。

require(data.table) ## 1.9.3
dt <- data.table(a=factor(rep(c("a", "b"), 5)), b=1:10)
str(dt[, list(mean(b), a), by=a])

# Classes ‘data.table’ and 'data.frame':    2 obs. of  3 variables:
#  $ a : Factor w/ 2 levels "a","b": 1 2
#  $ V1: num  5 6
#  $ a : Factor w/ 2 levels "a","b": 1 2
#  - attr(*, ".internal.selfref")=<externalptr> 

.BY的问题也在1.9.3中修复:

dt[, print(.BY), by=a]
# $a
# [1] a
# Levels: a b

# $a
# [1] b
# Levels: a b

# Empty data.table (0 rows) of 1 col: a

dt[, list(mean(b), a[[2]]), by=a]
# Error in `[[.default`(a, 2) : subscript out of bounds

这是因为by中的变量/列默认可用作length=1向量。毕竟,这是你要分组的变量。

但是,我已经通过@Matt和@eddi提出了此功能的潜在问题。您可以在评论中找到我和@eddi here之间的简短讨论。我也写过关于此的Matt,目前正在讨论中。无论分辨率如何,这都将很快得到解决和记录。

我现在的立场是by中的列不应该掩盖dt的列。这从bug #5191开始,基本上是这样的:

DT <- data.table(x=1:5, y=6:10)
DT[, sum(x), by=x%%3L]
#    x V1
# 1: 1  1
# 2: 2  2
# 3: 0  0

实际结果应该是:

DT <- data.table(x=1:5, y=6:10)
DT[, sum(x), by=list(grp=x%%3L)]
#    grp V1
# 1:   1  5
# 2:   2  7
# 3:   0  3

结果不正确,因为byx会屏蔽与每个组对应的x中的列DT。在这种情况下,发生这种情况是因为我们允许by中的表达式。

然而,即使不是情景,它也会延伸。考虑一下这个案例:

> DT[, sum(y), by=list(y=x)]
#    y V1
# 1: 1  1
# 2: 2  2
# 3: 3  3
# 4: 4  4
# 5: 5  5

此处发生的事情是,按列y命名会导致y DT被屏蔽。

恕我直言,应该做的是by不应该屏蔽DT中将j中使用的列。.BY相反,如果需要引用分组变量,则应使用已存在的[1L]变量(或简单地将第一个索引与> DT[, print(.BY$x), by=x] # [1] 1 # [1] 2 # [1] 3 # [1] 4 # [1] 5 # Empty data.table (0 rows) of 1 col: x 进行子集化),如下所示:

{{1}}

这只是我的观点,可能还有其他论据可以保留当前功能并修复这些潜在的错误案例。我们将不得不讨论并解决这个问题,并根据我们的结论,相应地进行记录。

一旦完成,我会更新这篇文章:)。