sql - 如何在R中模拟SQL等级函数?

标签 sql r data.table dplyr dense-rank

像Oracle ROW_NUMBER()RANK()DENSE_RANK()(“根据行的顺序将整数值分配给行”;请参见http://www.orafaq.com/node/55),R等价于R函数是什么?

我同意,每个功能的功能都可以通过临时方式实现。但是我主要关心的是性能。出于内存和速度的考虑,最好避免使用联接或索引访问。

最佳答案

data.table软件包,尤其是从1.8.1版开始的软件包,以SQL术语提供了分区的许多功能。 R中的rank(x, ties.method = "min")与Oracle RANK()类似,并且有一种使用因素(如下所述)来模仿DENSE_RANK()函数的方法。最后,模仿ROW_NUMBER的方法应该很明显。

这是一个示例:从R-Forge加载最新版本的data.table

install.packages("data.table",
  repos= c("http://R-Forge.R-project.org", getOption("repos")))

library(data.table)


创建一些示例数据:

set.seed(10)

DT<-data.table(ID=seq_len(4*3),group=rep(1:4,each=3),value=rnorm(4*3),
  info=c(sample(c("a","b"),4*2,replace=TRUE),
  sample(c("c","d"),4,replace=TRUE)),key="ID")

> DT
    ID group       value info
 1:  1     1  0.01874617    a
 2:  2     1 -0.18425254    b
 3:  3     1 -1.37133055    b
 4:  4     2 -0.59916772    a
 5:  5     2  0.29454513    b
 6:  6     2  0.38979430    a
 7:  7     3 -1.20807618    b
 8:  8     3 -0.36367602    a
 9:  9     3 -1.62667268    c
10: 10     4 -0.25647839    d
11: 11     4  1.10177950    c
12: 12     4  0.75578151    d


通过在ID内减小value来对每个group进行排名(注意-前面的value表示降序):

> DT[,valRank:=rank(-value),by="group"]
    ID group       value info valRank
 1:  1     1  0.01874617    a       1
 2:  2     1 -0.18425254    b       2
 3:  3     1 -1.37133055    b       3
 4:  4     2 -0.59916772    a       3
 5:  5     2  0.29454513    b       2
 6:  6     2  0.38979430    a       1
 7:  7     3 -1.20807618    b       2
 8:  8     3 -0.36367602    a       1
 9:  9     3 -1.62667268    c       3
10: 10     4 -0.25647839    d       3
11: 11     4  1.10177950    c       1
12: 12     4  0.75578151    d       2


对于在值中具有联系的DENSE_RANK(),您可以将值转换为因子,然后返回基础整数值。例如,根据ID中的info对每个group进行排名(将infoRankinfoRankDense比较):

DT[,infoRank:=rank(info,ties.method="min"),by="group"]
DT[,infoRankDense:=as.integer(factor(info)),by="group"]

R> DT
    ID group       value info valRank infoRank infoRankDense
 1:  1     1  0.01874617    a       1        1             1
 2:  2     1 -0.18425254    b       2        2             2
 3:  3     1 -1.37133055    b       3        2             2
 4:  4     2 -0.59916772    a       3        1             1
 5:  5     2  0.29454513    b       2        3             2
 6:  6     2  0.38979430    a       1        1             1
 7:  7     3 -1.20807618    b       2        2             2
 8:  8     3 -0.36367602    a       1        1             1
 9:  9     3 -1.62667268    c       3        3             3
10: 10     4 -0.25647839    d       3        2             2
11: 11     4  1.10177950    c       1        1             1
12: 12     4  0.75578151    d       2        2             2


ps。嗨Matthew Dowle。



铅和滞后

要模仿LEAD和LAG,请从提供的here答案开始。我将根据组内ID的顺序创建一个等级变量。对于上面的伪数据来说,这不是必需的,但是,如果ID在组内不是按顺序排列的,那么这将使生活更加困难。因此,这是一些具有非顺序ID的新伪造数据:

set.seed(10)

DT<-data.table(ID=sample(seq_len(4*3)),group=rep(1:4,each=3),value=rnorm(4*3),
  info=c(sample(c("a","b"),4*2,replace=TRUE),
  sample(c("c","d"),4,replace=TRUE)),key="ID")

DT[,idRank:=rank(ID),by="group"]
setkey(DT,group, idRank)

> DT
    ID group       value info idRank
 1:  4     1 -0.36367602    b      1
 2:  5     1 -1.62667268    b      2
 3:  7     1 -1.20807618    b      3
 4:  1     2  1.10177950    a      1
 5:  2     2  0.75578151    a      2
 6: 12     2 -0.25647839    b      3
 7:  3     3  0.74139013    c      1
 8:  6     3  0.98744470    b      2
 9:  9     3 -0.23823356    a      3
10:  8     4 -0.19515038    c      1
11: 10     4  0.08934727    c      2
12: 11     4 -0.95494386    c      3


然后,要获取前1条记录的值,请使用groupidRank变量,并从1减去idRank并使用multi = 'last'参数。要从上面的两个记录中获取值,请减去2

DT[,prev:=DT[J(group,idRank-1), value, mult='last']]
DT[,prev2:=DT[J(group,idRank-2), value, mult='last']]

    ID group       value info idRank        prev      prev2
 1:  4     1 -0.36367602    b      1          NA         NA
 2:  5     1 -1.62667268    b      2 -0.36367602         NA
 3:  7     1 -1.20807618    b      3 -1.62667268 -0.3636760
 4:  1     2  1.10177950    a      1          NA         NA
 5:  2     2  0.75578151    a      2  1.10177950         NA
 6: 12     2 -0.25647839    b      3  0.75578151  1.1017795
 7:  3     3  0.74139013    c      1          NA         NA
 8:  6     3  0.98744470    b      2  0.74139013         NA
 9:  9     3 -0.23823356    a      3  0.98744470  0.7413901
10:  8     4 -0.19515038    c      1          NA         NA
11: 10     4  0.08934727    c      2 -0.19515038         NA
12: 11     4 -0.95494386    c      3  0.08934727 -0.1951504


对于LEAD,将适当的偏移量添加到idRank变量并切换到multi = 'first'

DT[,nex:=DT[J(group,idRank+1), value, mult='first']]
DT[,nex2:=DT[J(group,idRank+2), value, mult='first']]

    ID group       value info idRank        prev      prev2         nex       nex2
 1:  4     1 -0.36367602    b      1          NA         NA -1.62667268 -1.2080762
 2:  5     1 -1.62667268    b      2 -0.36367602         NA -1.20807618         NA
 3:  7     1 -1.20807618    b      3 -1.62667268 -0.3636760          NA         NA
 4:  1     2  1.10177950    a      1          NA         NA  0.75578151 -0.2564784
 5:  2     2  0.75578151    a      2  1.10177950         NA -0.25647839         NA
 6: 12     2 -0.25647839    b      3  0.75578151  1.1017795          NA         NA
 7:  3     3  0.74139013    c      1          NA         NA  0.98744470 -0.2382336
 8:  6     3  0.98744470    b      2  0.74139013         NA -0.23823356         NA
 9:  9     3 -0.23823356    a      3  0.98744470  0.7413901          NA         NA
10:  8     4 -0.19515038    c      1          NA         NA  0.08934727 -0.9549439
11: 10     4  0.08934727    c      2 -0.19515038         NA -0.95494386         NA
12: 11     4 -0.95494386    c      3  0.08934727 -0.1951504          NA         NA

关于sql - 如何在R中模拟SQL等级函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11446254/

相关文章:

r - 为什么要在 data.table 中使用二级索引 (`on` ),除非用于连接?

r - setorder 丹麦字母或数据表中字母的自定义排序

MYSQL 子句错误

r - `contrasts<-` (`*tmp*` 中的错误,值 = contr.funs[1 + isOF[nn]]) 具有明显正确的数据集

r - 特定值上方和下方的 geom_line 的不同颜色

r - 如何使用 `plot_grid` 包中的 `cowplot` 对齐图排列的最后一列图中包含的图例?

R data.table使用日期的组子集的总和

sql - 如何在 PostgreSQL 中获得第二行?

php - mysql/laravel组查询结果

mysql - 通过中间 M 进行连接的嵌套查询 :N (MySQL)