Updated: 2021-09-17

Hari ni bersempena Hari kemerdekaan Malaysia ada masa untuk ulang kaji pakej data.table. Hari ni ialah mengenai Special Symbol seperti .N, .I, .GRP, .BY. Penerangan ini diambil dari manual di data.table tetapi diedit sedikit. Untuk rujukan di sini.

Ini data yang dipakai untuk membuat contoh:

  DT = data.table(x=rep(c("b","a","c"),each=3), v=c(1,1,1,2,2,1,1,2,2), y=c(1,6,3,7,8), a=1:9, b=9:1)
  X = data.table(x=c("c","b"), v=8:7, foo=c(4,2))

.N

Penggunaan .N selain dari untuk mendapatkan jumlah baris di dataset, .N boleh juga digunakan untuk melihat barisan terakhir di dataset. Untuk melihat barisan pertama guna DT[1].

  DT[.N] # last row, only special symbol allowed in 'i' - nesten som Total
  DT[, .N] # total number of rows in DT
  DT[, .N, by=x] # number of rows in each group

Mult

Contoh untuk penggunaan mult (multiple rows) adalah seperti di bawah. Penggunaan fungsi mult ialah untuk menetapkan kombinasi barisan yang ingin ditunjukkan samada “all”, “first” atau “last”. Variable x dan y boleh disusun dengan menggunakan setkey(DT, x, y). Sekiranya tidak disusun terlebih dahulu sebelum dipakai maka harus menggunakan fungsi on seperti contoh di bawah.

  ## contoh data
  dt <- data.table(x = c(1, 1, 3, 1, 7),
                   y = c(1, 2, 3, 2, 6))

  setkey(dt, x)

  ## dapatkan kombinasi yang unik
  udt <- unique(dt)

  ## buat kolom dengan nilai 0
  dt[, c("first", "last") := 0L][]
     x y first last
  1: 1 1     0    0
  2: 1 2     0    0
  3: 1 2     0    0
  4: 3 3     0    0
  5: 7 6     0    0

Menggunakan mult untuk menetapkan kombinasi unik yang diingini. Pemakaian "first" menunjukkan kombinasi pertama sahaja. Sekiranya kombinasi yang sama terdapat dipelbagai baris, hanya barisan yang pertama dimana kombinasi tersebut ditemui akan dipilih. Pemakaian "last" memilih barisan terakhir dimana kombinasi yang diingini ditemui.

  ## Sekiranya kombinasi x,y yang pertama terdapat
  ## di data masukkan 1 di kolom "first"
  dt[udt, first := 1L, on = c("x", "y"), mult = "first"][]

  ## Sekiranya kombinasi x,y yang terakhir terdapat
  ## di data masukkan nilai 1 di kolom "last"
  dt[udt, last := 1L, on = c("x", "y"), mult = "last"][]
     x y first last
  1: 1 1     1    1
  2: 1 2     1    0
  3: 3 3     1    1
  4: 1 2     0    1
  5: 7 6     1    1

Contoh di bawah menunjukkan cara sekiranya hanya ingin mendapatkan index kombinasi yang diingini sahaja.

  ## Untuk lihat indeks bagi kombinasi yang unik sahaja
  dt[unique(dt), on = c("x", "y"), mult = "first", which = TRUE]

  [1] 1 2 3 5

Contoh lain menggunakan mult. Seperti kajian isi rumah (household) dimana “id” mewakili rumah. Semua ahli keluarga mempunyai id-rumah sama. Sekiranya ingin mencari ahli termuda atau tertua fungsi mult dapat memudahkan proses.

  set.seed(1234)
  dt <- data.table(id = sample(1:4, 10, TRUE),
                   umur = sample(20:35, 10, TRUE),
                   jentina = sample(1:2, 10, TRUE),
                   kode = sample(1:5, 2, TRUE))

  ## Susun umur mengikut id
  setkey(dt, id, umur)

  ## first ialah id yang sama ahli yang paling muda
  dt[unique(dt), muda := 1L, on = list(id), mult = "first"][]

  ## Pilih yang terakhir dari id yang sama - cth utk pilih ahli tertua
  ## sekiranya tidak pakai list di 'on = list(nama-var)' boleh pakai "nama-var".
  dt[unique(dt), tua := as.integer(1L), on = "id", mult = "last", by = .(umur)][]

  ## pilih nilai pertama untuk setiap kombinasi unik antara 'id' dan 'kode'
  dt[unique(dt[, c("id", "kode")]), KodePertama := 1L, on = list(id, kode), mult = "first"][]

  ## pilih nilai terakhir untuk setiap kombinasi unik antara 'id' dan 'kode'
  dt[unique(dt[, c("id", "kode")]), KodeAkhir := 1L, on = c("id", "kode"), mult = "last"][]

Hasilnya dari contoh pemilihan ahli yang paling muda dan tua dari data di atas menggunakan "first" dan "last". Pemakaian unique(dt) berasaskan dari penetapan yang dibuat di fungsi setkey dimana data disusun mengikut id kemudian umur terlebih dahulu.

Sekiranya pemilihan kombinasi unik berasaskan kolom lain, selain dari id dan umur yang telah ditetapkan, pemilihan kolom unik boleh dibuat secara fungsi asas menggunakan unique(dt[, c("kol1", "kol2")]). Penggunaan on boleh memakai cara list atau concatenate.

       id umur jentina kode muda tua KodePertama KodeAkhir
   1:  1   24       2    3    1  NA           1        NA
   2:  1   24       2    2   NA  NA           1         1
   3:  1   31       1    3   NA   1          NA         1
   4:  3   22       2    3    1  NA           1        NA
   5:  3   23       1    2   NA  NA           1        NA
   6:  3   24       1    3   NA  NA          NA         1
   7:  3   28       1    2   NA  NA          NA        NA
   8:  3   33       2    2   NA  NA          NA        NA
   9:  3   34       1    2   NA   1          NA         1
  10:  4   24       1    3    1   1           1         1

.SD dan .SDcols

Penggunaan .SD juga boleh berasaskan indeks barisan. Contoh untuk menggunakan .SDcols seperti di bawah termasuk menggunakan fungsi lapply. Tetapi penggunaan ".SD" adalah lebih lambat berbanding menggunakan fungsi "on" seperti di atas.

  # pilih kolom 'x' dan 'y'
  DT[, .SD, .SDcols = x:y]
  # baris pertama di semua kolom
  DT[, .SD[1]]
  # baris pertama di 'y' dan 'v' untuk setiap kumpulan di 'x'
  DT[, .SD[1], by = x]
  # get rows *and* sum all col
  DT[, c(.N, lapply(.SD, sum)), by = x]
  # get rows *and* sum columns 'v' and 'y' by group
  DT[, c(.N, lapply(.SD, sum)), by = x, .SDcol = c("v", "y")]

.I

Untuk dapatkan indeks barisan simbol .I boleh dipakai. Hanya vektor untuk indeks barisan yang akan diberikan dan tidak nilai di indeks tersebut. Fungsinya sama seperti seq_len(nrow(x)). Semasa penggumpulan dibuat, pada masa yang sama penggumpulan dilakukan di dalam kumpulan yang ditetapkan. Sesuai digunakan untuk membuat subset di j seperti: DT[,.I[which.max(somecol)], by=grp]. Penggunaannya same seperti fungsi which di base.

Buat identity

Cara lain boleh digunakan untuk membuat indentity atau ID. DT[, id := .I] seperti menggunakan DT[, id := seq_len(.N)

Dapatkan barisan pertama

Pemakaian .I[1] contohny digunakan untuk mendapatkan index dimana nilai pertama bagi setiap kumpulan di x. Untuk kumpulan b di kolom x, nilai pertama ialah di barisan 1, nilai pertama bagi kumpulan a di kolom x ialah di barian ke 4 dan nilai pertama kumpulan c di barisan ke 7.

  DT
     x v y a b
  1: b 1 1 1 9
  2: b 1 6 2 8
  3: b 1 3 3 7
  4: a 2 7 4 6
  5: a 2 8 5 5
  6: a 1 1 6 4
  7: c 1 6 7 3
  8: c 2 3 8 2
  9: c 2 7 9 1

  DT[, .I[1], by = x] # first row number in DT corresponding to each group

     x V1
  1: b  1
  2: a  4
  3: c  7

  DT[, .(index = .I[1]), by = x] # Namakan variable untuk index

     x index
  1: 1     1
  2: 3     4
  3: 7     5

Dapatkan barisan nilai maksium

Untuk dapatkan index bagi nilai maksimum mengikut kumpulan di kolom x boleh dibuat seperti cara di bawah.

  DT[, .I[which.max(y)], by = x] # which row number with the max 'y' by 'x'

     x V1
  1: b  2
  2: a  5
  3: c  9

Buat subset

Untuk membuat subset data berdasarkan nilai atau kategori tertentu seperti setiap tahun.

## Dapatkan index barisan
DT[, .I[sample(age, 5)], by = year]

## Subset data dari index
DT[DT[, I[sample(age, 5)], by = year]$V1]

.GRP dan rleid

Untuk mengkaji menggikut kumpulan secara penyusunan.

  DT[, grp := .GRP, by = x][] # add a group counter

     x v y a b grp
  1: b 1 1 1 9   1
  2: b 1 6 2 8   1
  3: b 1 3 3 7   1
  4: a 2 7 4 6   2
  5: a 2 8 5 5   2
  6: a 1 1 6 4   2
  7: c 1 6 7 3   3
  8: c 2 3 8 2   3
  9: c 2 7 9 1   3

  DT[, .N, by = rleid(v)] # get count of consecutive runs of 'v'

     rleid N
  1:     1 3
  2:     2 2
  3:     3 2
  4:     4 2

  DT[, c(.(ym = max(y)), lapply(.SD, min)), by = rleid(v), .SDcols = v:b] # compute 'j' for each consecutive runs of 'v'

     rleid ym v y a b
  1:     1  6 1 1 1 7
  2:     2  8 2 7 4 5
  3:     3  6 1 1 6 3
  4:     4  7 2 3 8 1

Untuk gabungkan dua dataset. Tapi cara ini masih tidak difahami :-(

  X

     x v foo
  1: c 8   4
  2: b 7   2

  ## need more info for this
  X[, DT[.BY, y, on = "x"], by = x] # join within each group

     x V1
  1: c  6
  2: c  3
  3: c  7
  4: b  1
  5: b  6
  6: b  3

Untuk tukar nilai bagi setiap barisan pertama di kumpulan yang sama. Ini biasanya dipakai contohnya bila membuat kajian keluarga dan ingin memberikan kod tertentu yang membezakan keluarga 1 dan 2 dsb.

Cara ini tidak hard code data. Kolom c tidak dimasukkan ke data dan hanya disimpan di memory sahaja. Untuk simpan harus assign to save object atau gunakan cara mult.

  ## Recode to 99 for first row in each group by x
  DT[, {vDT = copy(.SD) #kopi semua kolom
        vDT[1, c := 99] #buat kolom C row pertama nilai 99
        vDT},
        by = x]

     x v y a b grp  c
  1: b 1 1 1 9   1 99
  2: b 1 6 2 8   1 NA
  3: b 1 3 3 7   1 NA
  4: a 2 7 4 6   2 99
  5: a 2 8 5 5   2 NA
  6: a 1 1 6 4   2 NA
  7: c 1 6 7 3   3 99
  8: c 2 3 8 2   3 NA
  9: c 2 7 9 1   3 NA

  DT[unique(x), d:=99, on = "x", mult = "first"][]

Contoh dari manual

Ini ialah contoh dan penerangan dari manual sekiranya penerangan diatas tidak difahami.

  ## Not run:
  DT = data.table(x=rep(c("b","a","c"),each=3), v=c(1,1,1,2,2,1,1,2,2), y=c(1,3,6), a=1:9, b=9:1)
  DT
  X = data.table(x=c("c","b"), v=8:7, foo=c(4,2))
  X

  DT[.N]                                 # last row, only special symbol allowed in 'i'
  DT[, .N]                               # total number of rows in DT
  DT[, .N, by=x]                         # number of rows in each group
  DT[, .SD, .SDcols=x:y]                 # select columns 'x' and 'y'
  DT[, .SD[1]]                           # first row of all columns
  DT[, .SD[1], by=x]                     # first row of 'y' and 'v' for each group in 'x'
  DT[, c(.N, lapply(.SD, sum)), by=x]    # get rows *and* sum all columns by group
  DT[, .I[1], by=x]                      # row number in DT corresponding to each group starting point
  DT[, .N, by=rleid(v)]                  # get count of consecutive runs of 'v'
  DT[, c(.(y=max(y)), lapply(.SD, min)),
          by=rleid(v), .SDcols=v:b]      # compute 'j' for each consecutive runs of 'v'
  DT[, grp := .GRP, by=x]                # add a group counter
  X[, DT[.BY, y, on="x"], by=x]          # join within each group

  ## End(Not run)
comments powered by Disqus