data.table包主要特色是:设置keys、快速分组和滚得时序的快速合并。data.table主要通过二元检索法大大提高数据操作的效率,同时它也兼容适用于data.frame的向量检索法。

require(data.table)
## Loading required package: data.table

1.创建data.table格式数据

类似于data.frame数据的创建,使用data.table函数

(DF = data.frame(x=c("b","b","b","a","a"), v=rnorm(5)))
##   x       v
## 1 b -0.8870
## 2 b 1.6066
## 3 b -0.1895
## 4 a 0.2375
## 5 a 1.0084
(DT = data.table(x=c("b","b","b","a","a"), v=rnorm(5)))
##    x       v
## 1: b -1.8458
## 2: b -0.2212
## 3: b -0.5812
## 4: a 0.2949
## 5: a 1.7858

可以看出,DF和DT的行号有一些区别,这也是data.frame和data.table主要区别。我们可以利用data.frame创建data.table:

CARS = data.table(cars)
head(CARS)
##    speed dist
## 1: 4 2
## 2: 4 10
## 3: 7 4
## 4: 7 22
## 5: 8 16
## 6: 9 10

现在我们已经创建了两个data.table数据,tables命令可以显示该信息:

tables()
##      NAME NROW MB COLS       KEY
## [1,] CARS 50 1 speed,dist
## [2,] DT 5 1 x,v
## Total: 2MB

其中"MB"列可以快速评估内存使用,发现删除可以释放内存的表格。

如果要查看表中数据类型可以使用

sapply(DT, class)
##           x           v
## "character" "numeric"

2.键Keys

类似人的姓名有“姓”和“名”组成,data.table中的Keys可以由多个部分组成,Keys的组成部分可以使整数、因子、字符串或其他格式,而且data.table中的每行数据是按照Keys排序的,所以data.table数据最多只有一个Key.

DT和CARS是data.table格式,当前没有设置任何Keys,我们可以使用适用于数据框data.frame的语法:

DT[2, ]
##    x       v
## 1: b -0.2212
DT[DT$x=="b", ]
##    x       v
## 1: b -1.8458
## 2: b -0.2212
## 3: b -0.5812

由于DT没有行名称,所以下面的命令不能正常运行:

cat(try(DT["b", ], silent=TRUE))
## Error in `[.data.table`(DT, "b", ) :
## When i is a data.table (or character vector), x must be keyed (i.e. sorted, and, marked as sorted) so data.table knows which columns to join to and take advantage of x being sorted. Call setkey(x,...) first, see ?setkey.

报错信息显示,我们需要对data.table数据设置keys:

setkey(DT, x)
DT
##    x       v
## 1: a 0.2949
## 2: a 1.7858
## 3: b -1.8458
## 4: b -0.2212
## 5: b -0.5812

此时,DT已经按照x值进行了重新排序,如果要确认一个data.table数据是否有keys,我们可以使用haskey()、key()、attributes()或者tables()函数。

tables()
##      NAME NROW MB COLS       KEY
## [1,] CARS 50 1 speed,dist
## [2,] DT 5 1 x,v x
## Total: 2MB

现在,DT数据已经拥有Key:x,我们尝试列出所有x=b的数据

DT["b", ]
##    x       v
## 1: b -1.8458
## 2: b -0.2212
## 3: b -0.5812

使用mult可以筛选出每组数据的第一个观测值和最后一个观测值

DT["b", mult="first"]
##    x      v
## 1: b -1.846
DT["b", mult="last"]
##    x       v
## 1: b -0.5812

下面创建一个足够大的数据来说明“向量检索法”和“二元检索法”的效率差异。

#10000068行,676个分组的数据DF
grpsize = ceiling(1e7/26^2)
tt=system.time( DF <- data.frame(
x=rep(LETTERS,each=26*grpsize),
y=rep(letters,each=grpsize),
v=runif(grpsize*26^2),
stringsAsFactors=FALSE)
)
tt
##    user  system elapsed
## 1.56 0.05 1.60
head(DF, 3)
##   x y       v
## 1 A a 0.08119
## 2 A a 0.64764
## 3 A a 0.80780
tail(DF, 3)
##          x y       v
## 10000066 Z z 0.65856
## 10000067 Z z 0.01941
## 10000068 Z z 0.88818
dim(DF)
## [1] 10000068        3

下面我们从DF中剥离其中任意一组

#'向量检索法'
(tt=system.time(ans1 <- DF[DF$x=="R" & DF$y=="h",]))
##    user  system elapsed
## 2.92 0.14 3.06
head(ans1, 3);dim(ans1)
##         x y       v
## 6642058 R h 0.90416
## 6642059 R h 0.86002
## 6642060 R h 0.02253
## [1] 14793     3
#'二元检索法'
DT = as.data.table(DF)
system.time(setkey(DT,x,y))#一次性遍历所有元素时间
##    user  system elapsed
## 0.26 0.04 0.31
(ss=system.time(ans2 <- DT[J("R","h")]))#二元条件检索
##    user  system elapsed
## 0.01 0.00 0.01
head(ans2, 3);dim(ans2)
##    x y       v
## 1: R h 0.90416
## 2: R h 0.86002
## 3: R h 0.02253
## [1] 14793     3
identical(ans1$v, ans2$v)
## [1] TRUE

可以看出使用二元检索法较向量检索法,效率上要高很多。

当然,data.table也支持向量检索,但这样的话效率会低很多,我们应尽量避免这种情况。例如:

system.time(ans1 <- DT[x=="R" & y=="h",])#低效的data.table用法
##    user  system elapsed
## 2.41 0.08 2.49
system.time(ans2 <- DF[DF$x=="R" & DF$y=="h",])#data.frame用法
##    user  system elapsed
## 4.59 0.20 4.89
mapply(identical,ans1,ans2)
##    x    y    v
## TRUE TRUE TRUE

上例中,当使用DT$x==“R"时候,就会使用”向量检索法“遍历数据的整列,y=="h"同样,最后再使用”&“合并两个条件。data.table包提供了J()函数用于数据合并,可以大大提高效率。

identical( DT[J("R","h"), ], DT[data.table("R","h"), ])
## [1] TRUE

3.快速分组

对于data.table,使用”[i, j]“进行二元检索,我们可以接"by"进行分组计算

DT[, sum(v), by=x]
##     x     V1
## 1: A 192333
## 2: B 192379
## 3: C 192299
## 4: D 192062
## 5: E 192653
## 6: F 192099
## 7: G 192296
## 8: H 192402
## 9: I 192396
## 10: J 192262
## 11: K 192200
## 12: L 192308
## 13: M 192475
## 14: N 192103
## 15: O 192423
## 16: P 192341
## 17: Q 192340
## 18: R 192135
## 19: S 192233
## 20: T 192492
## 21: U 192434
## 22: V 191940
## 23: W 192353
## 24: X 192466
## 25: Y 192206
## 26: Z 192385
## x V1

该种方法相当高效,下面我们将其与tapply函数进行对比

ttt=system.time(tt <- tapply(DT$v,DT$x,sum)); ttt
##    user  system elapsed
## 3.15 0.48 3.67
sss=system.time(ss <- DT[,sum(v),by=x]); sss
##    user  system elapsed
## 0.34 0.00 0.34
head(tt);head(ss)
##      A      B      C      D      E      F
## 192333 192379 192299 192062 192653 192099
##    x     V1
## 1: A 192333
## 2: B 192379
## 3: C 192299
## 4: D 192062
## 5: E 192653
## 6: F 192099
identical(as.vector(tt), ss$V1)
## [1] TRUE

下面我们按两列进行分组,比较两种方法的效率

ttt=system.time(tt <- tapply(DT$v,list(DT$x,DT$y),sum)); ttt
##    user  system elapsed
## 5.64 0.63 6.36
sss=system.time(ss <- DT[,sum(v),by="x,y"]); sss
##    user  system elapsed
## 0.35 0.00 0.34
tt[1:5,1:5]
##      a    b    c    d    e
## A 7507 7417 7360 7383 7399
## B 7449 7453 7405 7374 7384
## C 7412 7388 7375 7442 7388
## D 7430 7387 7418 7338 7433
## E 7387 7464 7440 7434 7464
head(ss)
##    x y   V1
## 1: A a 7507
## 2: A b 7417
## 3: A c 7360
## 4: A d 7383
## 5: A e 7399
## 6: A f 7413
identical(as.vector(t(tt)), ss$V1)
## [1] TRUE

4.其他

关于data.table的更多信息参见:https://github.com/Rdatatable/data.table

----------------------------------------------------------------------------------------

  • 简介 
    data.table继承于data.frame。它提供了一个快速通道,让我们能更加快速的读取文件,对数据进行筛选、分组、排序、联表,而且其语法灵活、简介。由于data.table是一个data.frame所以它几乎兼容所有的函数。

  • 特点

    1. data.table(DT)的操作语句类似于SQL,DT[i, j, by]中的i, j, by 对应着SQL语句的 i=where, j=select, by=group by。所以DT中的i, j并不是只是像data.frame只代表着行列,它更加的灵活多变。
    2. 符号 ” := “快速的增加或者删除列,类似SQL的update。
    3. setkey(DT, colA, colB),可以使得检索和分组更加快速
    4. order,快速多重排序, 例如对DT按照x,y进行排序DT[order(DT$x, -DT$y),]或者DT[with(DT, order(x, -y)),]
  • compare 
    包括使用DT使用Key后与DF的检索速度对比。 
    快速分组(需要设置KEY),进行计算,和使用tapply分组计算速度

###生成数据
grpsize <- ceiling(1e7/26^2) ##10^7 rows, 676 groups
DF <- data.frame(x=rep(LETTERS,each=26*grpsize),
y=rep(letters,each=grpsize), v=runif(grpsize*26^2),
stringsAsFactors=FALSE)
head(DF,3)
x y v
1 A a 0.5310106
2 A a 0.1980941
3 A a 0.8835322 DT <- as.data.table(DF) ##creat data.table
setkey(DT,x,y) #s et the key
##################################################
#比较检索速度,搜索x=="R",y="h"
system.time(ans1 <- DF[DF$x=="R" & DF$y=="h",]) #vector scan
user system elapsed
0.528 0.016 0.544
system.time(ans2 <- DT[list("R","h")]) # binary search
user system elapsed
0.004 0.000 0.001 ####################################################
###快速分组,按照x分组,然后计算sum(v)
#tapply
system.time(tt <- tapply(DT$v,DT$x,sum))
user system elapsed
0.704 0.064 0.767
#syntax of data.table
system.time(ss <- DT[,sum(v),by=x])
user system elapsed
0.080 0.000 0.078
#cheak ss and tt
head(ss)
x V1
1: A 192213.2
2: B 192183.3
3: C 192601.7
4: D 192308.0
5: E 192428.5
6: F 192071.0
head(tt)
A B C D E F
192213.2 192183.3 192601.7 192308.0 192428.5 192071.0
  • 其他基本操作 
    联表和统计计算,更清晰认知,DT[i, j, by]中的i, j, by 对应着SQL语句的 i=where, j=select, by=group by。
###Data preparation
DT = data.table(x=rep(c("a","b","c"),each=3), y=c(1,3,6), v=1:9) ##creat data.table DT
X = data.table(c("b","c"),foo=c(4,2)) ##use to join
setkey(DT,x) #set the key
########################cheak the data#######
DT
x y v
1: a 1 1
2: a 3 2
3: a 6 3
4: b 1 4
5: b 3 5
6: b 6 6
7: c 1 7
8: c 3 8
9: c 6 9 X
V1 foo
1: b 4
2: c 2
#################联表,注key1联的另一个表的第一列#################
##join类型1,联表,X中有b,c
DT[X] ##join X,by the key x.
x y v foo
1: b 1 4 4
2: b 3 5 4
3: b 6 6 4
4: c 1 7 2
5: c 3 8 2
6: c 6 9 2
##join类型2,类似查询,.() 表示list,类似于联一个1行2列的表
DT[.("a",3)]
x y v V2
1: a 1 1 3
2: a 3 2 3
3: a 6 3 3
#############################计算建表#############
#where=DT, select=sum(v)....., group by DT$x
DT[,list(MySum=sum(v),
MyMin=min(v),
MyMax=max(v)),
by=.(x)]
x MySum MyMin MyMax
1: a 6 1 3
2: b 15 4 6
3: c 24 7 9

data.table包简介的更多相关文章

  1. R︱高效数据操作——data.table包(实战心得、dplyr对比、key灵活用法、数据合并)

    每每以为攀得众山小,可.每每又切实来到起点,大牛们,缓缓脚步来俺笔记葩分享一下吧,please~ --------------------------- 由于业务中接触的数据量很大,于是不得不转战开始 ...

  2. R语言数据分析利器data.table包 —— 数据框结构处理精讲

        R语言data.table包是自带包data.frame的升级版,用于数据框格式数据的处理,最大的特点快.包括两个方面,一方面是写的快,代码简洁,只要一行命令就可以完成诸多任务,另一方面是处理 ...

  3. 使用 data.table 包操作数据

    在第一节中,我们回顾了许多用于操作数据框的内置函数.然后,了解了 sqldf 扩展包,它使得简单的数据查询和统计变得更简便.然而,两种方法都有各自的局限性.使用内置函数可能既繁琐又缓慢,而相对于各式各 ...

  4. R语言data.table包fread读取数据

    R语言处理大规模数据速度不算快,通过安装其他包比如data.table可以提升读取处理速度. 案例,分别用read.csv和data.table包的fread函数读取一个1.67万行.230列的表格数 ...

  5. R语言数据分析利器data.table包—数据框结构处理精讲

    R语言数据分析利器data.table包-数据框结构处理精讲 R语言data.table包是自带包data.frame的升级版,用于数据框格式数据的处理,最大的特点快.包括两个方面,一方面是写的快,代 ...

  6. data.table包

    data.table 1.生成一个data.table对象 生成一个data.table对象,记为DT. library(data.table) :],V3=round(rnorm(),),V4=:) ...

  7. data.table包使用应该注意的一些细节

    fread中nThread 参数的使用   注意默认nThread=getDTthreads(),即使用所有能用的核心,但并不是核心用的越多越好,本人亲自测试的情况下,其实单核具有较强的性能,只有在数 ...

  8. R读取大数据data.table包之fread

    >library(data.table)>data=fread("10000000.txt")>Read 9999999 rows and 71 (of 71) ...

  9. R语言学习笔记(十七):data.table包中melt与dcast函数的使用

    melt函数可以将宽数据转化为长数据 dcast函数可以将长数据转化为宽数据 > DT = fread("melt_default.csv") > DT family_ ...

随机推荐

  1. java基础之类与对象2

    这是上一篇文章的源码................ public class Main 是我创建的一个主类 我的基本操作就在这个类里面完成,public static void main(Strin ...

  2. DOM的发展,DOM0,DOM1,DOM2,DOM3

    Documentc Object Model文档对象模型是针对XML但经过扩展用于HTML的应用程序接口(API Application programming Interface).DOM把整个界面 ...

  3. Linux查看网络端口

    简单的总结一下前段时间学习Linux的成果 查看 TCP 22 端口是否打开1.列出所有端口:[root@Demon proc]# netstat -ntlpActive Internet conne ...

  4. Linux - 进程间通信 - 命名管道

    1.命名管道的特点: (1)是管道,可用于非血缘关系的进程间的通信 (2)使用命名管道时,梁金成需要用路径表示通道. (3)命名管道以FIFO的文件形式存储于文件系统中.(FIFO:总是按照先进先出的 ...

  5. CSS浮动专题!

    在css中,浮动问题可能是很多刚入门的小白比较头疼的问题. 1,首先先来介绍一下两种浮动类型:左浮动和右浮动 1) float:left;左浮动,后面的内容会流向对象的右侧 2) float:righ ...

  6. Python 基础 一

    Python 基础  一 一.关于Python的介绍 python的创始人为吉多·范罗苏姆(Guido van Rossum),这一两年在国内很流行,应用很广泛. 二.Python的基础知识(1) 1 ...

  7. bzoj4785 [Zjoi2017]树状数组

    Description 漆黑的晚上,九条可怜躺在床上辗转反侧.难以入眠的她想起了若干年前她的一次悲惨的OI 比赛经历.那是一道基础的树状数组题.给出一个长度为 n 的数组 A,初始值都为 0,接下来进 ...

  8. 做一个常规的banner图——负边距的使用、banner图的拼法

    在这之前,首先要了解如何设置块级元素在块级元素水平居中 方法: 设置子容器为定位元素 水平居中 left:50%:margin-left:-width/2: 垂直居中 top:50%:margin-t ...

  9. add,update,list.jsp源码

    add:<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncod ...

  10. 安卓OKhttp请求封装

    目前安卓开发中使用的网络工具为OKhttp,但是okhttp的使用还不是很方便,在okhttp的基础上再对请求进行封装会极大的方便网络调用. 下面直接上代码. 请求封装 public class Ht ...