SQL "SELECT * FROM table GROUP BY c1, c2" 的 R 等价物是什么?

Wil*_*ler 7 sql aggregate r data.table

我想将我的数据框(编辑:以 CPU 高效的方式)减少到具有 c3、c4 对唯一值的行,同时保留所有列。换句话说,我想转换我的数据框

> df <- data.frame(c1=seq(7), c2=seq(4, 10), c3=c("A", "B", "B", "C", "B", "A", "A"), c4=c(1, 2, 3, 3, 2, 2, 1))
  c1 c2 c3 c4
1  1  4  A  1
2  2  5  B  2
3  3  6  B  3
4  4  7  C  3
5  5  8  B  2
6  6  9  A  2
7  7 10  A  1
Run Code Online (Sandbox Code Playgroud)

到数据框

  c1 c2 c3 c4
1  1  4  A  1
2  2  5  B  2
3  3  6  B  3
4  4  7  C  3
6  6  9  A  2
Run Code Online (Sandbox Code Playgroud)

其中 c1 和 c2 的值可以是出现在唯一对 c3、c4 中的任何值。同样,结果数据帧的顺序也不重要。

编辑:我的数据框大约有 250 000 行和 12 列,应该按 2 列分组 - 因此我需要一个 CPU 高效的解决方案

工作但不令人满意的替代方案

我解决了这个问题

> library(sqldf)
> sqldf("Select * from df Group By c3, c4")
Run Code Online (Sandbox Code Playgroud)

但为了加速和并行化我的程序,我必须消除对 sqldf 的调用。

编辑:目前 sqldf 解决方案时钟为 3.5 秒。我认为这是一个体面的时间。问题是我无法并行启动各种查询,因此我正在寻找替代方法。

不工作的尝试

复制()

> df[duplicated(df, by=c("c3", "c4")),]
[1] c1 c2 c3 c4
<0 rows> (or 0-length row.names)
Run Code Online (Sandbox Code Playgroud)

选择重复的行而不选择只有 c3 和 c4 列重复的行。

总计的()

> aggregate(df, by=list(df$c3, df$c4))
Error in match.fun(FUN) : argument "FUN" is missing, with no default
Run Code Online (Sandbox Code Playgroud)

聚合需要一个函数应用于所有具有相同 c3 和 c4 值的行

数据表的由

> library(data.table)
> dt <- data.table(df)
> dt[,list(c1, c2) ,by=list(c3, c4)]
    c3 c4 c1 c2
1:  A  1  1  4
2:  A  1  7 10
3:  B  2  2  5
4:  B  2  5  8
5:  B  3  3  6
6:  C  3  4  7
7:  A  2  6  9
Run Code Online (Sandbox Code Playgroud)

不会踢出具有非唯一值 c3 和 c4 的行,而

> dt[ ,length(c1), by=list(c3, c4)]
   c3 c4 V1
1:  A  1  2
2:  B  2  2
3:  B  3  1
4:  C  3  1
5:  A  2  1
Run Code Online (Sandbox Code Playgroud)

确实会丢弃 c1 和 c2 的值,并将它们缩减为传递函数指定的一维length

jlh*_*ard 4

这是一个 data.table 解决方案。

library(data.table)
setkey(setDT(df),c3,c4)   # convert df to a data.table and set the keys.
df[,.SD[1],by=list(c3,c4)]
#    c3 c4 c1 c2
# 1:  A  1  1  4
# 2:  A  2  6  9
# 3:  B  2  2  5
# 4:  B  3  3  6
# 5:  C  3  4  7
Run Code Online (Sandbox Code Playgroud)

您建议的 SQL 似乎提取了具有给定组合 (c3,c4) 的第一行 - 我认为这就是您想要的。


编辑:回应OP的评论。

你引用的结果看起来很奇怪。下面的基准测试针对具有 12 列和 2.5e5 行的数据集,显示 data.table 解决方案在不设置键的情况下运行大约 25毫秒,在设置键的情况下运行大约 7 毫秒。

set.seed(1)  # for reproducible example
df <- data.frame(c3=sample(LETTERS[1:10],2.5e5,replace=TRUE),
                 c4=sample(1:10,2.5e5,replace=TRUE),
                 matrix(sample(1:10,2.5e6,replace=TRUE),nc=10))
library(data.table)
DT.1 <- as.data.table(df)
DT.2 <- as.data.table(df)
setkey(DT.2,c3,c4)
f.nokeys <- function() DT.1[,.SD[1],by=list(c3,c4)]
f.keys   <- function() DT.2[,.SD[1],by=list(c3,c4)]
library(microbenchmark)
microbenchmark(f.nokeys(),f.keys(),times=10)
# Unit: milliseconds
#        expr      min        lq    median        uq       max neval
#  f.nokeys() 23.73651 24.193129 24.609179 25.747767 26.181288    10
#    f.keys()  5.93546  6.207299  6.395041  6.733803  6.900224    10
Run Code Online (Sandbox Code Playgroud)

您的数据集与此数据集有何不同?