data.table包用法简介

data.table包提供了一个data.frame的高级版本,由于它是C语言编写,相比data.framedata.table能够让你更加快速高效的处理数据。非常适合那些需要处理大型数据集(比如 1GB 到100GB)和需要在内存中处理数据的人。虽然data.table很强大,但是有些语法还是比较独特的,因此在学习之余顺手翻译了data.table的文档,给自己个备忘,给大家个参考。

在数据分析中使用data.table

subset, group, update, join等数据处理操作都有内在的关联,结合这些相关操作有以下优点:

  • 可以不考虑你想要实现的一系列操作,通过简洁一致的语法达到最终目的。
  • 在执行分析前,没有把每一步操作都映射到从一组可用的函数中的特定函数上的负担,从而流畅的执行分析。
  • 通过精准的识别每一步操作需要的数据,自动优化内部操作,非常高效,从而实现快速计算和内存效率化。

简言之,如果你对缩短编程和计算时间非常感兴趣,这个包就适合你,data.table坚持的哲学就是使这些成为可能。

Data准备

在这个介绍中使用的是NYC-flights14 数据。这份数据来自于运输统计局,它包含了2014年纽约机场发出的所有航班的准点航班数据。这份数据只有2014年1月到10月是公开的。老规矩,输入下列命令安装并载入data.table

1
2
3
4
5
6
> install.packages("data.table")
> library(data.table)
data.table 1.10.4
The fastest way to learn (by data.table authors): https://www.datacamp.com/courses/data-analysis-the-data-table-way
Documentation: ?data.table, example(data.table) and browseVignettes("data.table")
Release notes, videos and slides: http://r-datatable.com

data.table的快速文件读取通过调用fread()实现。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
> flights <- fread("flights14.csv")
> flights
year month day dep_time dep_delay arr_time arr_delay cancelled carrier tailnum flight origin dest air_time distance hour min
1: 2014 1 1 914 14 1238 13 0 AA N338AA 1 JFK LAX 359 2475 9 14
2: 2014 1 1 1157 -3 1523 13 0 AA N335AA 3 JFK LAX 363 2475 11 57
3: 2014 1 1 1902 2 2224 9 0 AA N327AA 21 JFK LAX 351 2475 19 2
4: 2014 1 1 722 -8 1014 -26 0 AA N3EHAA 29 LGA PBI 157 1035 7 22
5: 2014 1 1 1347 2 1706 1 0 AA N319AA 117 JFK LAX 350 2475 13 47
---
253312: 2014 10 31 1459 1 1747 -30 0 UA N23708 1744 LGA IAH 201 1416 14 59
253313: 2014 10 31 854 -5 1147 -14 0 UA N33132 1758 EWR IAH 189 1400 8 54
253314: 2014 10 31 1102 -8 1311 16 0 MQ N827MQ 3591 LGA RDU 83 431 11 2
253315: 2014 10 31 1106 -4 1325 15 0 MQ N511MQ 3592 LGA DTW 75 502 11 6
253316: 2014 10 31 824 -5 1045 1 0 MQ N813MQ 3599 LGA SDF 110 659 8 24

fread()也可以直接读取网络链接。

1
> flights <- fread("https://github.com/arunsrinivasan/flights/wiki/NYCflights14/flights14.csv")

fread()也可以直接调用系统命令,这里不再详细举例,可以通过?fread查询。

介绍

首先将会从最基本的操作开始。例如什么是data.tabledata.table的基本形式,以及行列的抽取、选择和计算,第二部分将会介绍数据的聚合计算。

基本操作

创建变量

使用data.table创建变量。

1
2
3
4
5
6
7
8
9
10
11
12
13
> DT = data.table(ID = c("b","b","b","a","a","c"), a = 1:6, b = 7:12, c = 13:18)
> DT
ID a b c
1: b 1 7 13
2: b 2 8 14
3: b 3 9 15
4: a 4 10 16
5: a 5 11 17
6: c 6 12 18
> class(DT)
[1] "data.table" "data.frame"
> class(DT$ID)
[1] "character"

也可以使用as.data.table()函数将现有数据转换成data.table格式。

1
2
3
4
5
> class(mtcars)
[1] "data.frame"
> dtmtcars <- as.data.table(mtcars)
> class(dtmtcars)
[1] "data.table" "data.frame"

说明:

  • data.frame不同,字符型变量不会被自动转换为因子型。
  • 行号与第一列之间会用:隔开。
  • 当行号超过全局选项datatable.print.nrows时(默认为100),data.frame自动输出前五行与最后五行。
  • data.frame不会设置或使用行名。

一般形式

data.table的一般形式如下,使用数据集DT, 通过i选取行,进行j的计算,由by进行分组。这类似于SQL语言。

1
2
3
DT[i, j, by]
## R: i j by
## SQL: where select | update group by

通过i进行行操作

抽取出发地为JFK并且是六月的航班。

1
2
3
4
5
6
7
8
9
> ans <- flights[origin == "JFK" & month == 6L]
> head(ans)
year month day dep_time dep_delay arr_time arr_delay cancelled carrier tailnum flight origin dest air_time distance hour min
1: 2014 6 1 851 -9 1205 -5 0 AA N787AA 1 JFK LAX 324 2475 8 51
2: 2014 6 1 1220 -10 1522 -13 0 AA N795AA 3 JFK LAX 329 2475 12 20
3: 2014 6 1 718 18 1014 -1 0 AA N784AA 9 JFK LAX 326 2475 7 18
4: 2014 6 1 1024 -6 1314 -16 0 AA N791AA 19 JFK LAX 320 2475 10 24
5: 2014 6 1 1841 -4 2125 -45 0 AA N790AA 21 JFK LAX 326 2475 18 41
6: 2014 6 1 1454 -6 1757 -23 0 AA N785AA 117 JFK LAX 329 2475 14 54

说明:

  • data.table的框架内,列可以被看作是变量,因此我们不需要每次引用时都加上前缀flights$
  • 例子中j, by参数不存在,只对i进行运算,结果会返回所有满足条件i的列。
  • data.fram不同,在i后面不需要用,进行分割。

也可以通过行号进行选取。

1
2
3
4
5
> ans <- flights[1:2]
> ans
year month day dep_time dep_delay arr_time arr_delay cancelled carrier tailnum flight origin dest air_time distance hour min
1: 2014 1 1 914 14 1238 13 0 AA N338AA 1 JFK LAX 359 2475 9 14
2: 2014 1 1 1157 -3 1523 13 0 AA N335AA 3 JFK LAX 363 2475 11 57

先对origin进行升序排序,在对dest进行降序排序。

1
2
3
4
5
6
7
8
9
> ans <- flights[order(origin, -dest)]
> head(ans)
year month day dep_time dep_delay arr_time arr_delay cancelled carrier tailnum flight origin dest air_time distance hour min
1: 2014 1 5 836 6 1151 49 0 EV N12175 4419 EWR XNA 195 1131 8 36
2: 2014 1 6 833 7 1111 13 0 EV N24128 4419 EWR XNA 190 1131 8 33
3: 2014 1 7 811 -6 1035 -13 0 EV N12142 4419 EWR XNA 179 1131 8 11
4: 2014 1 8 810 -7 1036 -12 0 EV N11193 4419 EWR XNA 184 1131 8 10
5: 2014 1 9 833 16 1055 7 0 EV N14198 4419 EWR XNA 181 1131 8 33
6: 2014 1 13 923 66 1154 66 0 EV N12157 4419 EWR XNA 188 1131 9 23

order()被内部优化

  • 我们可以在框架内通过-号进行降序排列。
  • order()命令调用forder(),比base::order快很多。

通过j进行列操作

直接调用arr_delay列,以向量的形式返回。

1
2
3
> ans <- flights[, arr_delay]
> head(ans)
[1] 13 13 9 -26 1 0
  • 由于在data.table中列被看作是变量,我们可以直接调用我们想要的变量。跳过i参数,返回的是所有行。

通过list()调用arr_delay列,以data.table的形式返回。

1
2
3
4
5
6
7
8
9
> ans <- flights[, list(arr_delay)]
> head(ans)
arr_delay
1: 13
2: 13
3: 9
4: -26
5: 1
6: 0

同时选取arr_delaydep_delay

1
2
3
4
5
6
7
8
9
> ans <- flights[, .(arr_delay, dep_delay)]
> head(ans)
arr_delay dep_delay
1: 13 14
2: 13 -3
3: 9 2
4: -26 -8
5: 1 2
6: 0 4

也可以用下面形式

1
> ans <- flights[, list(arr_delay, dep_delay)]

同时选取arr_delaydep_delay列并重命名为delay_arrdelay_dep

由于.()等同于list(),我们可以在选取创建列表的时候命名列名。

1
2
3
4
5
6
7
8
9
> ans <- flights[, .(delay_arr = arr_delay, delay_dep = dep_delay)]
> head(ans)
delay_arr delay_dep
1: 13 14
2: 13 -3
3: 9 2
4: -26 -8
5: 1 2
6: 0 4

j中进行运算

data.table中的j不仅能处理列选取,也能处理表达式。例如,计算有多少航班延迟小于0

1
2
3
> ans <- flights[, sum((arr_delay + dep_delay) < 0)]
> head(ans)
[1] 141814

i中选择,在j中运算

data.table框架内有三个组成部分,分别是i, j, by。data.table计算前查看所有部分并整体优化请求,同时提高了速度和内存效率。例如,计算6月从JFK机场出发的所有航班的平均到达延迟和起飞延迟。

1
2
3
4
5
> ans <- flights[origin == "JFK" & month == 6L,
+ .(m_arr = mean(arr_delay), m_dep = mean(dep_delay))]
> ans
m_arr m_dep
1: 5.839349 9.807884

查询出2014年6月出发机场为JFK的航班数量。

1
2
3
> ans <- flights[origin == "JFK" & month == 6L, length(dest)]
> ans
[1] 8422

特殊符号.N

.N是一个特殊的内置变量,保存了当前组的样本长度,它在by结合使用时非常有用,这在下一节会提到。在没有分组的情况下,它会直接返回抽取样本的长度。因此我们用.N达到上面length()的目的。

1
2
3
> ans <- flights[origin == "JFK" & month == 6L, .N]
> ans
[1] 8422

这里我们用相同的方法抽取了2014年6月出发机场为JFK的航班,在j部分当中我们用.N只对抽取部分返回了样本长度。注意,我们并没有对.Nlist()或者.()处理,因此返回的是一个向量。

当然,我们可以通过nrow(flights[origin == "JFK" & month == 6L])来实现相同的效果, 但是那样的话我们首先要在整个表单中抽取i中相应的样本,然后用nrow()函数返回长度,这样是没有必要且非效率的。

j中通过列名调用列(类似data.frame

通过使用with = FALSE可以像data.frame一样调用列。

1
2
3
4
5
6
7
8
9
> ans <- flights[, c("arr_delay", "dep_delay"), with = FALSE]
> head(ans)
arr_delay dep_delay
1: 13 14
2: 13 -3
3: 9 2
4: -26 -8
5: 1 2
6: 0 4

这里参数被命名为with是因为它和R中with()函数有类似的效果。假设我们要从data.frame格式的DF中抽取x > 1的样本,可以通过两种方式来实现,首先是通常的方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
> DF = data.frame(x = c(1,1,1,2,2,3,3,3), y = 1:8)
> DF
x y
1 1 1
2 1 2
3 1 3
4 2 4
5 2 5
6 3 6
7 3 7
8 3 8
> DF[DF$x > 1,]
x y
4 2 4
5 2 5
6 3 6
7 3 7
8 3 8

其次我们还可以通过with()函数实现。

1
2
3
4
5
6
7
> DF[with(DF, x > 1),]
x y
4 2 4
5 2 5
6 3 6
7 3 7
8 3 8

使用with()函数时x列会被看成是变量,我们通过with = FALSE参数的设置就是避免了列被看成变量而被存储成data.frame 类型。通过查看类型我们可以看到ansdata.table类型,而通过with()函数实现的类型则是data.frame

1
2
3
4
> class(DF[with(DF, x > 1),])
[1] "data.frame"
> class(ans)
[1] "data.table" "data.frame"

我们还可以通过-或者!实现列的删除,例如

1
2
3
4
# returns all columns except arr_delay and dep_delay
> ans <- flights[, !c("arr_delay", "dep_delay"), with = FALSE]
# or
> ans <- flights[, -c("arr_delay", "dep_delay"), with = FALSE]

从v1.9.5版本开始,可以通过指定起始列和终止列的列名来抽取列。

1
2
3
4
5
6
7
# returns year,month and day
> ans <- flights[, year:day, with = FALSE]
# returns day, month and year
> ans <- flights[, day:year, with = FALSE]
# returns all columns except year, month and day
> ans <- flights[, -(year:day), with = FALSE]
> ans <- flights[, !(year:day), with = FALSE]

with = TRUE是默认设置,因为这样允许j处理表达式从而实现更多的操作,尤其是与by结合使用。

聚合操作

这一小节中主要说明i,j,和by结合的分组操作。

使用by进行分组

计算每个出发机场航班的样本长度。

1
2
3
4
5
6
> ans <- flights[, .N, by = .(origin)]
> ans
origin N
1: JFK 81483
2: LGA 84433
3: EWR 87400

by也可以使用字符型向量。由于只有一行,在jby中也没有指定表达式,.()可以省略掉,可以方便的用第二种形式代替。

1
2
3
> ans <- flights[, .(.N), by = "origin"]
# for convenience, we can instead do:
> ans <- flights[, .N, by = origin]

by也可以接受字符型向量

分组计算乘客代码为"AA",各个出发机场的航班的样本长度

1
2
3
4
5
6
> ans <- flights[carrier == "AA", .N, by = origin]
> ans
origin N
1: JFK 11923
2: LGA 11730
3: EWR 2649

by可以进行多列计算,只需要提供多个列。按照origin, dest分组计算乘客代码为"AA",各个出发机场的航班的样本长度。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
> ans <- flights[carrier == "AA", .N, by = .(origin, dest)]
> ans
origin dest N
1: JFK LAX 3387
2: LGA PBI 245
3: EWR LAX 62
4: JFK MIA 1876
5: JFK SEA 298
6: EWR MIA 848
7: JFK SFO 1312
8: JFK BOS 1173
9: JFK ORD 432
10: JFK IAH 7
11: JFK AUS 297
12: EWR DFW 1618
13: LGA ORD 4366
14: JFK STT 229
15: JFK SJU 690
16: LGA MIA 3334
17: LGA DFW 3785
18: JFK LAS 595
19: JFK MCO 597
20: JFK EGE 85
21: JFK DFW 474
22: JFK SAN 299
23: JFK DCA 172
24: EWR PHX 121
origin dest N

也可以在by使用字符型向量。

1
> ans <- flights[carrier == "AA", .N, by = c("origin", "dest")]

计算按照origin, dest, month分组、乘客代码为"AA"的平均到达延迟和出发延迟。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
> ans <- flights[carrier == "AA", .(mean(arr_delay), mean(dep_delay)), by = .(origin, dest, month)]
> ans
origin dest month V1 V2
1: JFK LAX 1 6.590361 14.2289157
2: LGA PBI 1 -7.758621 0.3103448
3: EWR LAX 1 1.366667 7.5000000
4: JFK MIA 1 15.720670 18.7430168
5: JFK SEA 1 14.357143 30.7500000
---
196: LGA MIA 10 -6.251799 -1.4208633
197: JFK MIA 10 -1.880184 6.6774194
198: EWR PHX 10 -3.032258 -4.2903226
199: JFK MCO 10 -10.048387 -1.6129032
200: JFK DCA 10 16.483871 15.5161290

这里我们并没有在j中指定表达式,结果自动生成V1,V2

keyby

data.table中保持了原始的分组顺序是有意为之。但是有时我们会需要根据我们分组的变量自动排序,这时可以使用keyby对分组进行排序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
> ans <- flights[carrier == "AA", .(mean(arr_delay), mean(dep_delay)), keyby = .(origin, dest, month)]
> ans
origin dest month V1 V2
1: EWR DFW 1 6.427673 10.0125786
2: EWR DFW 2 10.536765 11.3455882
3: EWR DFW 3 12.865031 8.0797546
4: EWR DFW 4 17.792683 12.9207317
5: EWR DFW 5 18.487805 18.6829268
---
196: LGA PBI 1 -7.758621 0.3103448
197: LGA PBI 2 -7.865385 2.4038462
198: LGA PBI 3 -5.754098 3.0327869
199: LGA PBI 4 -13.966667 -4.7333333
200: LGA PBI 5 -10.357143 -6.8571429

Chaining

data.table 可以在进行链式调用,例如我们要对上述ans结果进行按照orgin, -dest进行排序,我们可以在结果后面加上如下命令。

1
> ans <- ans[order(origin, -dest)]

上述操作需要对生成中间结果并对其进行覆盖操作,我们也可以直接通过链状表达实现相同的效果。

1
2
3
4
5
6
7
8
9
10
11
12
13
> ans <- flights[carrier == "AA", .N, by = .(origin, dest)][order(origin, -dest)]
> head(ans, 10)
origin dest N
1: EWR PHX 121
2: EWR MIA 848
3: EWR LAX 62
4: EWR DFW 1618
5: JFK STT 229
6: JFK SJU 690
7: JFK SFO 1312
8: JFK SEA 298
9: JFK SAN 299
10: JFK ORD 432

我们可以在一个表达式后边跟上另一个表达式,例如:DT[...][...][...],也可以垂直链接,例如:

1
2
3
4
DT[...
][...
][...
]

by中的表达式

by也可以接受表达式,例如如果我们想要找到起飞延迟但是提前到达、或者准时到达的,出发和到达都延迟的等等,可以用如下代码实现。

1
2
3
4
5
6
7
> ans <- flights[, .N, .(dep_delay > 0, arr_delay > 0)]
> ans
dep_delay arr_delay N
1: TRUE TRUE 72836
2: FALSE TRUE 34583
3: FALSE FALSE 119304
4: TRUE FALSE 26593

最后一行代码对应的是dep_delay > 0 = TRUE and arr_delay > 0 = FALSE, 我们可以看出26593个航班虽然出发延迟但是都提前或者正点到达。同样,我们也没有给·by表达式指定名字,变量名在结果中自动分配。

j中的多列运算:.SD

j中我们可以使用我们非常熟悉的基本函数lapply()来循环计算所有的列。这个方法是由data.table提供的叫做.SD的特殊符号来实现。首先我们通过之前的DT数据概览一下.SD

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
> DT
ID a b c
1: b 1 7 13
2: b 2 8 14
3: b 3 9 15
4: a 4 10 16
5: a 5 11 17
6: c 6 12 18
> DT[, print(.SD), by = .(ID)]
a b c
1: 1 7 13
2: 2 8 14
3: 3 9 15
a b c
1: 4 10 16
2: 5 11 17
a b c
1: 6 12 18
Empty data.table (0 rows) of 1 col: ID

.SD默认包含除分组列外的所有列,返回结果是原始排序,即我们所看到的首先是ID = "b", 其次是ID = "a", 最后是ID = "c"

接下来我们简单的调用基本的R函数lapply()实现多列运算。

1
2
3
4
5
> DT[, lapply(.SD, mean), by = ID]
ID a b c
1: b 2.0 8.0 14.0
2: a 4.5 10.5 16.5
3: c 6.0 12.0 18.0

说明:

  • .SD按组保存相应的a, b, c列,然后我们调用已经熟悉的基本函数lapply()计算了每列的平均值。
  • 每个组返回包含平均值的三个元素的列表,而它们就成为结果的data.table。
  • 由于lapply()返回的是列表,所以我们不需要额外的添加.()

如果我们不需要遍历所有的行,而是只计算其中两行,我们可以用.SDcols参数。.SDcols参数接受列名或者列索引,例如.SDcols = c("arr_delay", "dep_delay")确保了.SD每组只包含指定的两列。

with = FALSE用法相似,我们可以提供-!符号移除列,也可以使用colA : colB选择连续列,以及!(colA : colB)-(colA : colB)反选连续列。下面让我们试着.SD连同.SDcols一起使用,按orgin, dest, month分组,计算乘客代码为AAarr_delaydep_delay两列的平均值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
> flights[carrier == "AA",
lapply(.SD, mean),
by = .(origin, dest, month),
.SDcols = c("arr_delay", "dep_delay")]
origin dest month arr_delay dep_delay
1: JFK LAX 1 6.590361 14.2289157
2: LGA PBI 1 -7.758621 0.3103448
3: EWR LAX 1 1.366667 7.5000000
4: JFK MIA 1 15.720670 18.7430168
5: JFK SEA 1 14.357143 30.7500000
---
196: LGA MIA 10 -6.251799 -1.4208633
197: JFK MIA 10 -1.880184 6.6774194
198: EWR PHX 10 -3.032258 -4.2903226
199: JFK MCO 10 -10.048387 -1.6129032
200: JFK DCA 10 16.483871 15.5161290

对每组进行抽取.SD

我们可以通过如下代码返回每月的前两行数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
= month]
> head(ans)
month year day dep_time dep_delay arr_time arr_delay cancelled carrier tailnum
1: 1 2014 1 914 14 1238 13 0 AA N338AA
2: 1 2014 1 1157 -3 1523 13 0 AA N335AA
3: 2 2014 1 859 -1 1226 1 0 AA N783AA
4: 2 2014 1 1155 -5 1528 3 0 AA N784AA
5: 3 2014 1 849 -11 1306 36 0 AA N784AA
6: 3 2014 1 1157 -3 1529 14 0 AA N787AA
flight origin dest air_time distance hour min
1: 1 JFK LAX 359 2475 9 14
2: 3 JFK LAX 363 2475 11 57
3: 1 JFK LAX 358 2475 8 59
4: 3 JFK LAX 358 2475 11 55
5: 1 JFK LAX 375 2475 8 49
6: 3 JFK LAX 368 2475 11 57

说明:

  • .SD是一个保存了分组所有行的data.table, 就如结果显示那样我们可以简单的抽取前两行。
  • 对于每个分组,head(.SD, 2)以同为列表的data.table形式返回了前两行, 因此我们不需要使用.()。

为什么j如此灵活

这样我们就有了一致的语法并继续使用已有的(和熟悉的)基础函数而不是学习新的函数。举例说明的话,我们依然使用文章开始我们创建的data.table形式的DT,按ID分组对接列a, b

1
2
3
4
5
6
7
8
9
10
11
12
13
14
> DT[, .(val = c(a, b)), by = ID]
ID val
1: b 1
2: b 2
3: b 3
4: b 7
5: b 8
6: b 9
7: a 4
8: a 5
9: a 10
10: a 11
11: c 6
12: c 12

说明:

  • 就是这样。这里不需要特殊的语法。我们需要知道的只是用来连接向量的基本函数c()即可。

如果我们想要连接ab所有值, 但是作为列表列返回呢?

1
2
3
4
5
> DT[, .(val = list(c(a, b))), by = ID]
ID val
1: b 1,2,3,7,8,9
2: a 4, 5,10,11
3: c 6,12

说明:

  • 在这里,我们首先将每个组的值与c(a,b)连接起来,然后转换成list()。因此,对于每个组,我们返回一个所有连接值的列表。

一旦您开始在j中使用内部用法,您就会意识到语法有多么强大。理解它的一个非常有用的方法是在print()的帮助下多多尝试。

总结

data.table的一般形式为:

1
DT[i, j, by]

i的调用:

  • 我们可以用与data.frame类似的方法抽取行 -由于列在data.frame框架内被看成是变量,你不需要重复使用DT$
  • 我们可以使用order()来对data.table进行排序,它内部调用data.table的快速索引有更好的表现。

我们可以通过调整参数i做更多的工作,它可以得到更快速的选取和对接。

j的调用:

  • 得到data.table形式的行: DT[, .(colA, colB)]
  • 得到data.frame形式的行: DT[, c("colA", "colB"), with = FALSE]
  • 按行计算: DT[, .(sum(colA), mean(colB))]
  • 指定行名: DT[, .(sA =sum(colA), mB = mean(colB))]
  • i结合使用: DT[colA > value, sum(colB)]

by的调用:

  • 通过by, 我们可以指定列(列表形式),包含列名的字符向量,甚至是表达式来进行分组,j的灵活性结合byi能够实现非常强大的语法。
  • by可以处理多个列,也可以处理表达式。
  • 我们可以调用keyby实现分组结果的自动排序。
  • 我们可以使用我们比较熟悉的基本函数,调用.SD.SDcols在多个列上进行操作,这里有一些例子:
    1. DT[, lapply(.SD, fun), by = ..., .SDcols = ...]: 通过by分组,同时把fun运用到.SDcols指定的所有列上。
    2. DT[, head(.SD, 2), by = ...]: 返回每个分组的前两行。
    3. DT[col > val, head(.SD, 1), by = ...]: i, j, by连同使用。

后记

一开始只想做个笔记,后来就变成了翻译的风格,整体上看来90%都遵照了官方文档的格式,但是英语渣,中文渣加上非专业出身,有好多语句可以理解但是始终无法优雅的用中文表达出来,附上官方文档链接,读不懂的请参照原文,有翻译错误的也请指出,多谢!