Pertanyaan saya terkait dengan penugasan dengan referensi versus menyalin data.table
. Saya ingin tahu apakah seseorang dapat menghapus baris dengan referensi, mirip dengan
DT[ , someCol := NULL]
Saya ingin tahu tentang
DT[someRow := NULL, ]
Saya kira ada alasan bagus mengapa fungsi ini tidak ada, jadi mungkin Anda bisa menunjukkan alternatif yang baik untuk pendekatan penyalinan biasa, seperti di bawah ini. Secara khusus, pergi dengan favorit saya dari contoh (data.table),
DT = data.table(x = rep(c("a", "b", "c"), each = 3), y = c(1, 3, 6), v = 1:9)
# x y v
# [1,] a 1 1
# [2,] a 3 2
# [3,] a 6 3
# [4,] b 1 4
# [5,] b 3 5
# [6,] b 6 6
# [7,] c 1 7
# [8,] c 3 8
# [9,] c 6 9
Katakanlah saya ingin menghapus baris pertama dari data ini. Saya tahu saya bisa melakukan ini:
DT <- DT[-1, ]
tetapi seringkali kita mungkin ingin menghindarinya, karena kita menyalin objek (dan itu membutuhkan sekitar 3 * N memori, jika N object.size(DT)
, seperti yang ditunjukkan di sini . Sekarang saya temukan set(DT, i, j, value)
. Saya tahu cara mengatur nilai tertentu (seperti di sini: atur semua nilai dalam baris 1 dan 2 dan kolom 2 dan 3 ke nol)
set(DT, 1:2, 2:3, 0)
DT
# x y v
# [1,] a 0 0
# [2,] a 0 0
# [3,] a 6 3
# [4,] b 1 4
# [5,] b 3 5
# [6,] b 6 6
# [7,] c 1 7
# [8,] c 3 8
# [9,] c 6 9
Tapi bagaimana saya bisa menghapus dua baris pertama, katakan? Perbuatan
set(DT, 1:2, 1:3, NULL)
mengatur seluruh DT ke NULL.
Pengetahuan SQL saya sangat terbatas, jadi kalian beri tahu saya: diberikan data. Tabel menggunakan teknologi SQL, apakah ada yang setara dengan perintah SQL
DELETE FROM table_name
WHERE some_column=some_value
dalam data.table?
sumber
data.table()
menggunakan teknologi SQL sebanyak yang dapat menarik paralel antara operasi yang berbeda dalam SQL dan berbagai argumen kedata.table
. Bagi saya, referensi ke "teknologi" agak menyiratkan yangdata.table
duduk di atas database SQL di suatu tempat, yang AFAIK tidak demikian.DT[ , keep := .I > 1]
, kemudian subset untuk operasi selanjutnya :,DT[(keep), ...]
bahkan mungkinsetindex(DT, keep)
kecepatan subset ini. Bukan obat mujarab, tetapi layak untuk dipertimbangkan sebagai pilihan desain dalam alur kerja Anda - apakah Anda benar-benar ingin menghapus semua baris itu dari memori , atau apakah Anda lebih suka mengecualikannya? Jawabannya berbeda dengan use case.Jawaban:
Pertanyaan bagus.
data.table
belum dapat menghapus baris dengan referensi.data.table
dapat menambah dan menghapus kolom dengan referensi karena terlalu mengalokasikan vektor pointer kolom, seperti yang Anda tahu. Rencananya adalah melakukan sesuatu yang serupa untuk baris dan memungkinkan cepatinsert
dandelete
. Hapus baris akan digunakanmemmove
dalam C untuk menggerakkan item (di setiap kolom) setelah baris yang dihapus. Menghapus baris di tengah-tengah tabel masih akan sangat tidak efisien dibandingkan dengan database toko baris seperti SQL, yang lebih cocok untuk memasukkan dan menghapus baris dengan cepat di mana pun baris tersebut berada di dalam tabel. Tapi tetap saja, itu akan jauh lebih cepat daripada menyalin objek besar baru tanpa baris yang dihapus.Di sisi lain, karena vektor kolom akan dialokasikan secara berlebihan, baris dapat disisipkan (dan dihapus) di bagian akhir , secara instan; misalnya, deret waktu yang berkembang.
Itu diajukan sebagai masalah: Hapus baris dengan referensi .
sumber
fread
dulu. Setelah itu cukup tinggi.DT[b<8 & a>3]
mengembalikan data.table baru. Kami ingin menambahkandelete(DT, b>=8 | a<=3)
danDT[b>=8 | a<=8, .ROW:=NULL]
. Keuntungan dari yang terakhir adalah menggabungkan dengan fitur lain[]
seperti nomor barisi
, bergabungi
danroll
mendapat manfaat dari[i,j,by]
optimasi.pendekatan yang telah saya lakukan untuk membuat penggunaan memori mirip dengan penghapusan di tempat adalah dengan mengelompokkan kolom pada suatu waktu dan menghapus. tidak secepat solusi memmove C yang tepat, tetapi hanya menggunakan memori yang saya pedulikan di sini. sesuatu seperti ini:
sumber
memmove
s untuk menggerakkan kesenjangan, tapi tidak apa-apa.DT[, col:= NULL, with = F]
diset(DT, NULL, col, NULL)
Berikut adalah fungsi yang bekerja berdasarkan jawaban @ vc273 dan umpan balik @ Frank.
Dan contoh penggunaannya:
Di mana "dat" adalah data.table. Menghapus 14k baris dari 1.4M baris membutuhkan 0,25 detik pada laptop saya.
PS. Karena saya baru mengenal SO, saya tidak bisa menambahkan komentar ke utas @ vc273 :-(
sumber
Alih-alih atau mencoba mengatur ke NULL, coba atur ke NA (cocokkan tipe-NA untuk kolom pertama)
sumber
Topiknya masih menarik banyak orang (termasuk saya).
Bagaimana dengan itu? Saya dulu
assign
menggantiglovalenv
dan kode yang dijelaskan sebelumnya. Akan lebih baik untuk menangkap lingkungan asli tetapi setidaknya diglobalenv
dalamnya adalah memori yang efisien dan bertindak seperti perubahan oleh ref.sumber
address(DT); delete(DT, 3); address(DT)
), meskipun mungkin efisien dalam beberapa hal.Berikut adalah beberapa strategi yang saya gunakan. Saya percaya fungsi .ROW mungkin akan datang. Tidak satu pun dari pendekatan di bawah ini yang cepat. Ini adalah beberapa strategi yang sedikit melampaui himpunan bagian atau penyaringan. Saya mencoba berpikir seperti dba hanya mencoba untuk membersihkan data. Seperti disebutkan di atas, Anda dapat memilih atau menghapus baris dalam data.tabel:
Catatan: .SD membuat subset dari data asli dan memungkinkan Anda untuk melakukan sedikit pekerjaan di j atau data berikutnya. Lihat https://stackoverflow.com/a/47406952/305675 . Di sini saya memesan iris saya dengan Sepal Length, ambil Sepal yang ditentukan. Panjang minimum, pilih tiga teratas (dengan Sepal Length) dari semua Spesies dan kembalikan semua data yang menyertainya:
Pendekatan di atas semua menyusun ulang data.tabel berurutan saat menghapus baris. Anda dapat mengubah posisi suatu data. Tabel dan menghapus atau mengganti baris lama yang sekarang kolom ditransposisikan. Saat menggunakan ': = NULL' untuk menghapus baris yang dialihkan, nama kolom selanjutnya juga dihapus:
Ketika Anda mengubah data.frame kembali ke data.table, Anda mungkin ingin mengubah nama dari data asli.tabel dan mengembalikan atribut kelas dalam kasus penghapusan. Menerapkan ": = NULL" ke data.table yang sekarang diubah membuat semua kelas karakter.
Anda mungkin hanya ingin menghapus duplikat baris yang dapat Anda lakukan dengan atau tanpa Kunci:
Dimungkinkan juga untuk menambahkan penghitung tambahan dengan '.I'. Anda kemudian dapat mencari kunci atau bidang yang digandakan dan menghapusnya dengan menghapus catatan dengan penghitung. Ini mahal secara komputasi, tetapi memiliki beberapa keuntungan karena Anda dapat mencetak garis yang akan dihapus.
Anda juga bisa mengisi baris dengan 0s atau NAS dan kemudian menggunakan kueri untuk menghapusnya:
sumber
t
pada data.frame biasanya bukan ide yang baik; periksastr(m_iris)
untuk melihat bahwa semua data telah menjadi string / karakter. Btw, Anda juga bisa mendapatkan nomor baris dengan menggunakand_iris[duplicated(Key), which = TRUE]
tanpa membuat kolom penghitung.