Bagaimana Anda menghapus kolom dengan nama di data.table?

195

Untuk menghilangkan kolom bernama "foo" dalam data.frame, saya dapat melakukan:

df <- df[-grep('foo', colnames(df))]

Namun, setelah dfdikonversi ke data.tableobjek, tidak ada cara untuk hanya menghapus kolom.

Contoh:

df <- data.frame(id = 1:100, foo = rnorm(100))
df2 <- df[-grep('foo', colnames(df))] # works
df3 <- data.table(df)
df3[-grep('foo', colnames(df3))] 

Tapi begitu dikonversi menjadi data.tableobjek, ini tidak lagi berfungsi.

Maiasaura
sumber
2
Akan lebih jelas untuk memberi nama data. Tabel dtbukannya df3...
PatrickT

Jawaban:

283

Salah satu dari yang berikut ini akan menghapus kolom foodari tabel data df3:

# Method 1 (and preferred as it takes 0.00s even on a 20GB data.table)
df3[,foo:=NULL]

df3[, c("foo","bar"):=NULL]  # remove two columns

myVar = "foo"
df3[, (myVar):=NULL]   # lookup myVar contents

# Method 2a -- A safe idiom for excluding (possibly multiple)
# columns matching a regex
df3[, grep("^foo$", colnames(df3)):=NULL]

# Method 2b -- An alternative to 2a, also "safe" in the sense described below
df3[, which(grepl("^foo$", colnames(df3))):=NULL]

data.table juga mendukung sintaks berikut:

## Method 3 (could then assign to df3, 
df3[, !"foo"]  

meskipun jika Anda benar-benar ingin menghapus kolom "foo"dari df3(bukan hanya mencetak tampilan df3kolom minus "foo") Anda benar-benar ingin menggunakan Metode 1 sebagai gantinya.

(Perhatikan bahwa jika Anda menggunakan metode yang mengandalkan grep()atau grepl(), Anda perlu mengatur pattern="^foo$"daripada "foo", jika Anda tidak ingin kolom dengan nama seperti "fool"dan "buffoon"(yaitu yang mengandung foosebagai substring) juga dicocokkan dan dihapus.)

Opsi yang kurang aman, baik untuk penggunaan interaktif:

Dua idiom berikutnya juga akan berfungsi - jika df3berisi kolom yang cocok"foo" - tetapi akan gagal dengan cara yang mungkin tidak terduga jika tidak. Jika, misalnya, Anda menggunakan salah satu dari mereka untuk mencari kolom yang tidak ada "bar", Anda akan berakhir dengan tabel data baris-nol.

Sebagai konsekuensinya, mereka benar-benar paling cocok untuk penggunaan interaktif di mana orang mungkin, misalnya, ingin menampilkan data "foo". Untuk tujuan pemrograman (atau jika Anda ingin benar-benar menghapus kolom dari df3daripada dari salinannya), Metode 1, 2a, dan 2b benar-benar merupakan pilihan terbaik.

# Method 4:
df3[, .SD, .SDcols = !patterns("^foo$")]

Terakhir ada pendekatan menggunakan with=FALSE, meskipun data.tablesecara bertahap menjauh dari menggunakan argumen ini sehingga sekarang tidak disarankan di mana Anda bisa menghindarinya; ditampilkan di sini sehingga Anda tahu opsi ada jika Anda benar-benar membutuhkannya:

# Method 5a (like Method 3)
df3[, !"foo", with=FALSE] 
# Method 5b (like Method 4)
df3[, !grep("^foo$", names(df3)), with=FALSE]
# Method 5b (another like Method 4)
df3[, !grepl("^foo$", names(df3)), with=FALSE]
Josh O'Brien
sumber
2
Lihat komentar saya kepada OP tentang -grepversus !grepl.
Joshua Ulrich
1
@ JoshuaUlrich - Poin bagus. Saya mencoba secara grepl()initally dan tidak berhasil, karena kolom data.table tidak dapat diindeks oleh vektor logis. Tapi sekarang saya menyadari bahwa grepl()ini dapat dibuat untuk bekerja dengan membungkusnya which(), sehingga mengembalikan vektor integer.
Josh O'Brien
1
Saya tidak tahu tentang pengindeksan data.table, tetapi membungkusnya dengan whichcerdas!
Joshua Ulrich
6
Saya juga tidak tahu tentang data.tableitu; menambahkan FR # 1797 . Tetapi, metode 1 (hampir) jauh lebih cepat daripada yang lain. Metode 1 menghapus kolom dengan referensi tanpa salinan sama sekali. Saya ragu Anda mendapatkannya di atas 0,005 detik untuk semua data ukuran. Sebaliknya, yang lain mungkin tidak berfungsi sama sekali jika tabelnya mendekati 50% dari RAM karena mereka menyalin semua kecuali yang dihapus.
Matt Dowle
1
@ user3969377 jika Anda ingin menghapus kolom berdasarkan isi dari variabel karakter Anda cukup membungkusnya dalam tanda kurung. Yaitu. df [, (afoo): = NULL]
Dean MacGregor
31

Anda juga dapat menggunakan setini, yang menghindari overhead [.data.tabledalam loop:

dt <- data.table( a=letters, b=LETTERS, c=seq(26), d=letters, e=letters )
set( dt, j=c(1L,3L,5L), value=NULL )
> dt[1:5]
   b d
1: A a
2: B b
3: C c
4: D d
5: E e

Jika Anda ingin melakukannya dengan nama kolom, which(colnames(dt) %in% c("a","c","e"))harus berhasil j.

Ari B. Friedman
sumber
2
Di data.table1.11.8, jika Anda ingin melakukannya dengan nama kolom, Anda dapat melakukannya secara langsung rm.col = c("a","b")dandt[, (rm.col):=NULL]
Duccio A
20

Saya cukup melakukannya dalam bingkai data cara:

DT$col = NULL

Bekerja cepat dan sejauh yang saya lihat tidak menimbulkan masalah.

PEMBARUAN: bukan metode terbaik jika DT Anda sangat besar, karena menggunakan $<-operator akan menyebabkan penyalinan objek. Jadi lebih baik gunakan:

DT[, col:=NULL]
msp
sumber
8

Opsi yang sangat sederhana jika Anda memiliki banyak kolom individual untuk dihapus dalam tabel data dan Anda ingin menghindari mengetikkan semua nama kolom #careadviced

dt <- dt[, -c(1,4,6,17,83,104)]

Ini akan menghapus kolom berdasarkan nomor kolom sebagai gantinya.

Ini jelas tidak seefisien karena memotong keuntungan data. Tetapi jika Anda bekerja dengan kurang dari 500.000 baris, itu berfungsi dengan baik

SJDS
sumber
4

Misalkan dt Anda memiliki kolom col1, col2, col3, col4, col5, coln.

Untuk menghapus sebagian dari mereka:

vx <- as.character(bquote(c(col1, col2, col3, coln)))[-1]
DT[, paste0(vx):=NULL]
Ricardo Paixao
sumber
ini harus menjadi komentar
Sachila Ranawaka
-2

Berikut adalah cara ketika Anda ingin mengatur # kolom ke NULL mengingat nama kolom mereka fungsi untuk penggunaan Anda :)

deleteColsFromDataTable <- function (train, toDeleteColNames) {

       for (myNm in toDeleteColNames)

       train <- train [,(myNm):=NULL]

       return (train)
}
pengguna3531326
sumber
-3
DT[,c:=NULL] # remove column c
Durga Gaddam
sumber
-7

Untuk tabel data, menetapkan kolom ke NULL menghapusnya:

DT[,c("col1", "col1", "col2", "col2")] <- NULL
^
|---- Notice the extra comma if DT is a data.table

... yang setara dengan:

DT$col1 <- NULL
DT$col2 <- NULL
DT$col3 <- NULL
DT$col4 <- NULL

Setara untuk data.frame adalah:

DF[c("col1", "col1", "col2", "col2")] <- NULL
      ^
      |---- Notice the missing comma if DF is a data.frame

P. Mengapa ada koma di versi untuk data.table, dan tidak ada koma di versi untuk data.frame?

A. Karena data.frame disimpan sebagai daftar kolom, Anda dapat melewati koma. Anda juga dapat menambahkannya, namun kemudian Anda harus menetapkannya ke daftar NULLs DF[, c("col1", "col2", "col3")] <- list(NULL),.

Contango
sumber
@Arun Saya tidak bisa memikirkan situasi di data.framesmana baris dan kolom akan diaktifkan. Itu tidak masuk akal.
duHaas
@Arun Saya menandai Anda karena komentar pertama Anda membuatnya sepertinya ada saat-saat di mana Anda mungkin menelepon DF[column,row]jadi saya hanya ingin melihat apakah sebenarnya ada kejadian di mana ini terjadi.
duHaas
Memperbarui jawaban untuk menghapus kesalahan ketik.
Contango