2012-03-25 6 views
343

Когда мне нужно фильтровать data.frame, то есть извлекать строки, которые удовлетворяют определенным условиям, я предпочитаю использовать subset функцию:Почему `` `` лучше, чем `подмножество`?

subset(airquality, Month == 8 & Temp > 90) 

, а не функцию [:

airquality[airquality$Month == 8 & airquality$Temp > 90, ] 

Там являются двумя основными причинами для моих предпочтений:

  1. Я нахожу, что код читается лучше, слева направо. Даже люди, которые ничего не знают о R, могут сказать, что делает вышеприведенное заявление subset.

  2. Поскольку столбцы можно назвать переменными в выражении select, я могу сэкономить несколько нажатий клавиш. В моем примере выше мне только приходилось вводить airquality один раз с subset, но три раза с [.

Так я жил счастливым, используя subset везде, потому что он короче и читает лучше, даже защищая свою красоту моих коллег кодеров R. Но вчера мой мир развалился. При чтении документации subset, я заметил этот раздел:

Warning

This is a convenience function intended for use interactively. For programming it is better to use the standard subsetting functions like [, and in particular the non-standard evaluation of argument subset can have unanticipated consequences.

Может кто-нибудь помочь уточнить, что означают авторы?

Во-первых, что они означают по «для интерактивного использования»? Я знаю, что такое интерактивный сеанс, в отличие от сценария, запускаемого в режиме BATCH, но я не вижу, какую разницу он должен сделать.

Тогда, не могли бы вы объяснить «нестандартную оценку подмножества аргументов» и почему это опасно, может быть, привести пример?

+12

Это немного меньше (но меньше, чем гайка подмножества) для использования с, 'с (Качество воздуха, Качество воздуха [Месяц == 8 & Temp> 90,])' –

+1

В этом разделе обсуждается 'subset()' warning: http://r.789695.n4.nabble.com/Variable-passed-to-function-not-used-in-function-in-select-in-subset- tt872217.html – jthetzel

+3

Вы также можете взглянуть на Cirlces 8.2.31 и 8.2.32 из «The R Inferno» http://www.burns-stat.com/pages/Tutor/R_inferno.pdf –

ответ

201

Этот вопрос был поставлен под вопрос в комментариях @James, указывая на отличное объяснение Хэдли Уикхэма об опасностях subset (и функционирует как это) [here]. Пойдите, прочитайте это!

Это довольно длинный для чтения, так что это может быть полезно, чтобы записать здесь пример, который использует Hadley, что наиболее непосредственно рассматривается вопрос о том, «что может пойти не так?»:

Hadley предлагает следующий пример: предположим, что мы хочу подмножество, а затем изменить порядок кадр данных, используя следующие функции:

scramble <- function(x) x[sample(nrow(x)), ] 

subscramble <- function(x, condition) { 
    scramble(subset(x, condition)) 
} 

subscramble(mtcars, cyl == 4) 

Это возвращает ошибку:

Error in eval(expr, envir, enclos) : object 'cyl' not found

потому что R не ло nger «знает», где найти объект под названием «цил». Он также указывает на действительно странный материал, который может произойти, если случайно есть объект под названием «цил» в глобальной среде:

cyl <- 4 
subscramble(mtcars, cyl == 4) 

cyl <- sample(10, 100, rep = T) 
subscramble(mtcars, cyl == 4) 

(Выполнить их и посмотреть на себя, это довольно сумасшедшим.)

+2

Могу ли я задать некоторые вопросы для новичков? Когда мы пишем 'subset (mtcars, cyl == 4)' (на верхнем уровне), где R ищет цил? Если он смотрит в объект 'mtcars', который передается' subset() ', тогда он не может найти' cyl', даже если 'scramble' находится в пределах другой функции, так как' mtcars' все еще передается Это? Если мой вопрос не имеет смысла, вы можете просто уточнить, почему R больше не может найти «цил». Благодаря! – Heisenberg

+3

@Anh Внутри 'subset.data.frame' то, что мы пытаемся оценить в этой точке, это просто' условие'. Это не существует в 'mtcars'. Поэтому 'subset.data.frame' использует' enclos = parent.frame() ', чтобы убедиться, что' condition' правильно оценен как 'cyl == 4'. Но потом мы вернулись к рамке, и теперь, когда R ищет «цил», он больше не смотрит внутрь «mtcars». Если мы не использовали 'enclos', нечто вроде' subset (mtcars, cyl == a) 'не будет работать вообще. – joran

+0

Кто-нибудь знает, почему subset() не просто реализует более быстрый и безопасный метод [,] за кулисами? –

20

Также [ быстрее:

require(microbenchmark)   
microbenchmark(subset(airquality, Month == 8 & Temp > 90),airquality[airquality$Month == 8 & airquality$Temp > 90,]) 
    Unit: microseconds 
                  expr  min  lq median  uq  max neval 
        subset(airquality, Month == 8 & Temp > 90) 301.994 312.1565 317.3600 349.4170 500.903 100 
    airquality[airquality$Month == 8 & airquality$Temp > 90, ] 234.807 239.3125 244.2715 271.7885 340.058 100 
+26

Да и нет. Я думаю, что разница во времени, которую вы видите, объясняется двумя вещами. 1) небольшие (<100 микросекунд) служебные данные и 2) 'подмножество' в отличие от' ['удаляет строки, где фильтр оценивается как' NA'. Сделайте это, и вы увидите, что они так же быстро сравниваются «честно»: 'x <- do.call (rbind, rep (список (airquality), 100)); microbenchmark (subset (x, Month == 8 & Temp> 90), {i <- x $ Month == 8 & x $ Temp> 90; x [! is.na (i) & i,]}) ' – flodel

Смежные вопросы