Подстановка data.table переменной (когда varname идентично colname)

Как я могу подмножить таблицу данных с помощью переменной, если имя переменной идентично существующему имени столбца в таблице данных? Он работает с get("varname",pos = 1), но есть ли более надежное/гибкое решение?

library(data.table)

my_data_frame <- data.frame(
"V1"=c("A","B","C","A"),
"V2"=c(1, 2, 3, 4),
stringsAsFactors = FALSE        
)

V1 <- "A"

my_data_table <- as.data.table(my_data_frame)

# Can I improve this a bit? I want rows where V1 == "A", but use V1 in the statement 
my_data_table[ my_data_table$V1 == get("V1", pos = 1), ]

Переименование V1 не вариант.

ОБНОВЛЕНИЕ: я не считаю это 100% дубликатом. Принятый ответ на этот вопрос неприемлем для моего вопроса, поскольку он использует явное get, которое я не хочу использовать, как указано в комментариях.


person nilsole    schedule 24.09.2018    source источник
comment
Я не понимаю, что не так с my_data_table[,"V1"=="A"] или my_data_table[,"V1"==V1]?   -  person user2974951    schedule 24.09.2018
comment
@user2974951 user2974951 Спасибо, но ваши решения не дают желаемого результата, так как вы не используете синтаксис data.table. Желаемый результат имеет две строки.   -  person nilsole    schedule 24.09.2018
comment
Я не хочу явно указывать уровень окружения (pos = 1), как это сделано в примере. Вместо этого я хотел бы заставить R искать внешний объект с именем V1, а не использовать V1 в качестве имени столбца. Приведенный выше код работает, но не обязательно будет работать, если я скопирую код в другую область.   -  person nilsole    schedule 24.09.2018
comment
Возможно, немного неортодоксально выполнять поднабор строк в j, но тогда мы можем использовать 'точка-точка': d[ , d[V1 == ..V1]]   -  person Henrik    schedule 24.09.2018
comment
Другой вариант — указать среду: my_data_table[V1 == get("V1", envir = .GlobalEnv)]   -  person Jaap    schedule 24.09.2018
comment
@ Хенрик Попробовал ваш пример, но он дает мне Error in eval (expr, envir, enclos): object '..V1' not found   -  person nilsole    schedule 24.09.2018
comment
Это работает здесь (я просто использовал более короткое d в качестве имени набора данных). У вас data.table версия ›= v1.10.2?   -  person Henrik    schedule 24.09.2018
comment
@ Хенрик Правильно, очень хороший ответ только для данных.   -  person nilsole    schedule 24.09.2018
comment
другая альтернатива, похожая на Хенрика: d[d[, .I[V1 == ..V1]]]   -  person chinsoon12    schedule 24.09.2018
comment
связанные: stackoverflow.com/q/32738499/4137985   -  person Cath    schedule 24.09.2018
comment
Возможный дубликат назначений data.table := когда переменная имеет то же имя, что и столбец   -  person h3rm4n    schedule 24.09.2018


Ответы (3)


Если вы не против сделать это за 2 шага, вы можете просто выделить подмножество из области вашего data.table (хотя обычно это не то, что вы хотите делать при работе с data.table...):

wh_v1 <- my_data_table[, V1]==V1
my_data_table[wh_v1]
#   V1 V2
#1:  A  1
#2:  A  4
person Cath    schedule 24.09.2018
comment
Ваш ответ мой любимый, как и ответ @Henrik. - person nilsole; 24.09.2018

Вот решение с использованием library(tidyverse):

library(data.table)
library(tidyverse)
my_data_frame <- data.frame(
  "V1"=c("A","B","C","A"),
  "V2"=c(1, 2, 3, 4),
  stringsAsFactors = FALSE        
)

V1 = "A"
my_data_table <- as.data.table(my_data_frame)
df = my_data_table %>% filter(V1 == !!get("V1")) #you do not have to specify pos = 1

Если вы хотите, чтобы R использовал объект с именем «V1», вы можете сделать это

V1 = "A"
list_test = split(my_data_table, as.factor(my_data_table$V1)) #create a list for each factor level of the column V1.
df = list_test[[V1]] #extract the desired dataframe from the list using the object "V1"

Это то, что вы хотите?

person Paul    schedule 24.09.2018
comment
Здесь все правильно, но, возможно, вы могли бы дать аккуратное решение для конфликта имен V1, так как это кажется сутью проблемы здесь. - person Axeman; 24.09.2018
comment
Спасибо за ваше предложение. Я не уверен, что полностью понимаю, как tidyverse может помочь справиться с конфликтом имен. dplyr::filter использует только столбец фрейма данных V1. Это позволяет избежать конфликта имен, устраняя необходимость в объекте V1. Но я, хотя этот объект был необходим, поэтому я написал второе решение с base::split, которое позволяет без каких-либо сомнений использовать объект V1 и столбец фрейма данных V1. Кроме того, объект list_test очень удобен для работы с lapply() и пользовательскими функциями. - person Paul; 24.09.2018
comment
Другими словами, можете ли вы написать оператор filter таким образом, чтобы гарантированно использовалась глобальная переменная вместо имени столбца? (Как и нотация data.table ...) Для общего случая? Я знаю, что можно написать .data$ для противоположного, но я не уверен, как заставить область видимости находиться за пределами data.frame. - person Axeman; 24.09.2018
comment
Я нашел это: V1 = "A" my_data_table <- as.data.table(my_data_frame) df = my_data_table %>% filter(V1 == !!get("V1")) вдохновленный этим постом "> stackoverflow.com/questions/34219912/ - person Paul; 24.09.2018

Для условий равенства вы можете использовать соединение:

mDT = data.table(V1)
my_data_table[mDT, on=.(V1), nomatch=0]
#    V1 V2
# 1:  A  1
# 2:  A  4

Неявно условие соединения в x[i, on=.(V1)] равно

V1 == V1

где левая часть исходит из x, а правая часть из i. Это похоже на поиск каждой строки i в x. nomatch=0 означает, что любое значение, найденное в i, но не в x, удаляется из вывода... например

mDT2 = data.table(V1 = c("A", "D"))
my_data_table[mDT2, on=.(V1)]
#    V1 V2
# 1:  A  1
# 2:  A  4
# 3:  D NA

my_data_table[mDT2, on=.(V1), nomatch=0]
#    V1 V2
# 1:  A  1
# 2:  A  4
person Frank    schedule 24.09.2018