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