Когда мне нужно отфильтровать data.frame, т.е. извлечь строки, которые удовлетворяют определенным условиям, я предпочитаю использовать subset
функцию:
subset(airquality, Month == 8 & Temp > 90)
Вместо [
функции:
airquality[airquality$Month == 8 & airquality$Temp > 90, ]
Есть две основные причины моего предпочтения:
Я считаю, что код читается лучше, слева направо. Даже люди, которые ничего не знают о R, могут сказать, что
subset
делает приведенное выше утверждение.Поскольку в
select
выражении столбцы могут называться переменными , я могу сохранить несколько нажатий клавиш. В приведенном выше примере мне нужно было набратьairquality
только один разsubset
, но три раза[
.
Так что я жил счастливым, использовал subset
везде, потому что он короче и лучше читается, даже отстаивая его красоту среди моих коллег-программистов. Но вчера мой мир распался. Читая subset
документацию, я замечаю этот раздел:
Предупреждение
Это удобная функция, предназначенная для интерактивного использования. Для программирования лучше использовать стандартные функции подмножеств, такие как [, и, в частности, нестандартная оценка подмножества аргументов может иметь непредвиденные последствия.
Может ли кто-нибудь помочь уточнить, что авторы имеют в виду?
Во-первых, что они подразумевают под « для интерактивного использования »? Я знаю, что такое интерактивный сеанс, в отличие от сценария, запускаемого в режиме BATCH, но я не понимаю, какое это должно иметь значение.
Тогда, не могли бы вы объяснить « нестандартную оценку подмножества аргументов » и почему это опасно, может быть, привести пример?
with(airquality, airquality[Month == 8 & Temp > 90, ])
dplyr::filter
есть такая же проблема. Т.е. если в среде есть переменная с таким именем, она будет использовать ее вместо переменной во фрейме данных. Делает для запутанной отладки!Ответы:
На этот вопрос хорошо ответили в комментариях @James, указывая на превосходное объяснение Хэдли Уикхемом опасности
subset
(и подобных ей функций) [здесь] . Иди прочти это!Это довольно длинное чтение, поэтому может быть полезно записать здесь пример, который использует Хэдли, который самым непосредственным образом решает вопрос «что может пойти не так?»:
Хэдли предлагает следующий пример: предположим, что мы хотим поместить в подмножество, а затем переупорядочить фрейм данных, используя следующие функции:
Это возвращает ошибку:
потому что R больше не «знает», где найти объект с именем «cyl». Он также указывает на действительно странные вещи, которые могут произойти, если случайно в глобальной среде появится объект с именем 'cyl':
(Запустите их и убедитесь сами, это довольно безумно.)
источник
subset(mtcars, cyl == 4)
(на верхнем уровне), где R ищет цил? Если он смотрит наmtcars
объект, который передаетсяsubset()
, то не должен ли он быть в состоянии найти,cyl
даже еслиscramble
находится в другой функции, такmtcars
как он все еще передается ему? Если мой вопрос не имеет смысла, вы можете подробнее рассказать о том, почему R больше не может найтиcyl
. Спасибо!subset.data.frame
, вещь, которую мы пытаемся оценить в этот момент, простоcondition
. Это не существует вmtcars
. Такsubset.data.frame
использует,enclos = parent.frame()
чтобы убедиться, чтоcondition
правильно оценивается какcyl == 4
. Но потом мы вернулись обратно к рамке, и теперь, когда R ищетcyl
его, он больше не заглядывает внутрьmtcars
. Если бы мы не использовалиenclos
, что-то вродеsubset(mtcars,cyl == a)
не сработало бы вообще.subset.data.frame
являетсяx[r, vars, drop = drop]
. Проблема в том, как перейти от не заключенных в кавычкиsubset
иselect
аргументов к чему-то, что вы можете достоверно передать[.data.frame
.[]
?И
[
скорее:источник
subset
отличие от[
удаления строк, в которых оценивается фильтрNA
. Сделайте это, и вы увидите, что они оба такие же быстрые, если сравнивать их «довольно»:x <- do.call(rbind, rep(list(airquality), 100)); microbenchmark(subset(x, Month == 8 & Temp > 90),{ i <- x$Month == 8 & x$Temp > 90; x[!is.na(i) & i ,] })