Переопределите [.data.frame, чтобы удалить неиспользуемые уровни факторов по умолчанию

Возникла проблема отбрасывания неиспользуемых уровней факторов при разбиении на подмножества раньше. Общие решения включают использование векторов символов, где это возможно, путем объявления

options(stringsAsFactors = FALSE)

Однако иногда для построения графика необходимы упорядоченные коэффициенты, и в этом случае мы можем использовать вспомогательные функции, такие как droplevels, чтобы создать оболочку для subset:

subsetDrop <- function(...){droplevels(subset(...))}

Я понимаю, что subsetDrop в основном решает эту проблему, но есть ситуации, когда подмножество через [ более удобно (и меньше печатать!).

Мой вопрос в том, насколько дальше, ради удобства, мы можем сделать так, чтобы это было «стандартным» поведением R, переопределив [ для фреймов данных, чтобы автоматически понижать уровни факторов. Например, пакет Hmisc содержит dropUnusedLevels, который переопределяет [.factor для подмножества одного фактора (в котором больше нет необходимости, поскольку значение по умолчанию [.factor, похоже, имеет drop аргумент для удаления неиспользуемых уровней). Я ищу аналогичное решение, которое позволило бы мне разбивать фреймы данных с использованием [, но автоматически отбрасывать неиспользуемые уровни факторов (и, конечно, сохранять порядок в случае упорядоченных факторов).


person joran    schedule 18.06.2011    source источник
comment
Упорядоченные факторы почти никогда не нужны для построения графика. Изменение порядка уровней часто лежит в основе трудностей построения графика. Упорядочение факторов сильно отличается от изменения порядка уровней факторов.   -  person IRTFM    schedule 12.12.2013


Ответы (3)


Я бы очень осторожно менял поведение по умолчанию; вы никогда не знаете, когда другая функция, которую вы используете, зависит от обычного поведения по умолчанию. Вместо этого я бы написал аналогичную функцию для вашего subsetDrop, но для [, например

sel <- function(x, ...) droplevels(x[...])

потом

> d <- data.frame(a=factor(LETTERS[1:5]), b=factor(letters[1:5]))
> str(d[1:2,])
'data.frame':   2 obs. of  2 variables:
 $ a: Factor w/ 5 levels "A","B","C","D",..: 1 2
 $ b: Factor w/ 5 levels "a","b","c","d",..: 1 2
> str(sel(d,1:2,))
'data.frame':   2 obs. of  2 variables:
 $ a: Factor w/ 2 levels "A","B": 1 2
 $ b: Factor w/ 2 levels "a","b": 1 2

Если вы действительно хотите изменить значение по умолчанию, вы можете сделать что-то вроде

foo <- `[.data.frame`
`[.data.frame` <- function(...) droplevels(foo(...))

но убедитесь, что вы знаете, как работают пространства имен, поскольку это будет работать для всего, что вызывается из глобального пространства имен, но версия в базовом пространстве имен не изменяется. Это может быть хорошо, но вы должны убедиться, что понимаете. После этого изменения результат будет таким, как вам хотелось бы.

> str(d[1:2,])
'data.frame':   2 obs. of  2 variables:
 $ a: Factor w/ 2 levels "A","B": 1 2
 $ b: Factor w/ 2 levels "a","b": 1 2
person Aaron left Stack Overflow    schedule 19.06.2011
comment
Спасибо (и +1 за @kohske, который тоже туда попал)! Надо было подумать об использовании, по сути, того же трюка, что и с subset (). И ты прав, конфликтов лучше избегать ... - person joran; 19.06.2011

вы можете сделать эту работу, перезаписав значение по умолчанию аргумента drop следующим образом:

formals(`[.factor`)$drop <- TRUE

ОБНОВИТЬ

что касается data.frame, вы можете:

`[.data.frame` <- function(...)droplevels(base::`[.data.frame`(...))

на самом деле похож на @Aaron.

если вы хотите отменить это поведение, тогда:

rm(`[.data.frame`)

сделаю это.

> d <- data.frame(a=letters[1:10], b=LETTERS[1:10])
> str(d[1:5, ])
'data.frame':   5 obs. of  2 variables:
 $ a: Factor w/ 10 levels "a","b","c","d",..: 1 2 3 4 5
 $ b: Factor w/ 10 levels "A","B","C","D",..: 1 2 3 4 5
> `[.data.frame` <- function(...)droplevels(base::`[.data.frame`(...))
> str(d[1:5, ])
'data.frame':   5 obs. of  2 variables:
 $ a: Factor w/ 5 levels "a","b","c","d",..: 1 2 3 4 5
 $ b: Factor w/ 5 levels "A","B","C","D",..: 1 2 3 4 5
> rm(`[.data.frame`)
> str(d[1:5, ])
'data.frame':   5 obs. of  2 variables:
 $ a: Factor w/ 10 levels "a","b","c","d",..: 1 2 3 4 5
 $ b: Factor w/ 10 levels "A","B","C","D",..: 1 2 3 4 5
person kohske    schedule 19.06.2011
comment
Это меняет поведение по умолчанию для подмножества одного факторного вектора, но (по крайней мере, когда я это пробовал) не имеет никакого эффекта при использовании [ во фрейме данных, содержащем фактор, который я и ищу. - person joran; 19.06.2011

Я думаю, что изменение значения по умолчанию очень опасно, см. Мой ответ здесь.

В большинстве случаев, когда люди озабочены снижением уровней факторов, вам либо действительно не нужно (суммировать то, что вы заставили иметь 1 значение, глупо), либо есть лучший способ выполнить то, что вы пытаетесь. Возможные побочные эффекты от автоматического сброса потенциально хуже, чем пара сохраненных нажатий клавиш. Кроме того, если вы проводите воспроизводимое исследование, вы не должны зависеть от компьютера или даже позволять ему изменять данные без вашего конкретного согласия.

person Greg Snow    schedule 19.06.2011