1. 程式人生 > >R語言data.table簡介

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