美文网首页
R包data.table详情介绍

R包data.table详情介绍

作者: 生信摆渡 | 来源:发表于2020-01-03 23:16 被阅读0次

R-project教程原文

目录
该教程介绍了data.table语法,其一般形式,如何对行进行子集,如何在列上进行选择和计算以及如何按组进行聚合。熟悉基础函数data.frame生成数据结构对阅读这篇教程很有用,但不是必需的。

1 安装

install.packages("data.table")

2 基础用法

# DT是指用data.table()所产生的data,下同
DT[i, j, by] 

DT,用子/重新排序行i,然后计算j,按分组by

2.1 与data.frame的不同

2.1.1 数据生成与展示

DT = data.table(
  ID = c("b","b","b","a","a","c"),
  a = 1:6,
  b = 7:12,
  c = 13:18)
DX = data.frame(
  ID = c("b","b","b","a","a","c"),
  a = 1:6,
  b = 7:12,
  c = 13:18)

> class(DT$ID)
[1] "character"
> class(DX$ID)
[1] "factor"

> DT$ID
[1] "b" "b" "b" "a" "a" "c"
> DX$ID
[1] b b b a a c
Levels: a b c
  • data.frame 不同,character类型的列默认情况下从不转换为factors

  • 行号上印有:,以便在视觉上将行号与第一列分开。

  • 当要打印的行数超过全局选项datatable.print.nrows(默认= 100)时,它将自动仅打印前5行和后5行(在数据部分中可以看到)。如果您对data.frames 有很多经验,那么您可能会发现自己在等待较大的表打印页面时在等待,有时似乎是无休止的。您可以这样查询默认号码:

    getOption("datatable.print.nrows")
    
  • data.table永远不会设置或使用行名。我们将在“基于键和快速二进制搜索的子集”小插图中看到原因。

2.1.2 获取列/行的区别

# 因为date.table所创建的data里的每一列相当于一个变量,因此调用某一行时不需要加DT$
> DT[ID == "a"]
   ID a  b  c
1:  a 4 10 16
2:  a 5 11 17

# 而data.frame所创建的data众所周知是下面这样的
# 不指定data,即DX$,错!
> DX[ID == "a"]
Error in `[.data.frame`(DX, ID == "a") : object 'ID' not found
# 不设置代表取全列的符号“,”,错!
> DX[DX$ID == "a"]
Error in `[.data.frame`(DX, DX$ID == "a") : undefined columns selected
# 这才是data.frame的data的标准用法
> DX[DX$ID == "a",]
  ID a  b  c
4  a 4 10 16
5  a 5 11 17

另外,还会发现date.table所创建的data并不会创建和使用固定的行名,而data.frame所创建的data是要指定的或自动分配行名。

2.1.3 获取前两行

> DT[1:2]
   ID a b  c
1:  b 1 7 13
2:  b 2 8 14
> DX[1:2]
  ID a
1  b 1
2  b 2
3  b 3
4  a 4
5  a 5
6  c 6

蛤?数据框还能这样DX[1:2]取数据?而且是前两列?(弱小又无助.jpg)

在这种情况下,没有条件。行索引已在中提供i。因此,对于那些行索引,我们data.tableflightsat行返回所有列。

我们可以看到取行也是很大差距的

2.3 使用i取行

我们将使用通过flights包获得的NYC-flights14数据(仅在GitHub上可用),它包含运输统计局 2014年从纽约市机场起飞的所有航班的按时航班数据(灵感来自nycflights13)。该数据仅适用于2014年1月10日。

我们可以使用data.table的快速友好的文件阅读器直接fread进行加载flights

# get the file "flights14.csv"
URL = "https://raw.githubusercontent.com/Rdatatable/data.table/master/vignettes/flights14.csv"
flights <- fread(input)
> flights
        year month day dep_delay arr_delay carrier origin dest air_time distance hour
     1: 2014     1   1        14        13      AA    JFK  LAX      359     2475    9
     2: 2014     1   1        -3        13      AA    JFK  LAX      363     2475   11
     3: 2014     1   1         2         9      AA    JFK  LAX      351     2475   19
     4: 2014     1   1        -8       -26      AA    LGA  PBI      157     1035    7
     5: 2014     1   1         2         1      AA    JFK  LAX      350     2475   13
    ---                                                                              
253312: 2014    10  31         1       -30      UA    LGA  IAH      201     1416   14
253313: 2014    10  31        -5       -14      UA    EWR  IAH      189     1400    8
253314: 2014    10  31        -8        16      MQ    LGA  RDU       83      431   11
253315: 2014    10  31        -4        15      MQ    LGA  DTW       75      502   11
253316: 2014    10  31        -5         1      MQ    LGA  SDF      110      659    8

> dim(flights)
[1] 253316     11

2.3.1 获取6月所有以“肯尼迪国际机场”为始发机场的航班。

ans <- flights[origin == "JFK" & month == 6L]
> ans
      year month day dep_delay arr_delay carrier origin dest air_time distance hour
   1: 2014     6   1        -9        -5      AA    JFK  LAX      324     2475    8
   2: 2014     6   1       -10       -13      AA    JFK  LAX      329     2475   12
   3: 2014     6   1        18        -1      AA    JFK  LAX      326     2475    7
   4: 2014     6   1        -6       -16      AA    JFK  LAX      320     2475   10
   5: 2014     6   1        -4       -45      AA    JFK  LAX      326     2475   18
  ---                                                                              
8418: 2014     6  30        -3        -6      MQ    JFK  PIT       62      340   14
8419: 2014     6  30        -5       -32      MQ    JFK  RDU       65      427   14
8420: 2014     6  30        -3       -16      MQ    JFK  DCA       39      213   17
8421: 2014     6  30        -2         7      MQ    JFK  DCA       52      213    7
8422: 2014     6  30        -7       -18      MQ    JFK  RDU       67      427    8

2.3.2 排序:先以origin列在升序,然后以dest降序

我们可以使用R函数order()来完成此操作。

ans <- flights[order(origin, -dest)]
> ans
        year month day dep_delay arr_delay carrier origin dest air_time distance hour
     1: 2014     1   5         6        49      EV    EWR  XNA      195     1131    8
     2: 2014     1   6         7        13      EV    EWR  XNA      190     1131    8
     3: 2014     1   7        -6       -13      EV    EWR  XNA      179     1131    8
     4: 2014     1   8        -7       -12      EV    EWR  XNA      184     1131    8
     5: 2014     1   9        16         7      EV    EWR  XNA      181     1131    8
    ---                                                                              
253312: 2014    10  31        -1       -22      WN    LGA  ATL      112      762    9
253313: 2014    10  31        -5       -23      WN    LGA  ATL      112      762   20
253314: 2014     4   6        -6        -1      EV    LGA  AGS      110      678   10
253315: 2014     4   7         2         1      EV    LGA  AGS      111      678   11
253316: 2014     4  11         0       -19      EV    LGA  AGS      102      678   10

2.4 使用 j取列

2.4.1 提取arr_delay 列, 但是返回一个vector.

ans <- flights[, arr_delay]
head(ans)
[1]  13  13   9 -26   1   0

由于使用的是参数j,所以就要先加个,了。

2.4.2 提取arr_delay 列, 但是返回一个此列组成的data.table.

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

要确保列名要在list()里面,才能保证返回一个data.table。由上例可知不在list里面会返回一个vector。

此外,list()还被允许写为.(),非常地方便,下文就用简写的形式了。

2.4.3 提取多列

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

2.4.4 提取多列,并对列名重命名

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

3 使用j进行计算

3.1 有多少航班总晚点时长<0 ?

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

上文说过,每一列都是一个变量,因此我们可以对每一列的设置使用数学函数进行计算。

3.2 i取行&做 j运算

计算6月份所有以“肯尼迪国际机场”为始发机场的航班的平均到达和起飞延迟:

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年总共有多少航班从JFK机场出发 ?

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

3.3 特殊符号.N

.N是一个特殊的内置变量,它保存当前组中的观测值数量。当与by下一节中将要结合使用时,它特别有用。在没有分组操作的情况下,它仅返回子集中的行数。

因此,我们现在可以通过使用.N以下命令来完成相同的任务:

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

3.4 提取指定多列的几种方法

# 方法一,同list()
> flights[, .(day, hour)]
        day hour
# 方法二
> flights[, c("day", "hour")]

# 方法三,'..'前缀
> a=c("day", "hour")
> flights[, ..a]

# 方法四,使用参数'with = F'
select_cols = c(day, hour)
> flights[ , select_cols, with = FALSE]

# 以上结果均为:
        day hour
     1:   1    9
     2:   1   11
     3:   1   19
     4:   1    7
     5:   1   13
    ---         
253312:  31   14
253313:  31    8
253314:  31   11
253315:  31   11
253316:  31    8

with参数默认是TURE,因为这样我能够对select出的数据做更多的事情,如果输出的是data.table就不方便继续对里面的数据进行编辑了。当其与by参数连用时就会看得出来其好处,下文会讲到。

3.5 反选:!或者-

ns <- flights[, !c("arr_delay", "dep_delay")]
# or
ans <- flights[, -c("arr_delay", "dep_delay")]
> ns
        year month day carrier origin dest air_time distance hour
     1: 2014     1   1      AA    JFK  LAX      359     2475    9
     2: 2014     1   1      AA    JFK  LAX      363     2475   11
     3: 2014     1   1      AA    JFK  LAX      351     2475   19
     4: 2014     1   1      AA    LGA  PBI      157     1035    7
     5: 2014     1   1      AA    JFK  LAX      350     2475   13
    ---                                                          
253312: 2014    10  31      UA    LGA  IAH      201     1416   14
253313: 2014    10  31      UA    EWR  IAH      189     1400    8
253314: 2014    10  31      MQ    LGA  RDU       83      431   11
253315: 2014    10  31      MQ    LGA  DTW       75      502   11
253316: 2014    10  31      MQ    LGA  SDF      110      659    8

3.6 连选

> flights[, year:day]
        year month day
     1: 2014     1   1
     2: 2014     1   1
     3: 2014     1   1
     4: 2014     1   1
     5: 2014     1   1
    ---               
253312: 2014    10  31
253313: 2014    10  31
253314: 2014    10  31
253315: 2014    10  31
253316: 2014    10  31

# 反转day, month和year
> flights[, day:year]
        day month year
     1:   1     1 2014
     2:   1     1 2014
     3:   1     1 2014
     4:   1     1 2014
     5:   1     1 2014
    ---               
253312:  31    10 2014
253313:  31    10 2014
253314:  31    10 2014
253315:  31    10 2014
253316:  31    10 2014

# 反选之连选
ans <- flights[, -(year:day)]
# or
ans <- flights[, !(year:day)]

4 高级用法——by汇总

4.1 使用by进行分组

获取每个机场的航班数:

> flights[, .(.N), by = .(origin)]
   origin     N
1:    JFK 81483
2:    LGA 84433
3:    EWR 87400
  • 分组依据是origin.N对当前组分别进行行数的统计

  • 分组变量的原始顺序保留在结果中。注意这一点很重要!

  • by还可以接受列名称的字符向量

flights[, .(.N), by = "origin"]
  • 如果只有一列或表达式来引用jby,我们可以删除.()符号。这纯粹是为了方便。我们可以改为:
ans <- flights[, .N, by = origin]

我们将在以后适用的地方使用这种方便的形式。

计算承运商代码为AA的每个机场的航班数

> flights[carrier == "AA", .N, by = origin]
   origin     N
1:    JFK 11923
2:    LGA 11730
3:    EWR  2649
  • 首先获得要处理的对象i,即AA;分组依据是origin;处理方式是j,即.N,统计行数。

  • 因此我们就能得出以机场名为分组的对应的承运商代码为AA的航班数的个数。

计算每对origindest的对应的承运商代码为AA的航班数的个数

> ans = flights[carrier == "AA", .N, by = .(origin, dest)]
> head(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

计算每个月份每对origdest的平均起飞晚点时间和平均到达晚点时间

ans = (flights[carrier == "AA", .(mean(dep_delay), mean(arr_delay)), by = .(origin, dest, month)])
> head(ans)
   origin dest month         V1        V2
1:    JFK  LAX     1 14.2289157  6.590361
2:    LGA  PBI     1  0.3103448 -7.758621
3:    EWR  LAX     1  7.5000000  1.366667
4:    JFK  MIA     1 18.7430168 15.720670
5:    JFK  SEA     1 30.7500000 14.357143
6:    EWR  MIA     1 12.1235955 11.011236

4.2 排序:keyby

data.table保留组的原始顺序是有意并有意设计的。在某些情况下,保留原始顺序至关重要。但是有时我们希望根据分组中的变量自动排序。

方法很简单:将by改为keyby即可,默认升序。

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

4.3 链接

计算每对origindest的对应的承运商代码为AA的航班数的个数,并以origin升序,以dest降序

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

4.4 在by中使用表达式

计算晚发早归(含正点到)的航班次数

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

4.5 j中的特殊符号.SD

特殊符号.SD表示subset of data,是根据by来进行分组。以dataDT来说明:

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 and 1 cols): ID

使用lapply函数计算分组后的每一列的均值:

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求出以ID为分组的三组(如上例所示)
  • 然后lapply的功能就是对.SD中每一组的每一列使用mean求均值。

4.6 指定你想要计算的行

使用参数.SDcols

> 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

得到每个月的前两行

ans <- flights[, head(.SD, 2), by = month]
> head(ans)
   month year day dep_delay arr_delay carrier origin dest air_time distance hour
1:     1 2014   1        14        13      AA    JFK  LAX      359     2475    9
2:     1 2014   1        -3        13      AA    JFK  LAX      363     2475   11
3:     2 2014   1        -1         1      AA    JFK  LAX      358     2475    8
4:     2 2014   1        -5         3      AA    JFK  LAX      358     2475   11
5:     3 2014   1       -11        36      AA    JFK  LAX      375     2475    8
6:     3 2014   1        -3        14      AA    JFK  LAX      368     2475   11

4.7 为什么参数j如此灵活多样?

这样是为了使得R基础函数也能应用到其中,使得其功能更强大且具有高的兼容性。

如何对以ID为分组的每一subset的a列和b列进行连接?

> 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

如何对以ID为分组的每一subset的a列和b列进行连接,但是以list的形式输出连接结果?

> 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

4.8 结合print()函数的妙用

结合print()函数你就能更好地理解j参数每步在做什么了。

> # (1) look at the difference between

> DT[, print(c(a,b)), by = ID]
[1] 1 2 3 7 8 9
[1]  4  5 10 11
[1]  6 12
Empty data.table (0 rows and 1 cols): ID

> # (2) and

> DT[, print(list(c(a,b))), by = ID]
[[1]]
[1] 1 2 3 7 8 9

[[1]]
[1]  4  5 10 11

[[1]]
[1]  6 12

Empty data.table (0 rows and 1 cols): ID

它能够返回每一组的处理结果。可以发现(1)中每一组返回的是个vector,而(2)中每组返回的是个list。

5 总结

data.table 的通用语法:

DT[i, j, by]

i的用法:

  • 你可以用i根据列值以处理data.frame产生的data所类似的方式来取行,但是你不必使用在每列前面加DT$,因为DT在data.table产生的的data的列名,本身就相当于一个变量,可以直接调用。
  • 使用order函数对列进行排序,其使用了data.table的快速排序功能。

j的用法:

  • 取列:DT[, .(colA, colB)].
  • 取列:DT[, c("colA", "colB")].
  • 计算列:DT[, .(sum(colA), mean(colB))].
  • 提供列名: DT[, .(sA =sum(colA), mB = mean(colB))].
  • i连用: DT[colA > value, sum(colB)].

by

  • 通过给出一组列名的list或者character vector,对这些列进行分组;也可以使用表达式进行分组。j具有非常高的灵活性,其结合基础函数和iby可以显示出强大的功能。
  • 处理多列。
  • 设置keyby以自定义排序方式。
  • j中使用 .SD.SDcols用以得到以by为分类依据的subset,和规定所要处理的列;并且可以使用基础函数对subset进行分别处理:
    • 结合lapply函数,使用特定函数fun对特定的列的特定分类方式所得的subset进行处理:DT[, lapply(.SD, fun), by = ..., .SDcols = ...]
    • 返回前两行:DT[, head(.SD, 2), by = ...]
    • 联合使用ijbyDT[col > val, head(.SD, 1), by = ...]

最后记住一点:

一旦j返回的是一个list,那么这个list的每个元素都将成为一列。

相关文章

网友评论

      本文标题:R包data.table详情介绍

      本文链接:https://www.haomeiwen.com/subject/fxotactx.html