利用data.table進行數據分析

利用data.table進行數據分析

DataCamp課程的官方速查表(本篇內容由我跟小夥伴一年前翻譯,最開始掛在雪晴數據網上)python

原文連接:data-table-data-manipulation-r-tutorial

我的認爲R中最應該學習的一個R包就是data.table了,本人16年參加一些數據挖掘比賽,數據量較大,開始學習data.table來進行快速數據清洗,這邊的快速有2方面:git

  • data.table的運行速度快
  • data.table代碼簡短,寫起來快
dt[i,j,by] #一行代碼解決全部

能夠說data.table是R數據處理的極限了(不喜勿噴),運行速度也快於pythonpandas
下面將我看到的一些關於data.table的中文翻譯文章給出連接,包括當時我本身翻譯的文章,方便你們查詢,也方便我本身查詢。github

  1. data.table cheat sheet 看了這篇能夠快速入門了
  2. data.table Vignettes當時也想翻譯,後來發現網上已經有了,裏面一共包含5篇文章
  3. 知乎網友整理裏面共3篇
  4. data.table的前世此生1,
    data.table的前世此生2 來自大貓的翻譯,推薦下大貓的公衆號r-damao,裏面不少data.table的精彩內容

以上共9篇關於data.table的文章以及大貓的微信公衆號中的一些文章,都是中文翻譯好的,都看完就基本入門了.spring

介紹

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


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

1.生成一個data.table對象

生成一個data.table對象,記爲DT.函數

> library(data.table)
> set.seed(45L)
> DT <- data.table(V1=c(1L,2L),
+ V2=LETTERS[1:3],
+ V3=round(rnorm(4),4),
+ V4=1:12)
> DT
     V1 V2      V3 V4
 1:  1  A  0.3408  1
 2:  2  B -0.7033  2
 3:  1  C -0.3795  3
 4:  2  A -0.7460  4
 5:  1  B  0.3408  5
 6:  2  C -0.7033  6
 7:  1  A -0.3795  7
 8:  2  B -0.7460  8
 9:  1  C  0.3408  9
10:  2  A -0.7033 10
11:  1  B -0.3795 11
12:  2  C -0.7460 12

2.經過i來篩選數據集的行

經過數字來篩選數據集的行

選取第三行到第五行學習

> DT[3:5,] #or DT[3:5]
    V1 V2      V3 V4
1:  1  C -0.3795  3
2:  2  A -0.7460  4
3:  1  B  0.3408  5

基於使用快速自動索引條件,使用列名選擇行i

在V2這一列,選擇全部值爲A的行翻譯

> DT[ V2 == "A"]
    V1 V2      V3 V4
1:  1  A  0.3408  1
2:  2  A -0.7460  4
3:  1  A -0.3795  7
4:  2  A -0.7033 10

選擇多個值:

選擇在這一列中包含value1或value2的全部值code

> DT[column %in% c("value1","value2")]

選擇V2這列中包含值A或C的全部行

> DT[ V2 %in% c("A","C")]
    V1 V2      V3 V4
1:  1  A  0.3408  1
2:  1  C -0.3795  3
3:  2  A -0.7460  4
4:  2  C -0.7033  6
5:  1  A -0.3795  7
6:  1  C  0.3408  9
7:  2  A -0.7033 10
8:  2  C -0.7460 12

3.經過j來操做列

經過j來選擇一列

> DT[,V2]
[1] "A" "B" "C" "A" "B" "C" "A" "B" "C" "A" "B" "C"

注意到V2這一列是以向量的形式返回的

經過j來選擇多列

> DT[,.(V2,V3)]
     V2      V3
 1:  A  0.3408
 2:  B -0.7033
 3:  C -0.3795
 4:  A -0.7460
 5:  B  0.3408
 6:  C -0.7033
 7:  A -0.3795
 8:  B -0.7460
 9:  C  0.3408
10:  A -0.7033
11:  B -0.3795
12:  C -0.7460

V2與V3這兩列以data.table的形式返回

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

在j上調用函數

> DT[,sum(V1)]
[1] 18

以向量的形式返回V1列中全部元素的總和

在多列上進行計算

以data.table的形式,返回V1這列的全部元素之和與V3這列的標準差

> DT[,.(sum(V1),sd(V3))]
   V1        V2
1: 18 0.4546055

指定計算列的列名

相似上例,但有一個新的列名

> DT[,.(Aggregate = sum(V1), Sd.V3 = sd(V3))]
   Aggregate     Sd.V3
1:        18 0.4546055

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

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

> DT[,.(V1, Sd.V3 = sd(V3))]
 V1     Sd.V3
 1:  1 0.4546055
 2:  2 0.4546055
 3:  1 0.4546055
 4:  2 0.4546055
 5:  2 0.4546055
 6:  1 0.4546055
 7:  2 0.4546055
 8:  1 0.4546055
 9:  1 0.4546055
10:  2 0.4546055
11:  1 0.4546055
12:  2 0.4546055

多個表達式能夠包裹在花括號中

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

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

4.根據分組來操做j

根據分組來操做j

對V1中的每一類來計算V4列的和

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

經過使用.()控制多個列來操做j

與上例相似,但每個分組包含V1和V2兩列

> DT[,.(V4.Sum = sum(V4)),by=.(V1,V2)]
   V1 V2 V4.Sum
1:  1  A      8
2:  2  B     10
3:  1  C     12
4:  2  A     14
5:  1  B     16
6:  2  C     18

在by中調用函數

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

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

經過指定i行子集的分組進行操做

在前5行數據集中,經過V1列的分組來計算V4列的總和:

> DT[1:5,.(V4.Sum = sum(V4)),by=V1]
     V1 V4.Sum
1:  1      9
2:  2      6

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

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

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

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

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

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

> DT[, V1 := round(exp(V1),2)]

這段代碼沒有顯式的返回結果,而V1列從[1] 1 2 1 2 … 變成了 [1] 2.72 7.39 2.72 7.39 …

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

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

> DT[, c("V1","V2") := list(round(exp(V1),2), LETTERS[4:6])]

一樣沒有顯式的返回結果,V1列的結果與上相同,V2列從[1] "A" "B" "C" "A" "B" "C" … 變成: [1] "D" "E" "F" "D" "E" "F" …

使用函數:=

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

> DT[, ':=' (V1 =round(exp(V1),2),V2 = LETTERS[4:6])][]

與上例變化相同,可是因爲在語句最後添加了[],這一結果會返回至屏幕

經過使用:=來移除一列

移除V1列

> DT[, V1 := NULL]

無顯式的返回結果,但V1列變爲NULL

經過使用:=來移除多列

移除V1列與V2列

> DT[, c("V1","V2") := NULL]

無顯式的返回結果,但V1列與V2列變爲NULL

將一個包含列名的變量用小括號包裹起來,變量所傳遞的內容將會被刪除
注意:列名爲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##索引與鍵值

使用setkey()函數設置鍵值

(注意:因爲上面進行了更新操做,此處須要從新運行文章最開始的代碼,生成DT)

library(data.table)
set.seed(45L)
DT <- data.table(V1=c(1L,2L),
                 V2=LETTERS[1:3],
                 V3=round(rnorm(4),4),
                 V4=1:12)

setkey()函數能夠在數據集DT上設置鍵值。當咱們設置好key後,data.table會將數據按照key來排序。
在V2列上設置一個鍵值

> setkey(DT,V2)

無顯示返回結果

使用鍵值來選擇行

使用鍵值能夠更加有效地選擇行
因爲已將V2設置了鍵值,將會返回該列中全部包含變量值A的行

> DT["A"]
   V1 V2      V3 V4
1:  1  A  0.3408  1
2:  2  A -0.7460  4
3:  1  A -0.3795  7
4:  2  A -0.7033 10

返回鍵值所在列(V2列)包含變量值A或變量值C的全部行

> DT[c("A","C")]
   V1 V2      V3 V4
1:  1  A  0.3408  1
2:  2  A -0.7460  4
3:  1  A -0.3795  7
4:  2  A -0.7033 10
5:  1  C -0.3795  3
6:  2  C -0.7033  6
7:  1  C  0.3408  9
8:  2  C -0.7460 12

mult參數

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

> DT["A", mult ="first"]
    V1 V2    V3 V4
1:  1  A 0.3408  1

返回匹配到鍵值所在列(V2列)全部行中的最後一行

> DT["A", mult = "last"]
   V1 V2      V3 V4
1:  2  A -0.7033 10

nomatch參數

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

> DT[c("A","D")]
    V1 V2      V3 V4
1:  1  A  0.3408  1
2:  2  A -0.7460  4
3:  1  A -0.3795  7
4:  2  A -0.7033 10
5: NA  D      NA NA

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

> DT[c("A","D"), nomatch = 0]
   V1 V2      V3 V4
1:  1  A  0.3408  1
2:  2  A -0.7460  4
3:  1  A -0.3795  7
4:  2  A -0.7033 10

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

by=.EACHI參數

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

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

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

> DT[c("A","C"),sum(V4), by=.EACHI]
  V2 V1
1: A 22
2: C 30

使用setkey()設置主鍵

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

> setkey(DT,V1,V2)

無顯式返回結果

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

> DT[.(2,"C")]
  V1 V2      V3 V4
1:  2  C -0.7033  6
2:  2  C -0.7460 12

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

> DT[.(2,c("A","C"))]
    V1 V2      V3 V4
1:  2  A -0.7460  4
2:  2  A -0.7033 10
3:  2  C -0.7033  6
4:  2  C -0.7460 12

6.data.table高級操做

.N

.N能夠用來表示行的數量或者最後一行

在i處使用:

> DT[.N-1]
   V1 V2      V3 V4
1:  2  C -0.7033  6

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

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

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

.()

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

在j中使用:

> DT[,.(V2,V3)] #or DT[,list(V2,V3)]
   V2      V3
 1:  A  0.3408
 2:  B -0.7033
 3:  C -0.3795
 4:  A -0.7460
 5:  B  0.3408
 6:  C -0.7033
 7:  A -0.3795
 8:  B -0.7460
 9:  C  0.3408
10:  A -0.7033
11:  B -0.3795
12:  C -0.7460

在by中使用:

> DT[, mean(V3),by=.(V1,V2)]
   V1 V2       V1
1:  1  A -0.01935
2:  2  B -0.72465
3:  1  C -0.01935
4:  2  A -0.72465
5:  1  B -0.01935
6:  2  C -0.72465

以V1,V2爲分組,對V3求均值

.SD參數

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

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

以V2爲分組,選擇每組的第一和最後一列:

> DT[,.SD[c(1,.N)], by=V2]
   V2 V1      V3 V4
1:  A  1  0.3408  1
2:  A  2 -0.7033 10
3:  B  2 -0.7033  2
4:  B  1 -0.3795 11
5:  C  1 -0.3795  3
6:  C  2 -0.7460 12

以V2爲分組,計算.SD中全部元素的和:

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

.SDcols

.SDcols常於.SD用在一塊兒,他能夠指定.SD中所包含的列,也就是對.SD取子集:

> DT[, lapply(.SD,sum), by=V2,.SDcols = c("V3","V4")]
   V2     V3 V4
1:  A -1.488 22
2:  B -1.488 26
3:  C -1.488 30

.SDcols也能夠是一個函數的返回值:

> DT[, lapply(.SD,sum), by=V2,.SDcols = paste0("V",3:4)]
   V2     V3 V4
1:  A -1.488 22
2:  B -1.488 26
3:  C -1.488 30

結果與上一個是相同的。

7.串聯操做能夠把表達式聚合在一塊兒並避免多餘的中間變量

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

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

這個是不使用串聯的方法,先以V1爲分組,對V4求和,而後再把分組總和大於35的取出來。
使用串聯的方法:

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

分組求和以後對V1進行排序:

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

8.使用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

以上程序把給定的一組行和列都設置爲了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()

setcolorder()能夠用來修改列的順序。

setcolorder(DT,c("V2","V1","V4","V3"))

這段代碼會使得列的順序變成:

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

取各分組中機率最大的那個樣本的某字段

dt[order(-prob),字段[1],.(分組)]
dt[order(-label_prob),.(shop_id_yc = shop_id[1]),.(row_id)]
或者
dt[,.SD[which.max(label_prob)],.(row_id)]
或者
setorder(dt, -x)[, head(.SD, 5), .(row_id)] #setorder 稍快於order

選擇group列中的第一行數據

dt[!duplicated(dt$id),]
相關文章
相關標籤/搜索