Уровни фактора падения в подмноженном кадре данных

StackOverflow https://stackoverflow.com/questions/1195826

  •  20-09-2019
  •  | 
  •  

Вопрос

У меня есть кадр данных, содержащий фактор. Когда я создаю подмножество этой кадры данных, используя 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"
Это было полезно?

Решение

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

> 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

РЕДАКТИРОВАТЬ

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

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

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

subdf <- subset(df, numbers <= 3)
subdf[] <- lapply(subdf, function(x) if(is.factor(x)) factor(x) else x)

Другие советы

С версией R 2.12, есть droplevels() функция

levels(droplevels(subdf$letters))

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

options(stringsAsFactors = FALSE)

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

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

> 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"

Другой способ сделать то же самое, но с dplyr

library(dplyr)
subdf <- df %>% filter(numbers <= 3) %>% droplevels()
str(subdf)

Редактировать:

Также работает! Благодаря Агенис

subdf <- df %>% filter(numbers <= 3) %>% droplevels
levels(subdf$letters)

Ради полноты, теперь есть также fct_drop в forcats упаковка http://forcats.tidyverse.org/reference/fct_drop.html.

Это отличается от droplevels в том, как это касается NA:

f <- factor(c("a", "b", NA), exclude = NULL)

droplevels(f)
# [1] a    b    <NA>
# Levels: a b <NA>

forcats::fct_drop(f)
# [1] a    b    <NA>
# Levels: a b

Вот еще один способ, который, я считаю, эквивалентен factor(..) подход:

> 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"

Глядя на droplevels методы Код в источнике R вы можете увидеть это оборачивается factor функция Это означает, что вы можете в основном воссоздать колонку factor функция
Ниже данные. ТАБЛИЧНЫЙ СПОСОБ ОТКРЫТИЯ С ВАШИХ столбцов Фактора.

library(data.table)
dt = data.table(letters=factor(letters[1:5]), numbers=seq(1:5))
levels(dt$letters)
#[1] "a" "b" "c" "d" "e"
subdt = dt[numbers <= 3]
levels(subdt$letters)
#[1] "a" "b" "c" "d" "e"

upd.cols = sapply(subdt, is.factor)
subdt[, names(subdt)[upd.cols] := lapply(.SD, factor), .SDcols = upd.cols]
levels(subdt$letters)
#[1] "a" "b" "c"

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

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

Что вызывает вас:

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

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

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

не будет работать.

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

Я написал функции утилиты для этого. Теперь, когда я знаю о Gdata's Drop.Levels, это выглядит довольно похоже. Вот они (от здесь):

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
}

Вот способ сделать это

varFactor <- factor(letters[1:15])
varFactor <- varFactor[1:5]
varFactor <- varFactor[drop=T]

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

   df <- data.frame(letters=letters[1:5],numbers=seq(1:5))
   levels(df$letters)
   ## [1] "a" "b" "c" "d" "e"
   subdf <- df[df$numbers <= 3]
   subdf$letters<-factor(as.character(subdf$letters))

К сожалению, Factor (), похоже, не работает при использовании rxdatastep Revoscaler. Я делаю это в двух шагах: 1) преобразовывать в символ и хранить во временной внешней кадре данных (.xdf). 2) Преобразовать обратно в фактор и хранить в окончательной внешней кадре данных. Это устраняет любые неиспользованные уровни факторов, не загружая все данные в память.

# Step 1) Converts to character, in temporary xdf file:
rxDataStep(inData = "input.xdf", outFile = "temp.xdf", transforms = list(VAR_X = as.character(VAR_X)), overwrite = T)
# Step 2) Converts back to factor:
rxDataStep(inData = "temp.xdf", outFile = "output.xdf", transforms = list(VAR_X = as.factor(VAR_X)), overwrite = T)

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

Не уверен в проблемах производительности.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top