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/。商業使用請聯絡作者。