data.table包使用總結


裝載

作者:kicilove  
來源:CSDN  
原文:https://blog.csdn.net/kicilove/article/details/76060980?utm_source=copy 

data.table包使用總結

R中的data.table包提供了一個data.frame的高級版本,讓你的程序做數據整型的運算速度大大的增加。data.table已經在金融,基因工程學等領域大放光彩。他尤其適合那些需要處理大型數據集(比如 1GB 到100GB)需要在內存中處理數據的人。不過這個包的一些符號並不是很容易掌握,因為這些操作方式在R中比較少見。這也是這篇文章的目的,為了給大家提供一個速查的手冊。

    data.table的通用格式: DT[i, j, by],對於數據集DT,選取子集行i,通過by分組計算j

1.首先下載安裝data.table包

install.packages("data.table")
library(data.table)

    1
    2

利用fread函數導入數據,在data.table包支持使用fread函數從本地或者web上導入數據,功能相當於base包的read.csv。

mydata = fread("https://github.com/arunsrinivasan/satrdays-workshop/raw/master/flights_2014.csv")

    1

2.數據簡單描述

nrow(mydata)
[1] 253316

ncol(mydata)
[1] 17

names(mydata)
[1] "year"      "month"     "day"       "dep_time"  "dep_delay" "arr_time"  "arr_delay"
[8] "cancelled" "carrier"   "tailnum"   "flight"    "origin"    "dest"      "air_time"
[15] "distance"  "hour"      "min"

head(mydata[,c(2:6)])
   month day dep_time dep_delay arr_time
1:     1   1      914        14     1238
2:     1   1     1157        -3     1523
3:     1   1     1902         2     2224
4:     1   1      722        -8     1014
5:     1   1     1347         2     1706
6:     1   1     1824         4     2145

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19

3.選擇或保留某幾列

.()為list()的一個別名。如果使用.(),返回的為一個data.table對象。如果不使用.(),結果為返回一個向量。

如果要選擇carrier列,那么可以選擇如下幾種方式實現:

dat1 = mydata[ , carrier] # 返回一組向量

dat1 = mydata[ , .(carrier)] #返回一個data.table

dat1 = mydata[, c("carrier"), with=FALSE] #返回一組數據框

    1
    2
    3
    4
    5

根據列的位置保留某幾列,比如選擇第二列:

dat2 =mydata[, 2, with=FALSE]

    1

保留多列:

dat3 = mydata[, .(origin, year, month, hour)]

    1

根據列的位置保留多列:

dat3 = mydata[, .(origin, year, month, hour)]

    1

刪去列:利用!符號刪除某列

dat5 = mydata[, !c("origin"), with=FALSE]

    1

刪去多列

dat6 = mydata[, !c("origin", "year", "month"), with=FALSE]

    1

利用%like% 命令進行模糊匹配:

dat7 = mydata[,names(mydata) %like% "dep", with=FALSE]

    1

4.對變量進行重命名

可以利用setnames()函數對變量進行重命名操作:

setnames(mydata, c("dest"), c("Destination"))

    1

對多個變量進行重命名:

setnames(mydata, c("dest","origin"), c("Destination", "origin.of.flight"))

    1

5.子集的篩選與過濾

假設要找到origin為‘JFK’的所有子集:

dat8 = mydata[origin == "JFK"]

    1

按多個條件選擇

dat9 = mydata[origin %in% c("JFK", "LGA")]

dat11 = mydata[origin == "JFK" & carrier == "AA"]

    1
    2
    3

6.利用索引提升數據操作效率

使用setkey()函數設置鍵值
setkey()函數可以在數據集mydata上設置鍵值。當我們設置好key后,data.table會將數據按照key來排序。
利用setkey函數將origin設置為mydata的索引:

setkey(mydata, origin)

    1

當設置好索引后,可直接利用索引的值進行過濾查找

data12 = mydata[c("JFK", "LGA")]

    1

來看看用了索引與沒用索引的搜索效率:

system.time(mydata[origin %in% c("JFK", "LGA")])
system.time(mydata[c("JFK", "LGA")])

    1
    2

對多個變量設置索引

setkey(mydata, origin, dest)
mydata[.("JFK", "MIA")]

    1
    2

這等同於:

mydata[origin == "JFK" & dest == "MIA"]

    1

重要參數

mult參數

mult參數是用來控制i匹配到的哪一行的返回結果默認情況下會返回該分組的所有元素
返回匹配到鍵值所在列(V2列)所有行中的第一行

 DT["A", mult ="first"]

    1

返回匹配到鍵值所在列(V2列)所有行中的最后一行

 DT["A", mult = "last"]

    1

nomatch參數

nomatch參數用於控制,當在i中沒有到匹配數據的返回結果,默認為NA,也能設定為0。0意味着對於沒有匹配到的行將不會返回。
返回匹配到鍵值所在列(V2列)所有包含變量值A或D的所有行:

 DT[c("A","D")]

    1

變量值A匹配到了,而變量值D沒有,故返回NA。
返回匹配到鍵值所在列(V2列)所有包含值A或D的所有行:

DT[c("A","D"), nomatch = 0]

    1

因為nomatch參數,值D沒有匹配到故不返回。

by=.EACHI參數

by=.EACHI允許按每一個已知i的子集分組,在使用by=.EACHI時需要設置鍵值
返回鍵值(V2列)中包含A或C的所有行中,V4列的總和。

 DT[c("A","C"),
     sum(V4)]

    1
    2

返回鍵值所在列(V2列)中包含A的行在V4列總和與包含C的行在V4列的總和。

 DT[c("A","C"),
     sum(V4), by=.EACHI]

    1
    2

使用setkey()設置一個多列主鍵

任意列都能使用setkey()來設置主鍵,這種方式可以選擇2個列作為一個主鍵。以下是一個等值連接V1列的每個組先根據V1排序,再根據V2排序。

setkey(DT,V1,V2)
無顯式返回結果

選擇鍵值1(V1列)為2且鍵值2(V2列)為C的行。

 DT[.(2,"C")]

    1

選擇鍵值1(V1列)為2且鍵值2(V2列)為A或C的行

 DT[.(2,c("A","C"))]

    1

7.對數據進行排序

利用setorder()函數可對數據進行排序:升序

mydata01 = setorder(mydata, origin)

    1

對數據進行降序

mydata02 = setorder(mydata, -origin)

    1

還可 基於多個變量進行排序

mydata03 = setorder(mydata, origin, -carrier)

    1

8.使用:=引用來添加或更新一列

在一行中使用:=引用來添加或更新列.

注意: 額外的指定 (DT <- DT[…])是多余的
使用:=來更新V1列:

> DT[, V1 := round(exp(V1),2)]
#這段代碼沒有顯式的返回結果,而V1列從[1] 1 2 1 2 … 變成了 [1] 2.72 7.39 2.72 7.39 …
> DT
      V1 V2      V3 V4
 1: 2.72  A -0.8981  1
 2: 7.39  B -0.3348  2
 3: 2.72  C -0.5014  3
 4: 7.39  A -0.1745  4
 5: 2.72  B -0.8981  5
 6: 7.39  C -0.3348  6
 7: 2.72  A -0.5014  7
 8: 7.39  B -0.1745  8
 9: 2.72  C -0.8981  9
10: 7.39  A -0.3348 10
11: 2.72  B -0.5014 11
12: 7.39  C -0.1745 12

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16

使用:=引用來添加或更新多列

使用:=更新V1列和V2列:

 >DT[, c("V1","V2") := list(round(exp(V1),2), LETTERS[4:6])]
 > DT
         V1 V2      V3 V4
 1:   15.18  D -0.8981  1
 2: 1619.71  E -0.3348  2
 3:   15.18  F -0.5014  3
 4: 1619.71  D -0.1745  4
 5:   15.18  E -0.8981  5
 6: 1619.71  F -0.3348  6
 7:   15.18  D -0.5014  7
 8: 1619.71  E -0.1745  8
 9:   15.18  F -0.8981  9
10: 1619.71  D -0.3348 10
11:   15.18  E -0.5014 11
12: 1619.71  F -0.1745 12
#同樣沒有顯式的返回結果,V1列的結果與上相同,V2列從[1] “A” “B” “C” “A” “B” “C” … 變成: [1] “D” “E” “F” “D” “E” “F” …

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16

使用函數:=

上例的另一種寫法,但會在書寫時更易並齊。而且,當添加[]時,結果會返回在屏幕中

 > DT[, ':=' (V1 =round(exp(V1),2),V2 = LETTERS[4:6])][]
     V1 V2      V3 V4
 1: Inf  D -0.8981  1
 2: Inf  E -0.3348  2
 3: Inf  F -0.5014  3
 4: Inf  D -0.1745  4
 5: Inf  E -0.8981  5
 6: Inf  F -0.3348  6
 7: Inf  D -0.5014  7
 8: Inf  E -0.1745  8
 9: Inf  F -0.8981  9
10: Inf  D -0.3348 10
11: Inf  E -0.5014 11
12: Inf  F -0.1745 12

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15

與上例變化相同,但是由於在語句最后添加了[],這一結果會返回至屏幕

通過使用:=來移除一列

移除V1列

> DT[, V1 := NULL]
> DT
    V2      V3 V4
 1:  D -0.8981  1
 2:  E -0.3348  2
 3:  F -0.5014  3
 4:  D -0.1745  4
 5:  E -0.8981  5
 6:  F -0.3348  6
 7:  D -0.5014  7
 8:  E -0.1745  8
 9:  F -0.8981  9
10:  D -0.3348 10
11:  E -0.5014 11
12:  F -0.1745 12
 #無顯式的返回結果,但V1列變為NULL

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16

通過使用:=來移除多列

移除V1列與V2列

 DT[, c("V1","V2") := NULL]
 #無顯式的返回結果,但V1列與V2列變為NULL

    1
    2

將一個包含列名的變量用小括號包裹起來,變量所傳遞的內容將會被刪除
注意:列名為Cols.chosen的列將會被刪除,這里不是刪除”V1”,”V2”列

 Cols.chosen = c("V1","V2")
 DT[, Cols.chosen := NULL]
 #無顯式的返回結果,列名為Cols.chosen的列將會被刪除
 #刪除指定變量Cols.chosen包含的V1列和V2列
 DT[, (Cols.chosen) := NULL]
 #無顯式的返回結果,列名為V1和V2的列變為NULL

    1
    2
    3
    4
    5
    6

對原數據增加一列

mydata[, dep_sch:=dep_time - dep_delay]

    1

增加多列

mydata002 = mydata[, c("dep_sch","arr_sch"):=list(dep_time - dep_delay, arr_time - arr_delay)]

    1

9.數據聚合的實現,並賦予名字

mydata[, .(mean = mean(arr_delay, na.rm = TRUE),
           median = median(arr_delay, na.rm = TRUE),
           min = min(arr_delay, na.rm = TRUE),
           max = max(arr_delay, na.rm = TRUE))]
       mean median  min  max
1: 8.146702     -4 -112 1494

mydata[,.(sum(distance),sd(hour))]
          V1       V2
1: 278507079 4.897891

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11

若列的長度不一,則會循環對齊

選擇V1這一列,並計算V3這列的標准差,將會得到一個標准差的值並循環補齊

DT <- data.table(V1=c(1L,2L),
                   V2=LETTERS[1:3],
                   V3=round(rnorm(4),4),
                   V4=1:12)
 DT[,.(V1, Sd.V3 = sd(V3))]
   V1     Sd.V3
 1:  1 0.2810601
 2:  2 0.2810601
 3:  1 0.2810601
 4:  2 0.2810601
 5:  1 0.2810601
 6:  2 0.2810601
 7:  1 0.2810601
 8:  2 0.2810601
 9:  1 0.2810601
10:  2 0.2810601
11:  1 0.2810601
12:  2 0.2810601

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18

多個表達式可以包裹在花括號中

輸出V2這一列並繪制V3這一列

 DT[,{print(V2)
  plot(V3)
  NULL}]
   [1] "A" "B" "C" "A" "B" "C" "A" "B" "C" "A" "B" "C"
NULL

    1
    2
    3
    4
    5

plot(V3)

對多個變量做聚合計算

mydata[, .(mean(arr_delay), mean(dep_delay))]

    1

如果要對大量的變量做聚合計算,可以使用.SD函數,和.SDcols函數。

mydata[, lapply(.SD, mean), .SDcols = c("arr_delay", "dep_delay")]

    1

默認的,.SD函數指對所有變量進行計算

mydata[, lapply(.SD, mean)]

    1

對多個變量實現多個統計指標計算

mydata[, sapply(.SD, function(x) c(mean=mean(x), median=median(x)))]

    1

10.GROUP BY函數

#按照單個變量分組
mydata[, .(mean_arr_delay = mean(arr_delay, na.rm = TRUE)), by = origin]

#按照多個變量分組
mydata[, .(mean_arr_delay = mean(arr_delay, na.rm = TRUE)), by = .(origin,carrier)]

    1
    2
    3
    4
    5

在by中調用函數

以sign(V1-1)為分組,計算各個分組中V4列的和:

DT[,.(V4.Sum = sum(V4)),by=sign(V1-1)]

    1
    2

使用函數.N來得到每個類別的總觀測數

在V1列中計算每個分組的觀測數

 DT[,.N,by=V1]
    V1 N
1:  1 6
2:  2 6

    1
    2
    3
    4

11.data.table高級操作總結

.N

.N可以用來表示行的數量或者最后一行

在i處使用:

DT[.N-1]
   V1 V2      V3 V4
1:  1  B -0.5765 11

    1
    2
    3

返回每一列的倒數第二行
在j處使用:

DT[,.N-1]
[1] 11

    1
    2

返回倒數第二行所在的行數。

.()

.()是list()的一個別名,他們在data.table中是等價的。當只有一個元素的位置j或者by中,是不需要.()的。

在j中使用:

DT[,.(V2,V3)] #or DT[,list(V2,V3)]
    V2      V3
 1:  A -0.8313
 2:  B  0.7615
 3:  C -0.5765

    1
    2
    3
    4
    5
    6

在by中使用:

 DT[, mean(V3),by=.(V1,V2)]
   V1 V2       V1
1:  1  A -0.70390
2:  2  B  0.06755
3:  1  C -0.70390
4:  2  A  0.06755
5:  1  B -0.70390
6:  2  C  0.06755
#以V1,V2為分組,對V3求均值

    1
    2
    3
    4
    5
    6
    7
    8
    9

.SD參數

.SD是一個data.table,他包含了各個分組,除了by中的變量的所有元素。.SD只能在位置j中使用:

 DT[, print(.SD), by=V2]
   V1      V3 V4
1:  1 -0.8313  1
2:  2 -0.6264  4
3:  1 -0.5765  7
4:  2  0.7615 10
   V1      V3 V4
1:  2  0.7615  2
2:  1 -0.8313  5
3:  2 -0.6264  8
4:  1 -0.5765 11
   V1      V3 V4
1:  1 -0.5765  3
2:  2  0.7615  6
3:  1 -0.8313  9
4:  2 -0.6264 12
Empty data.table (0 rows) of 1 col: V2

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17

以V2為分組,選擇每組的第一和最后一列:

 DT[,.SD[c(1,.N)], by=V2]
   V2 V1      V3 V4
1:  A  1 -0.8313  1
2:  A  2  0.7615 10
3:  B  2  0.7615  2
4:  B  1 -0.5765 11
5:  C  1 -0.5765  3
6:  C  2 -0.6264 12

    1
    2
    3
    4
    5
    6
    7
    8
    9

以V2為分組,計算.SD中所有元素的和:

DT[, lapply(.SD, sum), by=V2]
   V2 V1      V3 V4
1:  A  6 -1.2727 22
2:  B  6 -1.2727 26
3:  C  6 -1.2727 30
.SDcols

    1
    2
    3
    4
    5
    6

.SDcols常於.SD用在一起,他可以指定.SD中所包含的列,也就是對.SD取子集:

DT[, lapply(.SD,sum), by=V2,
+    .SDcols = c("V3","V4")]
   V2      V3 V4
1:  A -1.2727 22
2:  B -1.2727 26
3:  C -1.2727 30
#.SDcols也可以是一個函數的返回值:

    1
    2
    3
    4
    5
    6
    7

DT[, lapply(.SD,sum), by=V2,
+    .SDcols = paste0("V",3:4)]
   V2      V3 V4
1:  A -1.2727 22
2:  B -1.2727 26
3:  C -1.2727 30
#結果與上一個是相同的。

    1
    2
    3
    4
    5
    6
    7

12.串聯操作可以把表達式聚合在一起並避免多余的中間變量

把多個操作串聯起來,這等價於SQL中的having

#這個是不使用串聯的方法,先以V1為分組,對V4求和,然后再把分組總和大於35的取出來。
DT<-DT[, .(V4.Sum = sum(V4)),by=V1]
DT[V4.Sum > 35] #no chaining
V1 V4.Sum
1: 1 36
2: 2 42

    1
    2
    3
    4
    5
    6

使用串聯的方法:

DT[, .(V4.Sum = sum(V4)),by=V1][V4.Sum > 35 ]
V1 V4.Sum
1: 1 36
2: 2 42

    1
    2
    3
    4

分組求和之后對V1進行排序:

 DT[, .(V4.Sum = sum(V4)),by=V1][order(-V1)]
V1 V4.Sum
1: 2 42
2: 1 36

    1
    2
    3
    4

13.使用set()家族

set()

set()通常用來更新給定的行和列的值,要注意的是,他不能跟by結合使用。

rows = list(3:4,5:6)
cols = 1:2
 for (i in seq_along(rows))
+ {
+ set(DT,
+ i=rows[[i]],
+ j = cols[i],
+ value = NA)
+}

DT
    V1 V2      V3 V4
 1:  1  A -0.0559  1
 2:  2  B -0.4450  2
 3: NA  C  0.0697  3
 4: NA  A -0.1547  4
 5:  1 NA -0.0559  5
 6:  2 NA -0.4450  6
 7:  1  A  0.0697  7
 8:  2  B -0.1547  8

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20

以上程序把給定的一組行和列都設置為了NA

setname()

與set()同理,setname()可以修改給定的列名和行名,以下程序是

#把名字為"old"的列,設置為"new"
setnames(DT,"old","new")
#把"V2","V3"列,設置為"V2.rating","V3.DataCamp"
setnames(DT,c("V2","V3"),c("V2.rating","V3.DataCamp"))
setcolorder()

    1
    2
    3
    4
    5

setcolorder()可以用來修改列的順序。

setcolorder(DT,c("V2","V1","V4","V3"))
#這段代碼會使得列的順序變成:

[1] "V2" "V1" "V4" "V3"

    1
    2
    3
    4

舉個栗子:
首先介紹下data.table的語法,如下所示:

這里寫圖片描述

在data.table包中,我們可以使用:=引用來添加或更新列
這里寫圖片描述
這里寫圖片描述

內置的 order() 函數 * 我們可以對一個字符型的列,使用減號“-”,來實現降序排列。

當我們用list()的時候,返回的是data.table,不用list()時,返回的是向量。一般建議加上list(),除非你就是想要得到向量格式的數據。

    select取子集方法之subset(x, subset, select)
    注:subset特指對列的選擇,select特指對行的選擇, with = FALSE 來引用列名

select列

    既然列可以作為變量被引用,我們可以直接引用我們想選取的列。

    既然我們想選取所有的行,則可毋需指定參數 i。

    返回了所有行的 arr_delay 列。

特殊的語法

.SD: data.table提供一個特殊的語法,形式是 .SD。它是 Subset of Data 的縮寫。

它自身就是一個data.table,包含通過by 分組后的每一組。 回憶一下,一個data.table本質上是一個list,它們的列包含的元素個數都相同(其實就是行數)。

說明:

    .SD 包含除了分組依據的那一列以外的所有列。
    返回值依舊保持了原數據的順序。首先打印出來的是 ID=“b” 的數據,然后是 ID=“a” 的,最后是 ID=“c” 的。
    為了對復數的列進行計算,我們可以簡單地使用函數 lapply()。

這里寫圖片描述

說明:

    .SD 分別包含了ID是 a、b、c的所有行,它們分別對應了各自的組。我們應用函數 lapply() 對每列計算平均值。
    每一組返回包含三個平均數的list,這些構成了最終返回的data.table。
    既然函數 lapply() 返回 list,我們就不需要在外面多加 .() 了。
    -如何指定希望計算平均值的列

.SDcols
使用參數 .SDcols。它接受列名或者列索引。比如,.SDcols = c(“arr_delay”, “dep_delay”)能確保.SD之包含 arr_delay 和 dep_delay 這兩列。
和 with = FALSE 一樣,我們也可以使用 - 或者 ! 來移除列。比如,我們指定 !(colA:colB) 或者 -(colA:colB)表示移除從 colA 到 colB 的所有列。

這里寫圖片描述
總結

data.table的語法形式是:

DT[i, j, by]
指定參數i:

    類似於data.frame,我們可以subset行,除非不需要重復地使用 DT$,既然我們能將列當做變量來引用。

    我們可以使用order()排序。為了得到更快速的效果,order()函數內部使用了data.table的快速排序。
    我們可以通過參數i做更多的事,得到更快速的選取和連結。我們可以在教程“Keys and fast binary search based subsets”和“Joins and rolling joins”中學到這些。
    指定參數j:

    以data.table的形式選取列:DT[, .(colA, colB)]。
    以data.frame的形式選取列:DT[, c(“colA”, “colB”), with=FALSE]。
    按列進行計算:DT[, .(sum(colA), mean(colB))]。
    如果需要:DT[, .(sA =sum(colA), mB = mean(colB))]。

    和i共同使用:DT[colA > value, sum(colB)]。
    指定參數by:* 通過by,我們可以指定列,或者列名,甚至表達式,進行分組。參數j可以很靈活地配置參數i和by實現強大的功能。

    by可以指定多個列,也可以指定表達式。
    我們可以用 keyby,對分組的結果自動排序。
    我們可以在參數j中指定 .SD 和 .SDcols,對復數的列進行操作。例如:
    1.把函數fun 應用到所有 .SDcols指定的列上,同時對參數by指定的列進行分組:DT[, lapply(.SD, fun), by=., .SDcols=…]。
    2.返回每組冊前兩行:DT[, head(.SD, 2), by=.]。
    3.三個參數聯合使用:DT[col > val, head(.SD, 1), by=.]

資料參考:

data.table包使用簡介
data.table–cran
R–data.table介紹學習
R–data.table速查手冊
---------------------  



免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM