• data.table包简介


    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
    ---------------------------------------------------------------------------------- 数据和特征决定了效果上限,模型和算法决定了逼近这个上限的程度 ----------------------------------------------------------------------------------
  • 相关阅读:
    Mac下好玩的终端命令
    【bzoj3441】乌鸦喝水
    LeetCode[39]: 组合总和
    打击盗版,支持原创
    状态模式(State)-设计模式
    webpack核心概念
    吴裕雄--天生自然TensorFlow高层封装:Estimator-自定义模型
    吴裕雄--天生自然TensorFlow高层封装:Estimator-DNNClassifier
    吴裕雄--天生自然TensorFlow高层封装:Keras-TensorFlow API
    吴裕雄--天生自然TensorFlow高层封装:Keras-多输入输出
  • 原文地址:https://www.cnblogs.com/payton/p/5363774.html
Copyright © 2020-2023  润新知