Уровни коэффициента отбрасывания в заданном кадре данных

У меня есть фрейм данных, содержащий фактор. Когда я создаю подмножество этого фрейма данных, используя subset() или другую функцию индексации, создается новый фрейм данных. Тем не менее, переменная фактора сохраняет все свои исходные уровни - даже если они не существуют в новом фрейме данных.

Это создает головную боль при выполнении граненых графиков или при использовании функций, основанных на факторных уровнях.

Какой самый краткий способ удалить уровни из фактора в моем новом фрейме данных?

Вот мой пример:

df <- data.frame(letters=letters[1:5],
                    numbers=seq(1:5))

levels(df$letters)
## [1] "a" "b" "c" "d" "e"

subdf <- subset(df, numbers <= 3)
##   letters numbers
## 1       a       1
## 2       b       2
## 3       c       3    

## but the levels are still there!
levels(subdf$letters)
## [1] "a" "b" "c" "d" "e"
491
задан divibisan 5 September 2018 в 18:14
поделиться

7 ответов

Все, что вам нужно сделать, это снова применить factor () к вашей переменной после подмножества:

> subdf$letters
[1] a b c
Levels: a b c d e
subdf$letters <- factor(subdf$letters)
> subdf$letters
[1] a b c
Levels: a b c

EDIT

Из примера страницы факторов:

factor(ff)      # drops the levels that do not occur

Для удаления уровней из всех столбцы фактора в кадре данных, вы можете использовать:

subdf <- subset(df, numbers <= 3)
subdf[] <- lapply(subdf, function(x) if(is.factor(x)) factor(x) else x)
393
ответ дан 22 November 2019 в 22:33
поделиться

Попробовали большинство примеров здесь, если не все ни кроме одного, кажется, работают в моем случае. После борьбы в течение достаточно долгого времени я попытался использовать as.character () на факторном столбце для изменения его на седло со строками, которое кажется тому, чтобы работать просто великолепно.

Не уверенный для проблем производительности.

0
ответ дан 22 November 2019 в 22:33
поделиться

Это известная проблема, и предлагается одно возможное решение от drop.levels () в пакете gdata , где ваш пример становится

> drop.levels(subdf)
  letters numbers
1       a       1
2       b       2
3       c       3
> levels(drop.levels(subdf)$letters)
[1] "a" "b" "c"

. Также есть функция dropUnusedLevels в Hmisc пакет. Однако он работает только путем изменения оператора подмножества [ и здесь не применим.

Как следствие, прямой подход на основе каждого столбца представляет собой простой as.factor (as .character (data)) :

> levels(subdf$letters)
[1] "a" "b" "c" "d" "e"
> subdf$letters <- as.factor(as.character(subdf$letters))
> levels(subdf$letters)
[1] "a" "b" "c"
35
ответ дан 22 November 2019 в 22:33
поделиться

Это неприятно. Я обычно делаю это так, чтобы не загружать другие пакеты:

levels(subdf$letters)<-c("a","b","c",NA,NA)

, что дает вам:

> subdf$letters
[1] a b c
Levels: a b c

Обратите внимание, что новые уровни заменят все, что занимает их индекс на старых уровнях (subdf $ письма), поэтому что-то вроде:

levels(subdf$letters)<-c(NA,"a","c",NA,"b")

не сработает.

Очевидно, это не идеально, когда у вас много уровней, но для некоторых это быстро и легко.

6
ответ дан 22 November 2019 в 22:33
поделиться

Если вам не нужно такое поведение, не используйте множители, вместо этого используйте векторы символов. Я думаю, что в этом больше смысла, чем исправлять вещи потом. Попробуйте выполнить следующее перед загрузкой данных с помощью read.table или read.csv :

options(stringsAsFactors = FALSE)

Недостатком является то, что вы ограничены алфавитным порядком. (повторный заказ - ваш друг для участков)

40
ответ дан 22 November 2019 в 22:33
поделиться

Вот еще один способ, который, как мне кажется, эквивалентен подходу с коэффициентом (..) :

> df <- data.frame(let=letters[1:5], num=1:5)
> subdf <- df[df$num <= 3, ]

> subdf$let <- subdf$let[ , drop=TRUE]

> levels(subdf$let)
[1] "a" "b" "c"
13
ответ дан 22 November 2019 в 22:33
поделиться

Для этого я написал служебные функции. Теперь, когда я знаю о drop.levels в gdata, он выглядит очень похоже. Вот они (из здесь ):

present_levels <- function(x) intersect(levels(x), x)

trim_levels <- function(...) UseMethod("trim_levels")

trim_levels.factor <- function(x)  factor(x, levels=present_levels(x))

trim_levels.data.frame <- function(x) {
  for (n in names(x))
    if (is.factor(x[,n]))
      x[,n] = trim_levels(x[,n])
  x
}
5
ответ дан 22 November 2019 в 22:33
поделиться
Другие вопросы по тегам:

Похожие вопросы: