Terkait dengan Bagaimana cara menggunakan data.table dalam fungsi dan loop?< /a>, apakah ada cara yang lebih baik untuk melakukan fungsi yang ditunjukkan di bawah ini, khususnya menggunakan data.table?
Catatan: Semua kode di bawah ini berfungsi, tetapi ... lambat.
(Saya menggunakan langkah-langkah "pembersihan" sederhana hanya untuk menunjukkan masalahnya).

Tujuannya adalah untuk menulis sebuah fungsi yang 1) efisien 2) mengganti 3) beberapa nilai dalam data.table, sehingga dapat kemudian digunakan dalam satu lingkaran untuk membersihkan kumpulan data dalam jumlah besar.
Di C++, ini akan dilakukan dengan menggunakan pointer dan panggilan dengan referensi seperti di bawah ini:

   void cleanDT(* dataTable dt); cleanDT(&dt222)

Namun dalam R, kita menyalin seluruh kumpulan data (data.tables) bolak-balik setiap kali kita memanggil suatu fungsi.

cleanDT <- function (dt) {
  strNames <- names(dt);   nCols <- 1:length(strNames)
  for (i in nCols) {
    strCol <- strNames[i]
    if ( class(dt[[strCol]]) == "numeric"  ) 
      dt[[strCol]] <- floor(dt[[strCol]])
    else 
      dt[[strCol]] <- gsub("I", "i", dt[[strCol]])
  }
  return(dt)
}
cleanDTByReference <- function (dt) {
  dtCleaned <- dt
  strNames <- names(dt);   nCols <- 1:length(strNames)
  for (i in nCols) {
    strCol = strNames[i]
    if ( class(dt[[strCol]]) == "numeric"  ) 
      dtCleaned[[strCol]] <- floor(dt[[strCol]])
    else 
      dtCleaned[[strCol]] <-  gsub("I", "i", dt[[strCol]]) 
  }
  eval.parent(substitute(dt <- dtCleaned))
}

dt222 <- data.table(ggplot2::diamonds); dt222[1:2]
dt222 <- cleanDT(dt222); dt222[1:2]

dt222 <- data.table(diamonds); dt222[1:2]
#   carat     cut color clarity depth table price    x    y    z
#1:  0.23   Ideal     E     SI2  61.5    55   326 3.95 3.98 2.43
#2:  0.21 Premium     E     SI1  59.8    61   326 3.89 3.84 2.31

cleanDTByReference(dt222); dt222[1:2]
#   carat     cut color clarity depth table price x y z
#1:     0   ideal     E     Si2    61    55   326 3 3 2
#2:     0 Premium     E     Si1    59    61   326 3 3 2

Kemudian kita akan menggunakan fungsi ini untuk membersihkan daftar tabel data dalam satu lingkaran seperti ini:

dt333 <- data.table(datasets::mtcars)
listDt <- list(dt222, dt333)

for(dt in listDt) {
  print(dt[1:2])
  cleanDTByReference(dt); print(dt[1:2])
}

Idealnya, sebagai hasilnya, saya ingin semua tabel data saya "dibersihkan" dengan cara ini, menggunakan fungsi. Tetapi saat ini tanpa menggunakan referensi, kode di atas TIDAK benar-benar mengubah listDt, atau dt222, dt333.
Dapatkah Anda menyarankan bagaimana untuk mencapai itu?

-3
IVIM 11 Maret 2017, 01:48

2 jawaban

Jawaban Terbaik

Anda dapat memodifikasi data.table dengan referensi menggunakan fungsi jika Anda mengikuti sintaks data.table.
(Saya sangat menyarankan untuk mempelajari data.table sketsa dan FAQ.)

Definisi fungsi:

change_DT_in_place <- function(DT){
  cat(address(DT), "\n")
  numcols <- DT[, which(sapply(.SD, is.numeric))]
  cat("num: ", numcols, "- ")
  if (length(numcols) > 0) {
    DT[, (numcols) := lapply(.SD, floor), .SDcols = numcols]
  }
  othcols <-  DT[, which(!sapply(.SD, is.numeric))]
  cat("other: ", othcols, "\n")
  if (length(othcols) > 0) {
    DT[, (othcols) := lapply(.SD, gsub, pattern = "I", replacement = "i"), 
       .SDcols = othcols]
  }
}

Perhatikan bahwa saya telah menambahkan beberapa pernyataan cat() untuk menunjukkan cara kerja bagian dalam. address() mengembalikan alamat dalam RAM suatu variabel.

Untuk memverifikasi bahwa fungsi berfungsi, harus ditunjukkan bahwa data.tables

  1. telah diubah
  2. tapi belum di copy.

Buat data.tabel:

library(data.table)
dt1 <- as.data.table(ggplot2::diamonds)
dt2 <- as.data.table(mtcars)

Ubah dulu data.table:

head(dt1)
#   carat       cut color clarity depth table price    x    y    z
#1:  0.23     Ideal     E     SI2  61.5    55   326 3.95 3.98 2.43
#2:  0.21   Premium     E     SI1  59.8    61   326 3.89 3.84 2.31
#3:  0.23      Good     E     VS1  56.9    65   327 4.05 4.07 2.31
#4:  0.29   Premium     I     VS2  62.4    58   334 4.20 4.23 2.63
#5:  0.31      Good     J     SI2  63.3    58   335 4.34 4.35 2.75
#6:  0.24 Very Good     J    VVS2  62.8    57   336 3.94 3.96 2.48
address(dt1)
#[1] "0000000015660EE0"
change_DT_in_place(dt1)
#0000000015660EE0 
#num:  1 5 6 7 8 9 10 - other:  2 3 4 
address(dt1)
#[1] "0000000015660EE0"
head(dt1)
#   carat       cut color clarity depth table price x y z
#1:     0     ideal     E     Si2    61    55   326 3 3 2
#2:     0   Premium     E     Si1    59    61   326 3 3 2
#3:     0      Good     E     VS1    56    65   327 4 4 2
#4:     0   Premium     i     VS2    62    58   334 4 4 2
#5:     0      Good     J     Si2    63    58   335 4 4 2
#6:     0 Very Good     J    VVS2    62    57   336 3 3 2

Ubah data.table kedua:

head(dt2)
#    mpg cyl disp  hp drat    wt  qsec vs am gear carb
#1: 21.0   6  160 110 3.90 2.620 16.46  0  1    4    4
#2: 21.0   6  160 110 3.90 2.875 17.02  0  1    4    4
#3: 22.8   4  108  93 3.85 2.320 18.61  1  1    4    1
#4: 21.4   6  258 110 3.08 3.215 19.44  1  0    3    1
#5: 18.7   8  360 175 3.15 3.440 17.02  0  0    3    2
#6: 18.1   6  225 105 2.76 3.460 20.22  1  0    3    1
address(dt2)
#[1] "0000000018C42E78"
change_DT_in_place(dt2)
#0000000018C42E78 
#num:  1 2 3 4 5 6 7 8 9 10 11 - other:   
address(dt2)
#[1] "0000000018C42E78"
head(dt2)
#   mpg cyl disp  hp drat wt qsec vs am gear carb
#1:  21   6  160 110    3  2   16  0  1    4    4
#2:  21   6  160 110    3  2   17  0  1    4    4
#3:  22   4  108  93    3  2   18  1  1    4    1
#4:  21   6  258 110    3  3   19  1  0    3    1
#5:  18   8  360 175    3  3   17  0  0    3    2
#6:  18   6  225 105    2  3   20  1  0    3    1

Kesimpulan

Dalam kedua kasus, fungsi telah mengubah data.tables di tempat seperti yang dapat dilihat dari alamat penunjuk yang tidak berubah.

3
Uwe 11 Maret 2017, 09:32

Berikut adalah cara yang lebih baik menggunakan data.table:

dt <- as.data.table(ggplot2::diamonds)
dt1 <- as.data.table(mtcars)

changeDT <- function(dt){
  cols <- names(dt)
  dt[, c(cols) := lapply(.SD, function(x) ifelse(sapply(x, is.numeric), 
                                                 floor(x), 
                                                 gsub("I", "i", x))),
     .SDcols = cols]
    }

    list1 <- list(dt, dt1)

    x <- lapply(list1, changeDT)
-2
tbradley 11 Maret 2017, 18:12