Frage

Ich habe einen Datenrahmen mit einem Faktor. Wenn ich eine Teilmenge dieses Datenrahmens erstelle subset() oder eine andere Indizierungsfunktion, ein neuer Datenrahmen wird erstellt. Die Faktorvariable behält jedoch alle ihre ursprünglichen Ebenen bei - selbst wenn sie im neuen Datenrahmen nicht vorhanden sind.

Dies schafft Kopfschmerzen bei facettiertem Plotten oder Verwenden von Funktionen, die auf Faktorebenen beruhen.

Was ist der prägnanteste Weg, um Ebenen von einem Faktor in meinem neuen Datenrahmen zu entfernen?

Hier ist mein Beispiel:

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"
War es hilfreich?

Lösung

Alles, was Sie tun müssen, ist, Faktor () nach der Teilmenge erneut auf Ihre Variable anzuwenden:

> 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

BEARBEITEN

Aus dem Faktor -Seite Beispiel:

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

Um Stufen aus allen Faktorspalten in einem Datenrahmen fallen zu lassen, können Sie:

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

Andere Tipps

Seit R Version 2.12 gibt es a droplevels() Funktion.

levels(droplevels(subdf$letters))

Wenn Sie dieses Verhalten nicht wollen, verwenden Sie keine Faktoren, verwenden Sie stattdessen Charaktervektoren. Ich denke, das ist sinnvoller, als die Dinge danach zusammenzupatschen. Versuchen Sie Folgendes, bevor Sie Ihre Daten mit laden read.table oder read.csv:

options(stringsAsFactors = FALSE)

Der Nachteil ist, dass Sie auf eine alphabetische Bestellung beschränkt sind. (Nachbestellung ist dein Freund für Handlungen)

Es ist ein bekanntes Problem, und ein mögliches Mittel wird von bereitgestellt drop.levels() in dem Gdata Paket, wo Ihr Beispiel wird

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

Es gibt auch die dropUnusedLevels Funktion in der HMISC Paket. Es funktioniert jedoch nur, indem es den Untermenschbetreiber verändert [ und ist hier nicht anwendbar.

Als Konsequenz ist ein direkter Ansatz pro Spaltbasis einfach 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"

Eine andere Möglichkeit, dasselbe zu tun, aber mit dplyr

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

Bearbeiten:

Funktioniert auch! Dank an Agenis

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

Aus Gründen der Vollständigkeit gibt es jetzt auch fct_drop in dem forcats Paket http://forcats.tidyverse.org/reference/fct_drop.html.

Es unterscheidet sich von droplevels in der Art und Weise, wie es sich umgeht 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

Hier ist ein anderer Weg, von dem ich glaube, dass es dem gleichwertig ist factor(..) sich nähern:

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

Mit Blick auf die droplevels Methoden Code in der R -Quelle, die Sie sehen können Es wickelt sich an factor Funktion. Das heißt, Sie können die Spalte im Grunde neu erstellen factor Funktion.
Unter den Daten.

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"

Das ist widerlich. So mache ich es normalerweise, um das Laden anderer Pakete zu vermeiden:

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

was dich bringt:

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

Beachten Sie, dass die neuen Ebenen das, was auch immer ihren Index in den alten Ebenen einnimmt (Subdf $ Letter), also so etwas wie:

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

Wird nicht funktionieren.

Dies ist offensichtlich nicht ideal, wenn Sie viele Ebenen haben, aber für ein paar ist es schnell und einfach.

Ich habe dazu gebraucht, um dies zu tun. Jetzt, wo ich über Gdatas Drop.levels weiß, sieht es ziemlich ähnlich aus. Hier sind sie (von hier):

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
}

Hier ist eine Möglichkeit, das zu tun

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

Sehr interessanter Thread, ich mochte besonders die Idee, die Unterauswahl wieder zu faktorieren. Ich hatte schon einmal ein ähnliches Problem und habe gerade in den Charakter umgewandelt und dann zurück zu Faktor.

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

Leider scheint Faktor () bei der Verwendung von RxDatastep von Revoscaler nicht zu funktionieren. Ich mache es in zwei Schritten: 1) in das Zeichen konvertieren und in temporärem externen Datenrahmen (.xdf) speichern. 2) Zurück in den Faktor und speichern Sie in definitivem externen Datenrahmen. Dadurch werden ungenutzte Faktorstufen beseitigt, ohne alle Daten in den Speicher zu laden.

# 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)

Ich habe die meisten Beispiele hier ausprobiert, wenn nicht alle, außer in meinem Fall nicht zu funktionieren. Nachdem ich schon einige Zeit gekämpft habe, habe ich versucht, es zu benutzen As.character () Auf der Faktor -Spalte, um es in ein COL mit Strings zu ändern, was gut zu funktionieren scheint.

Ich bin mir nicht sicher bei Leistungsproblemen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top