Şunları kullanarak birden çok sütun atayın: = data.table içinde, gruba göre


130

Kullanarak birden çok sütuna atamanın en iyi yolu nedir data.table? Örneğin:

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

Bunun gibi bir şey yapmak istiyorum (elbette bu sözdizimi yanlış):

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

Ve bunu genişletmek için, bir değişkende saklanan isimleri olan birçok sütunum olabilir (diyelim ki col_names) ve şunu yapmak istiyorum:

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

Böyle bir şeyi yapmanın doğru yolu nedir?


1
Yanıtlanmış gibi görünüyor: stackoverflow.com/questions/11308754/…
Alex

Alex, Bu cevap yakın ama by@Christoph_J ile birlikte işe yaramıyor gibi görünüyor demek doğru. Sorunuzun bağlantısı FR # 2120'ye eklendi "LHS için = FALSE ile ihtiyacı bırakın: =", böylece tekrar ziyaret etmeyi unutmayacaksınız.
Matt Dowle 08

Açık olmak gerekirse f(), sütunlarınızın her biri için birden çok değer döndüren bir işlevdir.
smci

Yanıtlar:


161

Bu artık R-Forge'da v1.8.3'te çalışıyor. Vurguladığınız için teşekkürler!

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

withArgümanı kullanan daha eski versiyon (mümkün olduğunda bu argümanı önermiyoruz):

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

Bu cevap ve örnekler için teşekkürler. İki satırlı bir sütun yerine her bir objectName için iki sütun almak için aşağıdaki satırı nasıl değiştirmeliyim? data.table(objectName=ls())[,c("rows","cols"):=dim(get(objectName)),by=objectName]( data.table1.8.11 kullanıyorum )
dnlbrky

@dnlbrky dimbir vektör döndürür, bu yüzden bunu türe dönüştürmek listonu döndürmelidir; ör [,c("rows","cols"):=as.list(dim(get(objectName))),by=objectNa‌​me]. Sorun, as.listçağrı ek yüküne sahip olması ve aynı zamanda küçük vektörü kopyalamasıdır. Grup sayısı arttıkça verimlilik sorun oluyorsa lütfen bize bildirin.
Matt Dowle

1
Merhaba Matt. İkinci kod bloğunuzdaki (yani x[,mynames:=list(mean(b)*4,sum(b)*3),by=a,with=FALSE][]) ilk örnek şimdi bir uyarı atıyor, bu yüzden belki kaldırılsın mı? İlgili bir kayda göre, biri aslında çalışması gerektiği options(datatable.WhenJisSymbolThenCallingScope=TRUE)gibi bir ödevle önerdi x[,mynames:=list(mean(b)*4,sum(b)*3),by=a]mi? Bu, diğer değişikliklerle tutarlı olacak gibi görünüyor, ancak çok fazla mevcut kullanıcı kodunu (?) Kırabileceğini tahmin ediyorum.
Josh O'Brien

1
@PanFrancisco Onsuz by=aişe yarayacak, ancak farklı bir yanıt döndürecektir. mean(a)Ve sum(a)agregalar, her grup içinde geridönüştürülerek by=a. Onsuz by=asadece meanve sumtüm sütun için her hücreye (yani farklı sayılar) yapıştırır .
Matt Dowle

1
@MattDowle, ya işlevim zaten adlandırılmış liste döndürürse, sütunları yeniden adlandırmak zorunda kalmadan dt'ye ekleyebilir miyim? örneğin f <- function (x) {list ("c" = "hi", "d" = "merhaba")} sonuçları x [, f (), by = a] [] ile adlandırılmış sütunlarla yazdıracaktır. Sonucu dt'ye nasıl ekleyeceğimi bilmiyorum.
Jfly

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.