您的位置:首页 > 其它

data.table包简介

2016-02-09 11:38 204 查看


data.table包简介


junjun


2016年2月9日

参考:http://blog.163.com/yugao1986@126/blog/static/6922850820145305014187


data.table包简介

data.table包主要特色是:设置keys、快速分组和滚得时序的快速合并。data.table主要通过二元检索法大大提高数据操作的效率,同时它也兼容适用于data.frame的向量检索法。
#1、加载data.table包并创建数据
library(data.table)

## Warning: package 'data.table' was built under R version 3.2.3

#类似于data.frame数据的创建,使用data.table函数
(DF = data.frame(x=c("b","b","b","a","a"), v=rnorm(5)))

##   x          v
## 1 b  2.6018532
## 2 b  1.3779741
## 3 b  0.1936382
## 4 a -1.7746176
## 5 a -0.1412760

(DT = data.table(x=c("b","b","b","a","a"), v=rnorm(5)))

##    x          v
## 1: b -0.9180313
## 2: b  1.5366401
## 3: b  0.2097379
## 4: a -0.2030940
## 5: a  0.6819083

#可以看出,DF和DT的行号有一些区别,这也是data.frame和data.table主要区别。

#利用data.frame创建data.table:
CARS <- data.table(cars)
head(CARS)

##    speed dist
## 1:     4    2
## 2:     4   10
## 3:     7    4
## 4:     7   22
## 5:     8   16
## 6:     9   10

#已经创建了两个data.table数据,tables命令可以显示该信息:
tables()

##      NAME NROW NCOL MB COLS       KEY
## [1,] CARS   50    2  1 speed,dist
## [2,] DT      5    2  1 x,v
## Total: 2MB

#其中"MB"列可以快速评估内存使用,发现删除可以释放内存的表格。

#查看表中数据类型
sapply(DT, class)

##           x           v
## "character"   "numeric"

#2、键Keys
#类似人的姓名有“姓”和“名”组成,data.table中的Keys可以由多个部分组成,Keys的组成部分可以使整数、因子、字符串或其他格式,而且data.table中的每行数据是按照Keys排序的,所以data.table数据最多只有一个Key.

#DT和CARS是data.table格式,当前没有设置任何Keys,我们可以使用适用于数据框data.frame的语法:
DT[2, ]

##    x       v
## 1: b 1.53664

DT[DT$x=="b", ]

##    x          v
## 1: b -0.9180313
## 2: b  1.5366401
## 3: b  0.2097379

#由于DT没有行名称,所以下面的命令不能正常运行:
cat(try(DT["b", ], silent = T))

## Error in `[.data.table`(DT, "b", ) :
##   When i is a data.table (or character vector), x must be keyed (i.e. sorted, and, marked as sorted) so data.table knows which columns to join to and take advantage of x being sorted. Call setkey(x,...) first, see ?setkey.

#报错信息显示,我们需要对data.table数据设置keys
setkey(DT, x)
#此时,DT已经按照x值进行了重新排序,如果要确认一个data.table数据是否有keys,我们可以使用haskey()、key()、attributes()或者tables()函数。
tables()

##      NAME NROW NCOL MB COLS       KEY
## [1,] CARS   50    2  1 speed,dist
## [2,] DT      5    2  1 x,v        x
## Total: 2MB

#现在,DT数据已经拥有Key:x,我们尝试列出所有x=b的数据
DT["b", mult="first"]

##    x          v
## 1: b -0.9180313

DT["b", mult="last"]

##    x         v
## 1: b 0.2097379

#3、下面创建一个足够大的数据来说明“向量检索法”和“二元检索法”的效率差异
##10000068行,676个分组的数据DF
grpsize <- ceiling(1e7/26^2)
tt <- system.time(DF <- data.frame(
x=rep(LETTERS,each=26*grpsize),
y=rep(letters,each=grpsize),
v=runif(grpsize*26^2),
stringsAsFactors=FALSE
))
tt

##    user  system elapsed
##    0.71    0.03    0.75

head(DF, 3)

##   x y         v
## 1 A a 0.6166219
## 2 A a 0.8981881
## 3 A a 0.5288605

tail(DF, 3)

##          x y          v
## 10000066 Z z 0.01418355
## 10000067 Z z 0.14773928
## 10000068 Z z 0.04807132

dim(DF)

## [1] 10000068        3

#下面我们从DF中剥离其中任意一组
#1)'向量检索法'
(tt <- system.time(ans1 <- DF[DF$x=="R" & DF$y=="h", ]))

##    user  system elapsed
##    0.85    0.05    0.89

head(ans1, 3)

##         x y         v
## 6642058 R h 0.2144749
## 6642059 R h 0.3516665
## 6642060 R h 0.7069858

dim(ans1)

## [1] 14793     3

#2)'二元检索法'
DT <- as.data.table(DF)
#一次性遍历所有元素时间
system.time(setkey(DT, x, y))

##    user  system elapsed
##    0.08    0.00    0.08

#二元条件检索
(ss <- system.time(ans2 <- DT[J("R", "h")]))

##    user  system elapsed
##       0       0       0

head(ans2, 3)

##    x y         v
## 1: R h 0.2144749
## 2: R h 0.3516665
## 3: R h 0.7069858

dim(ans2)

## [1] 14793     3

identical(ans1$v,ans2$v)

## [1] TRUE

#可以看出使用二元检索法较向量检索法,效率上要高很多。

#4、data.table也支持向量检索,但这样的话效率会低很多,我们应尽量避免这种情况。例如:
#1)低效的data.table用法
system.time(ans1 <- DT[x=="R" & y=="h",])

##    user  system elapsed
##    0.62    0.00    0.62

#2)data.frame用法
system.time(ans2 <- DF[DF$x=="R" & DF$y=="h",])

##    user  system elapsed
##    0.72    0.05    0.77

mapply(identical,ans1,ans2)

##    x    y    v
## TRUE TRUE TRUE

#上例中,当使用DT$x==“R"时候,就会使用”向量检索法“遍历数据的整列,y=="h"同样,最后再使用”&“合并两个条件。data.table包提供了J()函数用于数据合并,可以大大提高效率。
identical( DT[J("R","h"), ], DT[data.table("R","h"), ])

## [1] TRUE

#5、快速分组
#1)对于data.table,使用”[i, j]“进行二元检索,我们可以接"by"进行分组计算
DT[, sum(v), by=x]

##     x       V1
##  1: A 192354.6
##  2: B 192247.6
##  3: C 192292.0
##  4: D 192264.5
##  5: E 192288.5
##  6: F 192220.6
##  7: G 192395.2
##  8: H 192222.0
##  9: I 192040.1
## 10: J 192310.9
## 11: K 192260.1
## 12: L 192304.8
## 13: M 192153.6
## 14: N 191912.4
## 15: O 192417.9
## 16: P 192633.6
## 17: Q 192184.2
## 18: R 192329.8
## 19: S 192318.8
## 20: T 192192.2
## 21: U 192036.3
## 22: V 192267.9
## 23: W 192242.6
## 24: X 192354.4
## 25: Y 192666.8
## 26: Z 192172.9
##     x       V1

#该种方法相当高效,下面我们将其与tapply函数进行对比
(ttt <- system.time(tt <- tapply(DT$v, DT$x, sum)))

##    user  system elapsed
##    0.95    0.17    1.12

(sss <- system.time(ss <- DT[, sum(v), by=x]))

##    user  system elapsed
##     0.1     0.0     0.1

head(tt)

##        A        B        C        D        E        F
## 192354.6 192247.6 192292.0 192264.5 192288.5 192220.6

head(ss)

##    x       V1
## 1: A 192354.6
## 2: B 192247.6
## 3: C 192292.0
## 4: D 192264.5
## 5: E 192288.5
## 6: F 192220.6

identical(as.vector(tt), ss$V1)

## [1] TRUE

#下面我们按两列进行分组,比较两种方法的效率
(ttt=system.time(tt <- tapply(DT$v,list(DT$x,DT$y),sum)))

##    user  system elapsed
##    1.17    0.27    1.44

(sss=system.time(ss <- DT[,sum(v),by="x,y"]))

##    user  system elapsed
##    0.11    0.00    0.11

tt[1:5, 1:5]

##          a        b        c        d        e
## A 7452.168 7337.349 7346.136 7358.049 7364.880
## B 7416.583 7428.418 7386.688 7343.408 7427.261
## C 7327.265 7440.357 7375.328 7363.778 7389.635
## D 7375.853 7381.372 7409.695 7405.020 7406.129
## E 7372.986 7418.662 7376.146 7390.650 7356.680

head(ss)

##    x y       V1
## 1: A a 7452.168
## 2: A b 7337.349
## 3: A c 7346.136
## 4: A d 7358.049
## 5: A e 7364.880
## 6: A f 7407.672

identical(as.vector(t(tt)), ss$V1)

## [1] TRUE
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: