zoukankan      html  css  js  c++  java
  • data.table包使用总结

    装载

    作者:kicilove  
    来源:CSDN  
    原文:https://blog.csdn.net/kicilove/article/details/76060980?utm_source=copy 

    data.table包使用总结

    R中的data.table包提供了一个data.frame的高级版本,让你的程序做数据整型的运算速度大大的增加。data.table已经在金融,基因工程学等领域大放光彩。他尤其适合那些需要处理大型数据集(比如 1GB 到100GB)需要在内存中处理数据的人。不过这个包的一些符号并不是很容易掌握,因为这些操作方式在R中比较少见。这也是这篇文章的目的,为了给大家提供一个速查的手册。

        data.table的通用格式: DT[i, j, by],对于数据集DT,选取子集行i,通过by分组计算j

    1.首先下载安装data.table包

    install.packages("data.table")
    library(data.table)

        1
        2

    利用fread函数导入数据,在data.table包支持使用fread函数从本地或者web上导入数据,功能相当于base包的read.csv。

    mydata = fread("https://github.com/arunsrinivasan/satrdays-workshop/raw/master/flights_2014.csv")

        1

    2.数据简单描述

    nrow(mydata)
    [1] 253316

    ncol(mydata)
    [1] 17

    names(mydata)
    [1] "year"      "month"     "day"       "dep_time"  "dep_delay" "arr_time"  "arr_delay"
    [8] "cancelled" "carrier"   "tailnum"   "flight"    "origin"    "dest"      "air_time"
    [15] "distance"  "hour"      "min"

    head(mydata[,c(2:6)])
       month day dep_time dep_delay arr_time
    1:     1   1      914        14     1238
    2:     1   1     1157        -3     1523
    3:     1   1     1902         2     2224
    4:     1   1      722        -8     1014
    5:     1   1     1347         2     1706
    6:     1   1     1824         4     2145

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19

    3.选择或保留某几列

    .()为list()的一个别名。如果使用.(),返回的为一个data.table对象。如果不使用.(),结果为返回一个向量。

    如果要选择carrier列,那么可以选择如下几种方式实现:

    dat1 = mydata[ , carrier] # 返回一组向量

    dat1 = mydata[ , .(carrier)] #返回一个data.table

    dat1 = mydata[, c("carrier"), with=FALSE] #返回一组数据框

        1
        2
        3
        4
        5

    根据列的位置保留某几列,比如选择第二列:

    dat2 =mydata[, 2, with=FALSE]

        1

    保留多列:

    dat3 = mydata[, .(origin, year, month, hour)]

        1

    根据列的位置保留多列:

    dat3 = mydata[, .(origin, year, month, hour)]

        1

    删去列:利用!符号删除某列

    dat5 = mydata[, !c("origin"), with=FALSE]

        1

    删去多列

    dat6 = mydata[, !c("origin", "year", "month"), with=FALSE]

        1

    利用%like% 命令进行模糊匹配:

    dat7 = mydata[,names(mydata) %like% "dep", with=FALSE]

        1

    4.对变量进行重命名

    可以利用setnames()函数对变量进行重命名操作:

    setnames(mydata, c("dest"), c("Destination"))

        1

    对多个变量进行重命名:

    setnames(mydata, c("dest","origin"), c("Destination", "origin.of.flight"))

        1

    5.子集的筛选与过滤

    假设要找到origin为‘JFK’的所有子集:

    dat8 = mydata[origin == "JFK"]

        1

    按多个条件选择

    dat9 = mydata[origin %in% c("JFK", "LGA")]

    dat11 = mydata[origin == "JFK" & carrier == "AA"]

        1
        2
        3

    6.利用索引提升数据操作效率

    使用setkey()函数设置键值
    setkey()函数可以在数据集mydata上设置键值。当我们设置好key后,data.table会将数据按照key来排序。
    利用setkey函数将origin设置为mydata的索引:

    setkey(mydata, origin)

        1

    当设置好索引后,可直接利用索引的值进行过滤查找

    data12 = mydata[c("JFK", "LGA")]

        1

    来看看用了索引与没用索引的搜索效率:

    system.time(mydata[origin %in% c("JFK", "LGA")])
    system.time(mydata[c("JFK", "LGA")])

        1
        2

    对多个变量设置索引

    setkey(mydata, origin, dest)
    mydata[.("JFK", "MIA")]

        1
        2

    这等同于:

    mydata[origin == "JFK" & dest == "MIA"]

        1

    重要参数

    mult参数

    mult参数是用来控制i匹配到的哪一行的返回结果默认情况下会返回该分组的所有元素
    返回匹配到键值所在列(V2列)所有行中的第一行

     DT["A", mult ="first"]

        1

    返回匹配到键值所在列(V2列)所有行中的最后一行

     DT["A", mult = "last"]

        1

    nomatch参数

    nomatch参数用于控制,当在i中没有到匹配数据的返回结果,默认为NA,也能设定为0。0意味着对于没有匹配到的行将不会返回。
    返回匹配到键值所在列(V2列)所有包含变量值A或D的所有行:

     DT[c("A","D")]

        1

    变量值A匹配到了,而变量值D没有,故返回NA。
    返回匹配到键值所在列(V2列)所有包含值A或D的所有行:

    DT[c("A","D"), nomatch = 0]

        1

    因为nomatch参数,值D没有匹配到故不返回。

    by=.EACHI参数

    by=.EACHI允许按每一个已知i的子集分组,在使用by=.EACHI时需要设置键值
    返回键值(V2列)中包含A或C的所有行中,V4列的总和。

     DT[c("A","C"),
         sum(V4)]

        1
        2

    返回键值所在列(V2列)中包含A的行在V4列总和与包含C的行在V4列的总和。

     DT[c("A","C"),
         sum(V4), by=.EACHI]

        1
        2

    使用setkey()设置一个多列主键

    任意列都能使用setkey()来设置主键,这种方式可以选择2个列作为一个主键。以下是一个等值连接V1列的每个组先根据V1排序,再根据V2排序。

    setkey(DT,V1,V2)
    无显式返回结果

    选择键值1(V1列)为2且键值2(V2列)为C的行。

     DT[.(2,"C")]

        1

    选择键值1(V1列)为2且键值2(V2列)为A或C的行

     DT[.(2,c("A","C"))]

        1

    7.对数据进行排序

    利用setorder()函数可对数据进行排序:升序

    mydata01 = setorder(mydata, origin)

        1

    对数据进行降序

    mydata02 = setorder(mydata, -origin)

        1

    还可 基于多个变量进行排序

    mydata03 = setorder(mydata, origin, -carrier)

        1

    8.使用:=引用来添加或更新一列

    在一行中使用:=引用来添加或更新列.

    注意: 额外的指定 (DT <- DT[…])是多余的
    使用:=来更新V1列:

    > DT[, V1 := round(exp(V1),2)]
    #这段代码没有显式的返回结果,而V1列从[1] 1 2 1 2 … 变成了 [1] 2.72 7.39 2.72 7.39 …
    > DT
          V1 V2      V3 V4
     1: 2.72  A -0.8981  1
     2: 7.39  B -0.3348  2
     3: 2.72  C -0.5014  3
     4: 7.39  A -0.1745  4
     5: 2.72  B -0.8981  5
     6: 7.39  C -0.3348  6
     7: 2.72  A -0.5014  7
     8: 7.39  B -0.1745  8
     9: 2.72  C -0.8981  9
    10: 7.39  A -0.3348 10
    11: 2.72  B -0.5014 11
    12: 7.39  C -0.1745 12

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16

    使用:=引用来添加或更新多列

    使用:=更新V1列和V2列:

     >DT[, c("V1","V2") := list(round(exp(V1),2), LETTERS[4:6])]
     > DT
             V1 V2      V3 V4
     1:   15.18  D -0.8981  1
     2: 1619.71  E -0.3348  2
     3:   15.18  F -0.5014  3
     4: 1619.71  D -0.1745  4
     5:   15.18  E -0.8981  5
     6: 1619.71  F -0.3348  6
     7:   15.18  D -0.5014  7
     8: 1619.71  E -0.1745  8
     9:   15.18  F -0.8981  9
    10: 1619.71  D -0.3348 10
    11:   15.18  E -0.5014 11
    12: 1619.71  F -0.1745 12
    #同样没有显式的返回结果,V1列的结果与上相同,V2列从[1] “A” “B” “C” “A” “B” “C” … 变成: [1] “D” “E” “F” “D” “E” “F” …

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16

    使用函数:=

    上例的另一种写法,但会在书写时更易并齐。而且,当添加[]时,结果会返回在屏幕中

     > DT[, ':=' (V1 =round(exp(V1),2),V2 = LETTERS[4:6])][]
         V1 V2      V3 V4
     1: Inf  D -0.8981  1
     2: Inf  E -0.3348  2
     3: Inf  F -0.5014  3
     4: Inf  D -0.1745  4
     5: Inf  E -0.8981  5
     6: Inf  F -0.3348  6
     7: Inf  D -0.5014  7
     8: Inf  E -0.1745  8
     9: Inf  F -0.8981  9
    10: Inf  D -0.3348 10
    11: Inf  E -0.5014 11
    12: Inf  F -0.1745 12

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15

    与上例变化相同,但是由于在语句最后添加了[],这一结果会返回至屏幕

    通过使用:=来移除一列

    移除V1列

    > DT[, V1 := NULL]
    > DT
        V2      V3 V4
     1:  D -0.8981  1
     2:  E -0.3348  2
     3:  F -0.5014  3
     4:  D -0.1745  4
     5:  E -0.8981  5
     6:  F -0.3348  6
     7:  D -0.5014  7
     8:  E -0.1745  8
     9:  F -0.8981  9
    10:  D -0.3348 10
    11:  E -0.5014 11
    12:  F -0.1745 12
     #无显式的返回结果,但V1列变为NULL

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16

    通过使用:=来移除多列

    移除V1列与V2列

     DT[, c("V1","V2") := NULL]
     #无显式的返回结果,但V1列与V2列变为NULL

        1
        2

    将一个包含列名的变量用小括号包裹起来,变量所传递的内容将会被删除
    注意:列名为Cols.chosen的列将会被删除,这里不是删除”V1”,”V2”列

     Cols.chosen = c("V1","V2")
     DT[, Cols.chosen := NULL]
     #无显式的返回结果,列名为Cols.chosen的列将会被删除
     #删除指定变量Cols.chosen包含的V1列和V2列
     DT[, (Cols.chosen) := NULL]
     #无显式的返回结果,列名为V1和V2的列变为NULL

        1
        2
        3
        4
        5
        6

    对原数据增加一列

    mydata[, dep_sch:=dep_time - dep_delay]

        1

    增加多列

    mydata002 = mydata[, c("dep_sch","arr_sch"):=list(dep_time - dep_delay, arr_time - arr_delay)]

        1

    9.数据聚合的实现,并赋予名字

    mydata[, .(mean = mean(arr_delay, na.rm = TRUE),
               median = median(arr_delay, na.rm = TRUE),
               min = min(arr_delay, na.rm = TRUE),
               max = max(arr_delay, na.rm = TRUE))]
           mean median  min  max
    1: 8.146702     -4 -112 1494

    mydata[,.(sum(distance),sd(hour))]
              V1       V2
    1: 278507079 4.897891

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11

    若列的长度不一,则会循环对齐

    选择V1这一列,并计算V3这列的标准差,将会得到一个标准差的值并循环补齐

    DT <- data.table(V1=c(1L,2L),
                       V2=LETTERS[1:3],
                       V3=round(rnorm(4),4),
                       V4=1:12)
     DT[,.(V1, Sd.V3 = sd(V3))]
       V1     Sd.V3
     1:  1 0.2810601
     2:  2 0.2810601
     3:  1 0.2810601
     4:  2 0.2810601
     5:  1 0.2810601
     6:  2 0.2810601
     7:  1 0.2810601
     8:  2 0.2810601
     9:  1 0.2810601
    10:  2 0.2810601
    11:  1 0.2810601
    12:  2 0.2810601

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18

    多个表达式可以包裹在花括号中

    输出V2这一列并绘制V3这一列

     DT[,{print(V2)
      plot(V3)
      NULL}]
       [1] "A" "B" "C" "A" "B" "C" "A" "B" "C" "A" "B" "C"
    NULL

        1
        2
        3
        4
        5

    plot(V3)

    对多个变量做聚合计算

    mydata[, .(mean(arr_delay), mean(dep_delay))]

        1

    如果要对大量的变量做聚合计算,可以使用.SD函数,和.SDcols函数。

    mydata[, lapply(.SD, mean), .SDcols = c("arr_delay", "dep_delay")]

        1

    默认的,.SD函数指对所有变量进行计算

    mydata[, lapply(.SD, mean)]

        1

    对多个变量实现多个统计指标计算

    mydata[, sapply(.SD, function(x) c(mean=mean(x), median=median(x)))]

        1

    10.GROUP BY函数

    #按照单个变量分组
    mydata[, .(mean_arr_delay = mean(arr_delay, na.rm = TRUE)), by = origin]

    #按照多个变量分组
    mydata[, .(mean_arr_delay = mean(arr_delay, na.rm = TRUE)), by = .(origin,carrier)]

        1
        2
        3
        4
        5

    在by中调用函数

    以sign(V1-1)为分组,计算各个分组中V4列的和:

    DT[,.(V4.Sum = sum(V4)),by=sign(V1-1)]

        1
        2

    使用函数.N来得到每个类别的总观测数

    在V1列中计算每个分组的观测数

     DT[,.N,by=V1]
        V1 N
    1:  1 6
    2:  2 6

        1
        2
        3
        4

    11.data.table高级操作总结

    .N

    .N可以用来表示行的数量或者最后一行

    在i处使用:

    DT[.N-1]
       V1 V2      V3 V4
    1:  1  B -0.5765 11

        1
        2
        3

    返回每一列的倒数第二行
    在j处使用:

    DT[,.N-1]
    [1] 11

        1
        2

    返回倒数第二行所在的行数。

    .()

    .()是list()的一个别名,他们在data.table中是等价的。当只有一个元素的位置j或者by中,是不需要.()的。

    在j中使用:

    DT[,.(V2,V3)] #or DT[,list(V2,V3)]
        V2      V3
     1:  A -0.8313
     2:  B  0.7615
     3:  C -0.5765

        1
        2
        3
        4
        5
        6

    在by中使用:

     DT[, mean(V3),by=.(V1,V2)]
       V1 V2       V1
    1:  1  A -0.70390
    2:  2  B  0.06755
    3:  1  C -0.70390
    4:  2  A  0.06755
    5:  1  B -0.70390
    6:  2  C  0.06755
    #以V1,V2为分组,对V3求均值

        1
        2
        3
        4
        5
        6
        7
        8
        9

    .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

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17

    以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

        1
        2
        3
        4
        5
        6
        7
        8
        9

    以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

        1
        2
        3
        4
        5
        6

    .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也可以是一个函数的返回值:

        1
        2
        3
        4
        5
        6
        7

    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
    #结果与上一个是相同的。

        1
        2
        3
        4
        5
        6
        7

    12.串联操作可以把表达式聚合在一起并避免多余的中间变量

    把多个操作串联起来,这等价于SQL中的having

    #这个是不使用串联的方法,先以V1为分组,对V4求和,然后再把分组总和大于35的取出来。
    DT<-DT[, .(V4.Sum = sum(V4)),by=V1]
    DT[V4.Sum > 35] #no chaining
    V1 V4.Sum
    1: 1 36
    2: 2 42

        1
        2
        3
        4
        5
        6

    使用串联的方法:

    DT[, .(V4.Sum = sum(V4)),by=V1][V4.Sum > 35 ]
    V1 V4.Sum
    1: 1 36
    2: 2 42

        1
        2
        3
        4

    分组求和之后对V1进行排序:

     DT[, .(V4.Sum = sum(V4)),by=V1][order(-V1)]
    V1 V4.Sum
    1: 2 42
    2: 1 36

        1
        2
        3
        4

    13.使用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

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20

    以上程序把给定的一组行和列都设置为了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()

        1
        2
        3
        4
        5

    setcolorder()可以用来修改列的顺序。

    setcolorder(DT,c("V2","V1","V4","V3"))
    #这段代码会使得列的顺序变成:

    [1] "V2" "V1" "V4" "V3"

        1
        2
        3
        4

    举个栗子:
    首先介绍下data.table的语法,如下所示:

    这里写图片描述

    在data.table包中,我们可以使用:=引用来添加或更新列
    这里写图片描述
    这里写图片描述

    内置的 order() 函数 * 我们可以对一个字符型的列,使用减号“-”,来实现降序排列。

    当我们用list()的时候,返回的是data.table,不用list()时,返回的是向量。一般建议加上list(),除非你就是想要得到向量格式的数据。

        select取子集方法之subset(x, subset, select)
        注:subset特指对列的选择,select特指对行的选择, with = FALSE 来引用列名

    select列

        既然列可以作为变量被引用,我们可以直接引用我们想选取的列。

        既然我们想选取所有的行,则可毋需指定参数 i。

        返回了所有行的 arr_delay 列。

    特殊的语法

    .SD: data.table提供一个特殊的语法,形式是 .SD。它是 Subset of Data 的缩写。

    它自身就是一个data.table,包含通过by 分组后的每一组。 回忆一下,一个data.table本质上是一个list,它们的列包含的元素个数都相同(其实就是行数)。

    说明:

        .SD 包含除了分组依据的那一列以外的所有列。
        返回值依旧保持了原数据的顺序。首先打印出来的是 ID=“b” 的数据,然后是 ID=“a” 的,最后是 ID=“c” 的。
        为了对复数的列进行计算,我们可以简单地使用函数 lapply()。

    这里写图片描述

    说明:

        .SD 分别包含了ID是 a、b、c的所有行,它们分别对应了各自的组。我们应用函数 lapply() 对每列计算平均值。
        每一组返回包含三个平均数的list,这些构成了最终返回的data.table。
        既然函数 lapply() 返回 list,我们就不需要在外面多加 .() 了。
        -如何指定希望计算平均值的列

    .SDcols
    使用参数 .SDcols。它接受列名或者列索引。比如,.SDcols = c(“arr_delay”, “dep_delay”)能确保.SD之包含 arr_delay 和 dep_delay 这两列。
    和 with = FALSE 一样,我们也可以使用 - 或者 ! 来移除列。比如,我们指定 !(colA:colB) 或者 -(colA:colB)表示移除从 colA 到 colB 的所有列。

    这里写图片描述
    总结

    data.table的语法形式是:

    DT[i, j, by]
    指定参数i:

        类似于data.frame,我们可以subset行,除非不需要重复地使用 DT$,既然我们能将列当做变量来引用。

        我们可以使用order()排序。为了得到更快速的效果,order()函数内部使用了data.table的快速排序。
        我们可以通过参数i做更多的事,得到更快速的选取和连结。我们可以在教程“Keys and fast binary search based subsets”和“Joins and rolling joins”中学到这些。
        指定参数j:

        以data.table的形式选取列:DT[, .(colA, colB)]。
        以data.frame的形式选取列:DT[, c(“colA”, “colB”), with=FALSE]。
        按列进行计算:DT[, .(sum(colA), mean(colB))]。
        如果需要:DT[, .(sA =sum(colA), mB = mean(colB))]。

        和i共同使用:DT[colA > value, sum(colB)]。
        指定参数by:* 通过by,我们可以指定列,或者列名,甚至表达式,进行分组。参数j可以很灵活地配置参数i和by实现强大的功能。

        by可以指定多个列,也可以指定表达式。
        我们可以用 keyby,对分组的结果自动排序。
        我们可以在参数j中指定 .SD 和 .SDcols,对复数的列进行操作。例如:
        1.把函数fun 应用到所有 .SDcols指定的列上,同时对参数by指定的列进行分组:DT[, lapply(.SD, fun), by=., .SDcols=…]。
        2.返回每组册前两行:DT[, head(.SD, 2), by=.]。
        3.三个参数联合使用:DT[col > val, head(.SD, 1), by=.]

    资料参考:

    data.table包使用简介
    data.table–cran
    R–data.table介绍学习
    R–data.table速查手册
    ---------------------  


  • 相关阅读:
    大数加法、乘法实现的简单版本
    hdu 4027 Can you answer these queries?
    zoj 1610 Count the Colors
    2018 徐州赛区网赛 G. Trace
    1495 中国好区间 尺取法
    LA 3938 动态最大连续区间 线段树
    51nod 1275 连续子段的差异
    caioj 1172 poj 2823 单调队列过渡题
    数据结构和算法题
    一个通用分页类
  • 原文地址:https://www.cnblogs.com/Raymontian/p/9789512.html
Copyright © 2011-2022 走看看