data.table基礎知識
#載入航班資訊
#fread 快速檔案閱讀器
#使用data.table 親自建立
#如果列是字元型,則不能轉化成因子型(factor)
#data.table 不能設定和使用行名字。
> library(data.table)
> flights <- fread("flights14.csv")
> flights
> dim(flights)
> DT = data.table(ID = c("b","b","b","a","a","c"), a = 1:6, b = 7:12, c = 13:18)
> DT
ID a b c
1: b 1 7 13
2: b 2 8 14
3: b 3 9 15
4: a 4 10 16
5: a 5 11 17
6: c 6 12 18
> class(DT$ID)
[1] "character"
> as.data.table()
> getOption("datatable.print.nrows")
[1] 100
#data.table 的基本形式,與sql語法作對比,便於理解
> DT[i, j, by]
## R: i j by
## SQL: where select | update group by
#Take DT, subset rows using i, then calculate j, grouped by by.
> ans <- flights[origin == "JFK" & month == 6L]
> dim(ans)
[1] 8422 17
選取行i
> flights[origin == "JFK" & month == 6L, ]#逗號可加可不加,data.frame中則必須要加
> ans <- flights[1:2]
> ans
> ans <- flights[order(origin, -dest)]# -dest 降序
> head(ans)
> odt = data.table(col = sample(1e7))
> t1 <- system.time(ans1 <- odt[base::order(col)]) ## uses order from base R
> t2 <- system.time(ans2 <- odt[order(col)]) ## uses data.table's forder#傳統R自帶包中的order與data.table中的order執行時間作對比
> (identical(ans1, ans2)) #比較兩變數是否相同,相同返回TRUE,否則FALSE
[1] TRUE
#選取列j
> ans <- flights[, arr_delay] #變數格式
> head(ans)
[1] 13 13 9 -26 1 0
> ans <- flights[, list(arr_delay)] #返回data.table格式
> head(ans)
arr_delay
1: 13
2: 13
3: 9
4: -26
5: 1
6: 0
> ans <- flights[, .(arr_delay, dep_delay)] #等同於ans <- flights[, list(arr_delay, dep_delay)]
> head(ans)
arr_delay dep_delay
1: 13 14
2: 13 -3
3: 9 2
4: -26 -8
5: 1 2
6: 0 4
#重新命名
ans <- flights[, .(delay_arr = arr_delay, delay_dep = dep_delay)]
head(ans)
#關於j的計算
ans <- flights[, sum((arr_delay + dep_delay) < 0)]#[1] 141814 得到一個值 ,計算兩列數值相加小於0的個案個數
ans <- flights[, .((arr_delay + dep_delay) < 0)]
table(ans)
#計算6月份以“JFK”為原產地機場的所有航班的平均到達和離開延誤時間
ans <- flights[origin == "JFK" & month == 6L,.(m_arr = mean(arr_delay), m_dep = mean(dep_delay))] # 為什麼month == 6L
ans
# m_arr m_dep
# 1: 5.839349 9.807884
#data.frame 的操作方式
flights_test<-as.data.frame(flights)
ansx<-apply(flights_test[which(origin %in% "JFK" & month %in% 6),c(5,7)],2,mean)
ansx
#dep_delay arr_delay
#9.807884 5.839349
#在6月份的“JFK”機場2014年有多少次旅行?
ans <- flights[origin == "JFK" & month == 6L, length(dest)] #同下
ans
# [1] 8422
ans <- flights[origin == "JFK" & month == 6L, .N] #.N返回查詢的子集的行數
ans
# [1] 8422
nrow(flights[origin == "JFK" & month == 6L])#同上 低效
按名稱引用列
#設定with = FALSE禁止引用列的功能,就像它們是變數一樣,從而恢復“ data.frame模式”
ans <- flights[, c("arr_delay", "dep_delay"),with = FALSE]
head(ans)
ans <- flights[, !c("arr_delay", "dep_delay"), with = FALSE]#取消列的選擇
ans <- flights[, -c("arr_delay", "dep_delay"), with = FALSE]#取消列的選擇
#通過指定開始和結束列名year:day來選擇
ans<-flights[,year: day,with = FALSE]
ans<-flights[,!(year: day),with = FALSE]
ans<-flights[,-(year: day),with = FALSE]
使用分組
ans <- flights[, .(.N), by = .(origin)]
ans
#origin N
#1: JFK 81483
#2: LGA 84433
#3: EWR 87400
#同上 ans<-flights[,.(.N),by="origin"]
#如果只有一列或表示式來引用j和by,我們可以刪除.()符號。
ans <- flights[, list(.N), by = list(origin)]
ans <- flights[, .N, by = origin]
#如何計算每個起運機場的航空公司程式碼為“AA”的旅行次數?
ans <- flights[carrier == "AA", .N, by = origin]
ans
#怎樣才能得到每origin, dest對貨運程式碼為“AA”的旅行總次數?
ans <- flights[carrier == "AA", .N, by = .(origin,dest)]
#orig,dest運營商程式碼“AA”每月如何得到每對貨物的平均到達和離開延遲?
ans <- flights[carrier == "AA",
.(mean(arr_delay), mean(dep_delay)),
by = .(origin, dest, month)] #月份排序
ans <- flights[carrier == "AA",
.(mean(arr_delay), mean(dep_delay)),
keyby = .(origin, dest, month)] #月份排序
ans
#對origin升序,dest降序,對結果進行重排列
ans <- flights[carrier == "AA", .N, by = .(origin, dest)][order(origin, -dest)]
連結[chain]
如:
ans <- flights[carrier == "AA", .N, by = .(origin, dest)][order(origin, -dest)]
head(ans, 10)
可以一直鏈接下去,形式如:DT[ ... ][ ... ][ ... ]
或者進行垂直鏈接:
DT[ ...
][ ...
][ ...
]
by中的表示式
by也可以接受表示式或列,如想知道哪一個航班起步較晚,但是提前達到,可以寫成:
ans <- flights[, .N, .(dep_delay>0, arr_delay>0)]
ans
dep_delay arr_delay N
1: TRUE TRUE 72836
2: FALSE TRUE 34583
3: FALSE FALSE 119304
4: TRUE FALSE 26593
最後一行對應於dep_delay > 0 = TRUE和arr_delay > 0 = FALSE。我們可以看到,26593班航班起步晚,但提早(或按時)到達。
j 中含有多列--.SD
> DT
ID a b c
1: b 1 7 13
2: b 2 8 14
3: b 3 9 15
4: a 4 10 16
5: a 5 11 17
6: c 6 12 18
> DT[,print(.SD),by=ID]
a b c
1: 1 7 13
2: 2 8 14
3: 3 9 15
a b c
1: 4 10 16
2: 5 11 17
a b c
1: 6 12 18
Empty data.table (0 rows) of 1 col: ID
.SD包含出分組以外的所有的列。可以用apply進行計算。
> DT[,lapply(.SD,mean),by=ID]
ID a b c
1: b 2.0 8.0 14.0
2: a 4.5 10.5 16.5
3: c 6.0 12.0 18.0
因為apply()返回的就是列表格式,因此不需要再使用 “.()”.
指定想要計算的列的均值mean
使用引數 .SDcols()
flights[carrier == "AA", ## Only on trips with carrier "AA"
lapply(.SD, mean), ## compute the mean
by = .(origin, dest, month), ## for every 'origin,dest,month'
.SDcols = c("arr_delay", "dep_delay")] ## for just those specified in .SDcols
origin dest month arr_delay dep_delay
1: JFK LAX 1 6.590361 14.2289157
2: LGA PBI 1 -7.758621 0.3103448
3: EWR LAX 1 1.366667 7.5000000
4: JFK MIA 1 15.720670 18.7430168
5: JFK SEA 1 14.357143 30.7500000
---
196: LGA MIA 10 -6.251799 -1.4208633
197: JFK MIA 10 -1.880184 6.6774194
198: EWR PHX 10 -3.032258 -4.2903226
199: JFK MCO 10 -10.048387 -1.6129032
200: JFK DCA 10 16.483871 15.5161290
.SD 每個組的子集
> ans <- flights[, head(.SD, 2), by = month]
> ans
提取每個月的前兩個的子集
1
1
2
2
3
3
保持j的靈活性
DT[,.(val=c(a,b)),by=ID]
ID val
1: b 1
2: b 2
3: b 3
4: b 7
5: b 8
6: b 9
7: a 4
8: a 5
9: a 10
10: a 11
11: c 6
12: c 12
DT[,.(val=list(c(a,b))),by=ID]
ID val
1: b 1,2,3,7,8,9
2: a 4, 5,10,11
3: c 6,12
總結
data.table 的語法形式是:data.table[i,j,by]
使用i:
1.可以採用與資料框類似的提取子集的方式
2.使用order對data.table進行排序
使用j:
1.選擇列的data.table 方式:DT[,.(colA,colB)]
2.選擇data.frame的方式:DT[,c("colA","colB"),with = FALSE]
3.在列上計算:DT[,.(sum(colA),mean(colB))]
4.如有必要提供列名:DT[,.(sA=sum(colA),mB=mean(colB))]
5.結合i:DT[colA > value,sum(colB)]
使用by:
1. `DT[, lapply(.SD, fun), by = ..., .SDcols = ...]
--對SDcols中選擇的所有列進行函式fun計算,通過by分組進行分組計算
2. `DT[, head(.SD, 2), by = ...] --返回每組的前兩行資料
3. `DT[col > val, head(.SD, 1), by = ...]`
---先選擇滿足col > val的行,然後通過by進行分組,最後提取每組中的第一行資料。