R语言data.table简介

data.table包提供了一个非常简洁的通用格式:DT[i,j,by],可以理解为:对于数据集DT,选取子集行i,通过by分组计算j,对比与dplyr等包,data.table的运行速度更快。

创建一个data.table

set.seed(1)
DF = data.frame(x=c("b","b","b","a","a"),v=rnorm(5))
DF
##   x          v
## 1 b -0.6264538
## 2 b  0.1836433
## 3 b -0.8356286
## 4 a  1.5952808
## 5 a  0.3295078

这跟data.frame的创建是一样的

DT = data.table(x=c("b","b","b","a","a"),v=rnorm(5))
DT
##    x          v
## 1: b -0.8204684
## 2: b  0.4874291
## 3: b  0.7383247
## 4: a  0.5757814
## 5: a -0.3053884

或者可以直接将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

我们可以使用tables()函数查看所有在内存的data.table

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

1. Keys

Keys在data.table中是一个重要的概念,在一个data.table中只能设置一个key,但是这一个key可以包含多个列。当我们设置好key后,data.table会将数据按照key来排序。

DT[2,] #取第2行
##    x         v
## 1: b 0.4874291
DT[x=="b",] #取x=b的行
##    x          v
## 1: b -0.8204684
## 2: b  0.4874291
## 3: b  0.7383247
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.

当没有设置key时,DT[“b”]操作会报以上错误,我们可以用setkey() 给DT设置key

setkey(DT,x)
DT["b",]
DT["b"] #更简洁的写法
##    x          v
## 1: b -0.8204684
## 2: b  0.4874291
## 3: b  0.7383247

默认情况下会返回该分组的所有元素mult='all',但是如果我们想要其他结果,比如返回第一个元素,或返回最后一个元素

DT["b",mult="first"]
##    x          v
## 1: b -0.8204684
DT["b",mult="last"]
##    x         v
## 1: b 0.7383247

接下下我们创建一个1000万行的数据,用来演示data.table的性能

grpsize = ceiling(1e7/26^2) # 10 million rows, 676 groups
tt=system.time( DF <- data.frame(
 x=rep(LETTERS,each=26*grpsize),
 y=rep(letters,each=grpsize),
 v=runif(grpsize*26^2),
 stringsAsFactors=FALSE)
 )
head(DF,3)
##   x y         v
## 1 A a 0.9347052
## 2 A a 0.2121425
## 3 A a 0.6516738
tail(DF,3)
##          x y         v
## 10000066 Z z 0.9537745
## 10000067 Z z 0.6654964
## 10000068 Z z 0.9368095
dim(DF)
## [1] 10000068        3

我们试试将DF中x为“R”的行与y为”h”的行提取出来

system.time(ans1 <- DF[DF$x=="R" & DF$y=="h",])
##    user  system elapsed 
##    1.35    0.07    1.42
head(ans1,3)
##         x y         v
## 6642058 R h 0.2442074
## 6642059 R h 0.6491902
## 6642060 R h 0.5894140

我们使用data.table做相同的操作:

DT = as.data.table(DF)
system.time(setkey(DT,x,y))
##    user  system elapsed 
##    0.13    0.01    0.14
system.time(ans2 <- DT[list("R","h")])
##    user  system elapsed 
##    0.02    0.00    0.02

可以看到,当我们设置好key后,提取行的操作基本不需要等待时间,比我们平时用的操作快了100倍。要注意的是,如果使用”==”操作符,那么它会扫描整个数组,虽然data.table用这种方法也可以提取,但很慢,要尽量避免。

system.time(ans1 <- DT[x=="R" & y=="h"]) # works but is using data.table badly
##    user  system elapsed 
##    1.06    0.00    1.06

2. 快速聚合(fast grouping)

接下来我们要介绍data.table的第二个参数

DT[,sum(v)]
## [1] 4999770
head(DT[,sum(v),by=x])
##     x       V1
##  1: A 192270.6
##  2: B 192261.3
##  3: C 192292.2
##  4: D 191924.2
##  5: E 192457.3
##  6: F 192240.2

以上代码以x为分组,依次调用sum函数,统计了每个分组x的总和。显然这一功能在plyr包和dplyr包也有相对应的函数实现,接下来我们比较一下这3个包的速度。

#plyr包
system.time(
  ddply(DF,.(x),function(x)sum(x$v))
  )
##    user  system elapsed 
##    1.71    0.22    1.94
#dplyr包
system.time({
  DF%>%
  group_by(x)%>%
  summarise(sum(v))
})
##    user  system elapsed 
##    0.60    0.12    0.72
#data.table包
DT = as.data.table(DF)
system.time({
DT[,sum(v),by=x]
})
##    user  system elapsed 
##    0.12    0.02    0.14

从以上结果中很明显看到data.table远远快于dplyr和plyr包

3. 快速连接

使用DT[X],该操作会将X中key(没指定key则默认第一列)与DT的key作连接,同理,X[DT]会将DT与X作连接

DT = data.table(x=rep(c("a","b","c"),each=3), y=c(1,3,6), v=1:9)
DT
##    x y v
## 1: a 1 1
## 2: a 3 2
## 3: a 6 3
## 4: b 1 4
## 5: b 3 5
## 6: b 6 6
## 7: c 1 7
## 8: c 3 8
## 9: c 6 9
X = data.table(c("b","c"),foo=c(4,2))
X
##    V1 foo
## 1:  b   4
## 2:  c   2
setkey(DT,x)
DT[X]
##    x y v foo
## 1: b 1 4   4
## 2: b 3 5   4
## 3: b 6 6   4
## 4: c 1 7   2
## 5: c 3 8   2
## 6: c 6 9   2
setkey(X,V1)
X[DT]
##    V1 foo y v
## 1:  a  NA 1 1
## 2:  a  NA 3 2
## 3:  a  NA 6 3
## 4:  b   4 1 4
## 5:  b   4 3 5
## 6:  b   4 6 6
## 7:  c   2 1 7
## 8:  c   2 3 8
## 9:  c   2 6 9

我们也可以使用on操作来连接两个相同的列:

DT = data.table(x=rep(c("a","b","c"),each=3), y=c(1,3,6), v=1:9)
X = data.table(x=c("b","c"),foo=c(4,2))
DT[X, on="x"] # join on columns 'x'
##    x y v foo
## 1: b 1 4   4
## 2: b 3 5   4
## 3: b 6 6   4
## 4: c 1 7   2
## 5: c 3 8   2
## 6: c 6 9   2

我们也可以使用data.table中的merge函数

(dt1 <- data.table(A = letters[1:10], X = 1:10, key = "A"))
##     A  X
##  1: a  1
##  2: b  2
##  3: c  3
##  4: d  4
##  5: e  5
##  6: f  6
##  7: g  7
##  8: h  8
##  9: i  9
## 10: j 10
(dt2 <- data.table(A = letters[5:14], Y = 1:10, key = "A"))
##     A  Y
##  1: e  1
##  2: f  2
##  3: g  3
##  4: h  4
##  5: i  5
##  6: j  6
##  7: k  7
##  8: l  8
##  9: m  9
## 10: n 10
merge(dt1, dt2)
##    A  X Y
## 1: e  5 1
## 2: f  6 2
## 3: g  7 3
## 4: h  8 4
## 5: i  9 5
## 6: j 10 6

作为分享主义者(sharism),本人所有互联网发布的图文均遵从CC版权,转载请保留作者信息并注明作者a358463121专栏:http://blog.csdn.net/a358463121,如果涉及源代码请注明GitHub地址:https://github.com/358463121/。商业使用请联系作者。

你可能感兴趣的:(R语言)