当你的数据集有百万条,或600MB以上时,你需要data.table包协助,加速你的操作,data.table是data.frame的加强版。
读取文件,忘记read.csv, 使用fread吧,速度快,还有进度提醒。
提取某些行的数据,忘记vector scan, 使用binary search吧,速度快。
df[df$x == "R" & df$y == "h", ])
# vector scan
dt = as.data.table(df)
setkey(dt, x, y)
# binary search
dt[list("R", "h')]
#or binary search
dt[.("R", "h')]
简单版本:
dt[, sum(v), by = x]
#或者
dt[, sum(v), by = "x, y"]
# x V1
# 1: A 192214
# 2: B 192183
复杂版本:
DT = as.data.table(iris)
whatToRun = quote( .(AvgWidth = mean(Sepal.Width),
MaxLength = max(Sepal.Length)) )
DT[, eval_r(whatToRun), by=.(FirstLetter=substring(Species,1,1))]
# FirstLetter AvgWidth MaxLength
# 1: s 3.428 5.8
# 2: v 2.872 7.9
进阶版本:
DT[x>1000, sum(y*z), by=w]
DT[, region]
#或者
DT[, "region", with = FALSE] 或者DT[["region"]]
# 取多个列
DT[, c(1, 4, 10), with = FALSE]
DT[, region] #返回一个向量
DT[, .(region)] #返回一个 data.table
These queries can be chained together just by adding another one on the end:
DT[...][...]
# sum(v) by colA then return the 6 largest which are under 300
DT[, sum(v), by = colA] [V1<300] [tail(order(V1))]
DT[, V1 := round(exp(V1),2)]
DT[, c("V1","V2") := list(round(exp(V1),2), LETTERS[4:6])]
#or
DT[, ':=' (V1 =round(exp(V1),2),V2 = LETTERS[4:6])][]
DT[, V1 := NULL] # 移除一列
DT[, c("V1","V2") := NULL] # 移除多列
Cols.chosen = c("V1","V2")
DT[, Cols.chosen := NULL]
#无显式的返回结果,列名为Cols.chosen的列将会被删除
#删除指定变量Cols.chosen包含的V1列和V2列
DT[, (Cols.chosen) := NULL]
.N
.N可以用来表示行的数量或者最后一行
# 在i处使用:
DT[.N-1]
# V1 V2 V3 V4
# 1: 1 B -0.5765 11
# 返回每一列的倒数第二行
# 在j处使用:
DT[,.N-1]
# [1] 11
# 返回倒数第二行所在的行数。
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
.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
以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
以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
.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也可以是一个函数的返回值:
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
结果与上一个是相同的。
使用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"
参考
推荐一个学习data.table的资源
再推荐一本关于R的新书
备注:转移自新浪博客,截至2021年11月,原阅读数34,评论0个。