Призначте кілька стовпців, використовуючи: = у таблиці даних, за групами


130

Який найкращий спосіб призначити кілька колонок за допомогою data.table? Наприклад:

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

Я хотів би зробити щось подібне (звичайно, цей синтаксис є неправильним):

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

І щоб розширити це, у мене може бути багато стовпців із іменами, що зберігаються у змінній (скажімо col_names), і я хотів би зробити:

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

Який правильний спосіб зробити щось подібне?


1
Схоже, на нього відповіли: stackoverflow.com/questions/11308754/…
Алекс

Алекс, ця відповідь близька, але, схоже, це не працює в поєднанні з тим, byяк @Christoph_J правильно сказати. Посилання на ваше запитання додано до FR # 2120 "Відкиньте потрібне значення = FALSE для LHS: =", тому він не забуде повторно переглянути.
Метт Даул

Щоб було зрозуміло, f()це функція, що повертає кілька значень, по одному для кожного вашого стовпця.
smci

Відповіді:


161

Зараз це працює у версії 1.8.3 на R-Forge. Дякуємо, що виділили це!

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

Старіша версія з використанням withаргументу (ми відмовляємо цей аргумент, коли це можливо):

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

Дякую за цю відповідь та приклади. Як я можу змінити наступний рядок, щоб отримати два стовпці для кожного objectName з тьмяного виводу, а не один стовпчик з двома рядками? data.table(objectName=ls())[,c("rows","cols"):=dim(get(objectName)),by=objectName](Я використовую data.table1.8.11)
dnlbrky

@dnlbrky dimповертає вектор настільки перетворюючи, що для введення його listслід обертати; напр [,c("rows","cols"):=as.list(dim(get(objectName))),by=objectNa‌​me]. Проблема в тому, що as.listмає накладні виклики, а також копіює малий вектор. Якщо ефективність є проблемою, оскільки кількість груп збільшується, то повідомте нас про це.
Метт Даул

1
Привіт Метт. Перший приклад у вашому другому блоці коду (тобто x[,mynames:=list(mean(b)*4,sum(b)*3),by=a,with=FALSE][]) тепер накидає попередження, тож, можливо, видаліть його? У відповідній записці хтось підказав, що, з options(datatable.WhenJisSymbolThenCallingScope=TRUE)таким завданням, як x[,mynames:=list(mean(b)*4,sum(b)*3),by=a]насправді, має працювати? Схоже, це відповідало б іншим змінам, хоча, мабуть, це може зламати занадто багато існуючого коду користувача (?).
Josh O'Brien

1
@PanFrancisco Без by=aцього буде працювати, але поверніть іншу відповідь. Коли mean(a)та sum(a)агрегати переробляються в межах кожної групи, коли by=a. Без by=aцього просто вставляємо meanі sumдля цілого стовпця в кожну комірку (тобто різні цифри).
Метт Даул

1
@MattDowle, що, якщо моя функція вже повертає названий список, чи все-таки я можу додати стовпці до dt, не потребуючи їх знову називати? наприклад, f <- функція (x) {list ("c" = "привіт", "d" = "привіт")} надрукує результати з названими cols з x [, f (), by = a] []. Я не знаю, як додати результат до dt.
Jfly

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.