data.table包提供了一个非常简洁的通用格式:DT[i,j,by],可以理解为:对于数据集DT,选取子集行i,通过by分组计算j,对比与dplyr等包,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
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
接下来我们要介绍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包
使用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/。商业使用请联系作者。