与sqldf相比,如何使用data.table获得相同的分组结果?

问题描述

我尝试使用 sqldf 和 data.table 来实现 sql 查询
我需要使用这两个不同的库分别执行此操作。
不幸的是,我无法使用 data.table 产生相同的结果。

library(sqldf)
library(data.table)

Id       <- c(1,2,3,4)
HasPet   <- c(0,1,1)
Age      <- c(20,14,10)

Posts <- data.table(Id,HasPet,Age)

# sqldf way
ref <- sqldf("
      SELECT Id,MAX(Age) AS MaxAge
      FROM Posts
      GROUP BY HasPet
  ")

# data.table way
res <- Posts[,list(Id,MaxAge=max(Age)),by=list(HasPet)]

head(ref)
head(res)

sqldf 的输出是:

> head(ref)
  Id HasPet MaxAge
1  1      0     20
2  3      1     14

而 data.table 的输出不同:

> head(res)
   HasPet Id HasPet MaxAge
1:      0  1      0     20
2:      0  2      0     20
3:      1  3      1     14
4:      1  4      1     14

请注意,不能修改 sql 查询

解决方法

data.table 经常出现这种情况。如果您想要按组划分的最大值或最小值,最好的方法是自联接。它很快,而且有点神秘。

您可以逐步构建它: 在data.table中,可以在i中选择,在j中进行,然后进行分组。所以第一步是在群的各个层级中找到我们想要的东西

Posts[,Age == max(Age),by = HasPet]
#    HasPet    V1
# 1:      0  TRUE
# 2:      0 FALSE
# 3:      1  TRUE
# 4:      1 FALSE

我们可以使用 .I 来检索每行的整数向量,然后是每组中以前的 V1 逻辑向量 TRUE 和 FALSE 索引,因此我们只有包含每组最大值的行。

Posts[,.I[Age == max(Age)],by=HasPet]

# From the data.table special symbols help:
# .I is an integer vector equal to seq_len(nrow(x)). While grouping,# it holds for each item in the group,its row location in x. This is useful
# to subset in j; e.g. DT[,.I[which.max(somecol)],by=grp].

#    HasPet V1
# 1:      0  1
# 2:      1  3

然后我们使用刚刚创建的 V1 列来调用 data.table 中的特定行(1 和 3)。就这样!

Posts[Posts[,by=HasPet]$V1]
,

您可以使用 .SD 获取 HasPet 的每个值的行子集。

library(data.table)
Posts[,.SD[Age==max(Age)],HasPet]

#   HasPet Id Age
#1:      0  1  20
#2:      1  3  14

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...