Tetapkan beberapa kolom menggunakan: = dalam data.table, berdasarkan grup


130

Apa cara terbaik untuk menggunakan beberapa kolom data.table? Sebagai contoh:

f <- function(x) {c("hi", "hello")}
x <- data.table(id = 1:10)

Saya ingin melakukan sesuatu seperti ini (tentu saja sintaks ini salah):

x[ , (col1, col2) := f(), by = "id"]

Dan untuk memperluas itu, saya mungkin memiliki banyak kolom dengan nama yang disimpan dalam variabel (katakanlah col_names) dan saya ingin melakukan:

x[ , col_names := another_f(), by = "id", with = FALSE]

Apa cara yang benar untuk melakukan sesuatu seperti ini?


1
Ini sepertinya sudah dijawab: stackoverflow.com/questions/11308754/…
Alex

Alex, Jawaban itu dekat tetapi tampaknya tidak bekerja bersama- bysama dengan @Christoph_J benar untuk mengatakan. Tautkan ke pertanyaan Anda yang ditambahkan ke FR # 2120 "Drop needing with = FALSE for LHS of: =", sehingga tidak akan lupa untuk mengunjungi kembali.
Matt Dowle

Agar jelas, f()adalah fungsi yang mengembalikan beberapa nilai, satu untuk setiap kolom Anda.
smci

Jawaban:


161

Ini sekarang bekerja di v1.8.3 pada R-Forge. Terima kasih telah menyorotnya!

x <- data.table(a = 1:3, b = 1:6) 
f <- function(x) {list("hi", "hello")} 
x[ , c("col1", "col2") := f(), by = a][]
#    a b col1  col2
# 1: 1 1   hi hello
# 2: 2 2   hi hello
# 3: 3 3   hi hello
# 4: 1 4   hi hello
# 5: 2 5   hi hello
# 6: 3 6   hi hello

x[ , c("mean", "sum") := list(mean(b), sum(b)), by = a][]
#    a b col1  col2 mean sum
# 1: 1 1   hi hello  2.5   5
# 2: 2 2   hi hello  3.5   7
# 3: 3 3   hi hello  4.5   9
# 4: 1 4   hi hello  2.5   5
# 5: 2 5   hi hello  3.5   7
# 6: 3 6   hi hello  4.5   9 

mynames = c("Name1", "Longer%")
x[ , (mynames) := list(mean(b) * 4, sum(b) * 3), by = a]
#     a b col1  col2 mean sum Name1 Longer%
# 1: 1 1   hi hello  2.5   5    10      15
# 2: 2 2   hi hello  3.5   7    14      21
# 3: 3 3   hi hello  4.5   9    18      27
# 4: 1 4   hi hello  2.5   5    10      15
# 5: 2 5   hi hello  3.5   7    14      21
# 6: 3 6   hi hello  4.5   9    18      27


x[ , get("mynames") := list(mean(b) * 4, sum(b) * 3), by = a][]  # same
#    a b col1  col2 mean sum Name1 Longer%
# 1: 1 1   hi hello  2.5   5    10      15
# 2: 2 2   hi hello  3.5   7    14      21
# 3: 3 3   hi hello  4.5   9    18      27
# 4: 1 4   hi hello  2.5   5    10      15
# 5: 2 5   hi hello  3.5   7    14      21
# 6: 3 6   hi hello  4.5   9    18      27

x[ , eval(mynames) := list(mean(b) * 4, sum(b) * 3), by = a][]   # same
#    a b col1  col2 mean sum Name1 Longer%
# 1: 1 1   hi hello  2.5   5    10      15
# 2: 2 2   hi hello  3.5   7    14      21
# 3: 3 3   hi hello  4.5   9    18      27
# 4: 1 4   hi hello  2.5   5    10      15
# 5: 2 5   hi hello  3.5   7    14      21
# 6: 3 6   hi hello  4.5   9    18      27

Versi yang lebih lama menggunakan withargumen (kami mencegah argumen ini bila memungkinkan):

x[ , mynames := list(mean(b) * 4, sum(b) * 3), by = a, with = FALSE][] # same
#    a b col1  col2 mean sum Name1 Longer%
# 1: 1 1   hi hello  2.5   5    10      15
# 2: 2 2   hi hello  3.5   7    14      21
# 3: 3 3   hi hello  4.5   9    18      27
# 4: 1 4   hi hello  2.5   5    10      15
# 5: 2 5   hi hello  3.5   7    14      21
# 6: 3 6   hi hello  4.5   9    18      27

Terima kasih atas jawaban dan contohnya. Bagaimana saya harus memodifikasi baris berikut untuk mendapatkan dua kolom untuk setiap objectName dari keluaran redup, daripada satu kolom dengan dua baris? data.table(objectName=ls())[,c("rows","cols"):=dim(get(objectName)),by=objectName](Saya menggunakan data.table1.8.11)
dnlbrky

@ dnlbrky dimmengembalikan vektor sehingga mengonversi itu untuk mengetik listharus memutarnya; mis [,c("rows","cols"):=as.list(dim(get(objectName))),by=objectNa‌​me]. Masalahnya adalah yang as.listmemiliki panggilan overhead dan juga menyalin vektor kecil. Jika efisiensi menjadi masalah karena jumlah grup meningkat maka beri tahu kami.
Matt Dowle

1
Hai Matt. Contoh pertama di blok kode kedua Anda (yaitu x[,mynames:=list(mean(b)*4,sum(b)*3),by=a,with=FALSE][]) sekarang melempar peringatan, jadi mungkin menghapusnya? Pada catatan terkait, adakah yang menyarankan agar, dengan options(datatable.WhenJisSymbolThenCallingScope=TRUE), penugasan seperti x[,mynames:=list(mean(b)*4,sum(b)*3),by=a]apakah sebenarnya berhasil? Sepertinya itu akan konsisten dengan perubahan lain, meskipun saya kira itu mungkin merusak terlalu banyak kode pengguna yang ada (?).
Josh O'Brien

1
@ PanFrancisco Tanpa by=aitu akan berhasil, tetapi kembalikan jawaban yang berbeda. The mean(a)dan sum(a)agregat sedang didaur ulang dalam setiap kelompok saat by=a. Tanpanya by=ahanya akan menempelkan meandan sumuntuk seluruh kolom ke dalam setiap sel (yaitu angka yang berbeda).
Matt Dowle

1
@MattDowle bagaimana jika fungsi saya sudah mengembalikan daftar bernama, adakah di sana saya dapat menambahkan kolom ke dt tanpa harus menamai mereka lagi? misal f <- function (x) {list ("c" = "hi", "d" = "hello")} akan mencetak hasil dengan nama cols dengan x [, f (), dengan = a] []. Saya tidak tahu bagaimana menambahkan hasilnya ke dt.
Jfly

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.