data.table简介
关于R中的数据处理,我们接着介绍data.table
包。上期我们介绍的dplyr
有类似于sql的一套数据处理的语法,而data.table
则有着它自己的一套语法,它能处理几乎所有dplyr
可以处理的数据,而且代码量更少,效率更高,特别是在处理大至GB级别的数据时,它比dplyr
以及python的pandas
处理数据都要快。参见https://github.com/Rdatatable/data.table/wiki/Benchmarks-%3A-Grouping。
示例数据
我们继续沿用dplyr
中使用到的示例数据集pgdat
,这样可以方便做对比,如果你想要获取该数据集的源代码,可以通过点击微信公众号学习课堂中的案例数据
得到。
pgdat <- as.data.table(pgdat)
pgdat
1. 基本概念
a) data.table是什么?
我们知道R中的数据框data.frame,而data.table可以看做是一个增强版的data.frame。创建一个data.table对象可以使用fread
函数以读入文件的形式生成,也可以直接采用data.table
函数生成。
DT = data.tableID c("b","a",68);">"c"),
? ? ? ? ? ? ? ?a = 1:6,b 712,0);">c=1318DT
classDT$ID)
用as.data.table
可以将data.frame转化为data.table。
data.table与data.frame的区别:
与data.frames不同,在生成data.table的时候character
类型的数据绝对不会默认地转换成factors
类型,这样的好处就是你不用再在语句中每次都添加stringsAsFactors = FALSE了;
打印数据时在行号后面加了一个冒号:
用以区分行号与第一列数据;
当数据行数超过options()
参数设置datatable.print.nrows
的值时,仅仅只会打印该数据集的前5行以及最后5行的数据;
getOption"datatable.print.nrows"# [1] 100
b)?一般形式
为了让大家快速理解data.table语法的一般形式,先看看如下说明:
DT[i,0);">j,0);">by]
看看上述描述,如果你了解sql语言,可能你就能很快明白data.table的语法。对于一个数据集DT
,用i
对数据的行数进行筛选,用j
对数据的列进行筛选以及计算,用by
来指定数据如何进行分组。接下来我们就来看看如何利用i
和j
对数据进行处理。
c) 用i
筛选行数
# 筛选出得分大于40并且助攻数大于7次的数据
ans pts > 40 & ast >= 8]headans# ? ?rk player wl ? ? ? ? ? match gs min ? fgp fgm fga ? ?p3p p3m p3a ? ?ftp
– 提取pgdat
的前两行数据
[2ans
– 排序
我们可以直接用R里自带的函数order
来完成排序。
# 把数据首先按得分降序排列,然后再按助攻数升序排列
order(-pts,0);">ast)# ? ?rk player wl ? ? ? ? ? ? match gs min ? fgp fgm fga ? p3p p3m p3a
在使用order
进行排序时,默认是升序排列,如果需要降序排列,可以在列名前加上-
。
值得一提的是,在data.table里面用到的order实际上经过内部优化过了,它比R自带的order
实际上要快不少,看如下例子:
# Win7 32 odt col=sample(1e7## uses order from base R
t1 system.timeans1 odtbase::col]) ?
t2 ans2 ) ? ? ? ?
identicalans1,0);">ans2# [1] TRUE
上述测试在win7的32位系统下进行,内存大小为4GB,R采用的3.2.1版本,我们可以看到加速了~15倍。
d) 用j
选择列
– 选择pts
列,返回向量
[,0);">pts]
# [1] 46 37 17 27 21 39
– 选择data.table
list# ? ?pts
– 选择pts
和ast
两列数据
# ? ?pts ast
– 选择ast
两列数据并且将它们重命名为points
和assists
points assists # ? ?points assists
e) 用j
来计算
– 计算直接得分和间接得分之和
# 间接得分简单记为助攻数*2
player,0);">tpts + 2*# ? ? ?player tpts
f) 用i
筛选数据并且用j
做一些计算
– 计算库里的场均得分和助攻数
player == "库里",? ? ? ? ? ? ? .m_ptsmeanm_ast# ? ? ? m_pts ? ?m_ast
– 计算得分大于等于20分并且助攻数大于等于10个的两双的总场次
20 10,0);">length# [1] 87
length
用来计算数据的长度,这里的列名实际上选取任意一列都可以,data.table提供了一个相同功能的函数.N
来实现,用来表示数据的行数。于是上述代码可以有以下等价表述方式:
.N# [1] 87
g) 用j
通过字符串的变量名来选择数据列
使用参数with = FALSE
– 跟data.frame相同的方式选择"pts",68);">"ast"with=FALSE# 6: ?39 ? 7
2. 数据整合
介绍完了i
和j
的用法,接下来介绍如何用by
来实现分组数据计算。
a) 用by
分组
– 计算不同球员的参赛场次
by=.player# ? ?player ?N
– 计算不同球员助攻大于等于8次的参赛场次
8,0);">.N,136); font-style: italic;"># 1: ? 库里 30
– 计算不同球员在不同胜负关系下助攻大于等于8次的参赛场次
wl# ? ? player wl ?N
– 计算不同球员在不同胜负关系下场均得分与助攻数
## j设置参数名
# ? ? player wl ? ? ? V1 ? ? ? ?V2
mpts mast # ? ? player wl ? ? mpts ? ? ?mast
b) keyby
如果在分组数据计算后,想要对分组数据进行排序,这时便可用到keyby
参数。
– 计算不同球员在不同胜负关系下场均得分与助攻数,并按球员和胜负关系进行排序
keyby# ?1: ? 保罗 胜 18.98000 10.240000
c) 管道操作
data.table
中也有类似dplyr
中%>%
功能的函数,下面我们来看看这个功能的好处:
# 按球员分组求出场均得分和助攻,再按得分降序排列
mptsmastby = .mpts# ? ?player ? ? mpts ? ? ?mast
# 使用管道操作
# 6: ? 康利 15.30357 ?6.107143
可以看出,data.table
中的管道操作是按照DT[ ... ][ ... ][ ... ]
的形式进行操作的。
e) 用.SD
同时对多列进行相同计算
– 计算每一个球员的场均数据
# 提取球员,得分,助攻,抢断,失误数据列
ast,0);">stl,0);">tov# 按球员分组计算其他所有数据列的均值
lapply.SD,136); font-style: italic;"># ? ?player ? ? ?pts ? ? ? ast ? ? ?stl ? ? ?tov
采用.SD
会对除分组数据外所有的数据列做处理,而实际处理数据的时候,往往是需要指定其中多列数据进行处理,并不是全部数据列,这时候就需要配合.SDcols
参数进行操作。例子如下:
# 按球员分组仅计算得分和助攻数据的均值
.SDcols]
– 取每个球员前两场的数据
# ? ? player pts ast
– 把每个球员的得分和助攻数连起来作为一个变量
# 新变量为一列
val # ? ? ?player val
# ? ?player ? ? ? ? ? ? ? ?val
小结
data.table的一般语法形式如下:
]
i
选择行:
按条件筛选行数据:DT[colA > value1 & colB < value2]
排序:DT[order(colA,-colB)]
j
选择列和计算:
选择数据列:?DT[,.(colA,colB)]
?或者?.
计算:?.
配合i
一起使用:?DT[colA > value,sum(colB)]
.
by
数据分组:
分组计算汇总:
配合i
、j
一起使用:DT[col > val,by=.]
至此,data.table
的基本函数功能就介绍完了。 最后在这里说说自己使用data.table
以及dplyr
进行数据处理的区别感受,在使用dplyr
进行数据处理时的处理逻辑层次比较清晰,毕竟类似sql的操作习惯比较容易接受,其代码整体可读性更好;而用data.table
的时候,代码量更少,处理速度更快。总体来说,在处理小数据的时候更倾向于使用dplyr
,在处理数据量比较大的情形时,更倾向于使用data.table
,当然这最终看你个人的使用习惯。
data.table
还有一些其它的功能,比如表关联操作,快速读写文件的函数fread
以及fwrite
等等,更多功能就留给大家自己去探索吧。
?本文来自№→★飞刀的微信公共帐号“数据挖掘与R语言”,用微信添加数据挖掘与R语言公众号,即可订阅。转载必须保留作者、公共帐号信息。
长按识别图中二维码?
