2014-11-29 2 views
12

У меня есть фрейм данных и вы хотите отфильтровать его одним из двух способов, по столбцу «this» или столбцу «that». Я хотел бы иметь возможность ссылаться на имя столбца как на переменную. Как (в dplyr, если это имеет значение) ссылаюсь ли я на имя столбца переменной?Фильтровать фрейм данных по имени столбца символа (в dplyr)

library(dplyr) 
df <- data.frame(this = c(1, 2, 2), that = c(1, 1, 2)) 
df 
# this that 
# 1 1 1 
# 2 2 1 
# 3 2 2 
df %>% filter(this == 1) 
# this that 
# 1 1 1 

Но сказать, что я хочу использовать переменную column держать либо «это» или «что», а фильтр на независимо от значения column есть. Оба as.symbol и get работают в других контекстах, но не в этом:

column <- "this" 
df %>% filter(as.symbol(column) == 1) 
# [1] this that 
# <0 rows> (or 0-length row.names) 
df %>% filter(get(column) == 1) 
# Error in get("this") : object 'this' not found 

Как я могу превратить значение column в имени столбца?

+0

Почему вы хотите это сделать? Попытка параметризировать выбор переменной? – smci

+3

У меня есть набор данных с двумя типами вещей в нем и разными столбцами для каждого. Я хочу подойти к этому так, потому что я использую Shiny для интерактивной визуализации, и я хочу, чтобы люди выбирали, к какому типу вещей нужно смотреть, но затем используйте тот же код для извлечения данных, передавая их в имени столбца по их выбору. – wdenton

+0

Почти отправил мой вопрос и нашел это :) – biocyberman

ответ

21

Я бы избежал использования get() все вместе. Похоже, в этой ситуации это было бы очень опасно, особенно если вы программируете. Вы можете использовать либо неоплаченный вызов, либо вставную строку символов, но вам нужно будет использовать filter_() вместо filter().

df <- data.frame(this = c(1, 2, 2), that = c(1, 1, 2)) 
column <- "this" 

Вариант 1 - с помощью невычисленного вызова:

Вы можете жестко закодировать y, как 1, но здесь я показываю как y, чтобы показать, как вы можете изменить значение выражения легко.

expr <- lazyeval::interp(quote(x == y), x = as.name(column), y = 1) 
## or 
## expr <- substitute(x == y, list(x = as.name(column), y = 1)) 
df %>% filter_(expr) 
# this that 
# 1 1 1 

Вариант 2 - с помощью paste() (и, очевидно, проще):

df %>% filter_(paste(column, "==", 1)) 
# this that 
# 1 1 1 

Главное об этих двух вариантов является то, что мы должны использовать filter_() вместо filter(). Фактически, из того, что я прочитал, если вы программируете с помощью dplyr, вы всегда должны использовать функции *_().

Я использовал это сообщение как полезную ссылку: character string as function argument r, и я использую dplyr версии 0.3.0.2.

+1

Вариант 1 - это надежное решение, рекомендованное @hadley в нескольких сообщениях на SO и в виньетке («nse»). Тем не менее, похоже, что это противоречит стилю элегантных функций. Не может ли это быть обернуто и представлено более простым способом? – biocyberman

+0

Почему get() считается опасным? – pluke

+0

Это хороший ответ для более старых версий 'dpylr', но функции подчеркивания устаревают, поэтому ответ Салима-Б ниже будет лучше идти вперед. – Elin

5

Что касается решения Ричарда, просто хочу добавить, что если столбец является символом. Вы можете добавить shQuote для фильтрации по символьным значениям.

Например, вы можете использовать

df %>% filter_(paste(column, "==", shQuote("a"))) 

Если у вас есть несколько фильтров, вы можете указать collapse = "&" в paste.

df %>$ filter_(paste(c("column1","column2"), "==", shQuote(c("a","b")), collapse = "&")) 
4

Из текущего файла dplyr помощи (курсив мной):

dplyr используется, чтобы предложить двойные версии каждого глагола с суффиксом подчеркиванием. Эти версии имели семантику стандартной оценки (SE): вместо того, чтобы принимать аргументы с помощью кода, например глаголы NSE, они принимали аргументы по значению. Их цель состояла в том, чтобы дать возможность программировать с dplyr. Тем не менее, dplyr теперь использует аккуратную семантику оценки.Глаголы NSE по-прежнему фиксируют свои аргументы, но теперь вы можете недооценивать части этих аргументов. Это обеспечивает полную программируемость с помощью глаголов NSE. Таким образом, подчеркнутые версии теперь излишни.

Что unquoting именно средства могут быть изучены в виньетка Programming with dplyr. Это достигается с помощью функции UQ() или как syntactic sugar от !!. Теперь есть ситуации - как и ваши, где только первые правильно работают, потому что !! может столкнуться с одним !.

Применительно к вашему примеру:

library(dplyr) 
df <- data.frame(this = c(1, 2, 2), 
       that = c(1, 1, 2)) 
column <- "this" 

df %>% filter(UQ(as.name(column)) == 1) 
# this that 
# 1 1 1 

Но не:

df %>% filter(!!as.name(column) == 1) 
# [1] this that 
# <0 Zeilen> (oder row.names mit Länge 0) 
+1

В последнем случае вы можете использовать некоторые дополнительные круглые скобки 'df%>% filter ((!! as.name (column)) == 1)' –

0

Как Салим B объяснено выше, но с небольшим изменением:

df %>% filter(1 == !!as.name(column)) 

т.е. просто передачи заднего хода состояние, потому что !! иначе beha %

!!(as.name(column)==1) 
Смежные вопросы