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速查手册
    ---------------------  


  • 相关阅读:
    文档注释
    配置环境变量
    Java编译-->运行
    DOS命令(日后补充)
    字符、字符串函数
    输入字符串,逆序输出
    求矩阵最大元素值,以及行号和列号
    Apache和Tomcat的区别
    C# params关键字
    JSP的隐式对象(session)
  • 原文地址:https://www.cnblogs.com/Raymontian/p/9789512.html
Copyright © 2011-2022 走看看