data table使用

来源:互联网 发布:影视包装培训软件 编辑:程序博客网 时间:2024/06/06 10:51

转载
http://blog.163.com/yugao1986@126/blog/static/6922850820145305014187

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

require(data.table)

Loading required package: data.table

1.创建data.table格式数据

类似于data.frame数据的创建,使用data.table函数

(DF = data.frame(x=c(“b”,”b”,”b”,”a”,”a”), v=rnorm(5)))

x v

1 b -0.8870

2 b 1.6066

3 b -0.1895

4 a 0.2375

5 a 1.0084

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

x v

1: b -1.8458

2: b -0.2212

3: b -0.5812

4: a 0.2949

5: a 1.7858

可以看出,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 MB COLS KEY

[1,] CARS 50 1 speed,dist

[2,] DT 5 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 -0.2212

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

x v

1: b -1.8458

2: b -0.2212

3: b -0.5812

由于DT没有行名称,所以下面的命令不能正常运行:

cat(try(DT[“b”, ], silent=TRUE))

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 v

1: a 0.2949

2: a 1.7858

3: b -1.8458

4: b -0.2212

5: b -0.5812

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

tables()

NAME NROW MB COLS KEY

[1,] CARS 50 1 speed,dist

[2,] DT 5 1 x,v x

Total: 2MB

现在,DT数据已经拥有Key:x,我们尝试列出所有x=b的数据

DT[“b”, ]

x v

1: b -1.8458

2: b -0.2212

3: b -0.5812

使用mult可以筛选出每组数据的第一个观测值和最后一个观测值

DT[“b”, mult=”first”]

x v

1: b -1.846

DT[“b”, mult=”last”]

x v

1: b -0.5812

下面创建一个足够大的数据来说明“向量检索法”和“二元检索法”的效率差异。

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

1.56 0.05 1.60

head(DF, 3)

x y v

1 A a 0.08119

2 A a 0.64764

3 A a 0.80780

tail(DF, 3)

x y v

10000066 Z z 0.65856

10000067 Z z 0.01941

10000068 Z z 0.88818

dim(DF)

[1] 10000068 3

下面我们从DF中剥离其中任意一组

‘向量检索法’

(tt=system.time(ans1 <- DF[DFx=="R" & DFy==”h”,]))

user system elapsed

2.92 0.14 3.06

head(ans1, 3);dim(ans1)

x y v

6642058 R h 0.90416

6642059 R h 0.86002

6642060 R h 0.02253

[1] 14793 3

‘二元检索法’

DT = as.data.table(DF)
system.time(setkey(DT,x,y))#一次性遍历所有元素时间

user system elapsed

0.26 0.04 0.31

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

user system elapsed

0.01 0.00 0.01

head(ans2, 3);dim(ans2)

x y v

1: R h 0.90416

2: R h 0.86002

3: R h 0.02253

[1] 14793 3

identical(ans1v,ans2v)

[1] TRUE

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

当然,data.table也支持向量检索,但这样的话效率会低很多,我们应尽量避免这种情况。例如:

system.time(ans1 <- DT[x==”R” & y==”h”,])#低效的data.table用法

user system elapsed

2.41 0.08 2.49

system.time(ans2 <- DF[DFx=="R" & DFy==”h”,])#data.frame用法

user system elapsed

4.59 0.20 4.89

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

3.快速分组

对于data.table,使用”[i, j]“进行二元检索,我们可以接”by”进行分组计算

DT[, sum(v), by=x]

x V1

1: A 192333

2: B 192379

3: C 192299

4: D 192062

5: E 192653

6: F 192099

7: G 192296

8: H 192402

9: I 192396

10: J 192262

11: K 192200

12: L 192308

13: M 192475

14: N 192103

15: O 192423

16: P 192341

17: Q 192340

18: R 192135

19: S 192233

20: T 192492

21: U 192434

22: V 191940

23: W 192353

24: X 192466

25: Y 192206

26: Z 192385

x V1

该种方法相当高效,下面我们将其与tapply函数进行对比

ttt=system.time(tt <- tapply(DTv,DTx,sum)); ttt

user system elapsed

3.15 0.48 3.67

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

user system elapsed

0.34 0.00 0.34

head(tt);head(ss)

A B C D E F

192333 192379 192299 192062 192653 192099

x V1

1: A 192333

2: B 192379

3: C 192299

4: D 192062

5: E 192653

6: F 192099

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

[1] TRUE

下面我们按两列进行分组,比较两种方法的效率

ttt=system.time(tt <- tapply(DTv,list(DTx,DT$y),sum)); ttt

user system elapsed

5.64 0.63 6.36

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

user system elapsed

0.35 0.00 0.34

tt[1:5,1:5]

a b c d e

A 7507 7417 7360 7383 7399

B 7449 7453 7405 7374 7384

C 7412 7388 7375 7442 7388

D 7430 7387 7418 7338 7433

E 7387 7464 7440 7434 7464

head(ss)

x y V1

1: A a 7507

2: A b 7417

3: A c 7360

4: A d 7383

5: A e 7399

6: A f 7413

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

[1] TRUE

4.其他

关于data.table的更多信息参见:https://github.com/Rdatatable/data.table

0 0