web-dev-qa-db-de.com

Wie konvertiert man einen Faktor in eine Ganzzahl ohne Verlust von Informationen?

Wenn ich einen Faktor in eine Zahl oder eine Ganzzahl konvertiere, erhalte ich die zugrunde liegenden Ebenencodes und nicht die Werte als Zahlen.

f <- factor(sample(runif(5), 20, replace = TRUE))
##  [1] 0.0248644019011408 0.0248644019011408 0.179684827337041 
##  [4] 0.0284090070053935 0.363644931698218  0.363644931698218 
##  [7] 0.179684827337041  0.249704354675487  0.249704354675487 
## [10] 0.0248644019011408 0.249704354675487  0.0284090070053935
## [13] 0.179684827337041  0.0248644019011408 0.179684827337041 
## [16] 0.363644931698218  0.249704354675487  0.363644931698218 
## [19] 0.179684827337041  0.0284090070053935
## 5 Levels: 0.0248644019011408 0.0284090070053935 ... 0.363644931698218

as.numeric(f)
##  [1] 1 1 3 2 5 5 3 4 4 1 4 2 3 1 3 5 4 5 3 2

as.integer(f)
##  [1] 1 1 3 2 5 5 3 4 4 1 4 2 3 1 3 5 4 5 3 2

Ich muss auf paste zurückgreifen, um die tatsächlichen Werte zu erhalten:

as.numeric(paste(f))
##  [1] 0.02486440 0.02486440 0.17968483 0.02840901 0.36364493 0.36364493
##  [7] 0.17968483 0.24970435 0.24970435 0.02486440 0.24970435 0.02840901
## [13] 0.17968483 0.02486440 0.17968483 0.36364493 0.24970435 0.36364493
## [19] 0.17968483 0.02840901

Gibt es eine bessere Möglichkeit, einen Faktor in eine Zahl umzuwandeln?

507
Adam SO

Siehe den Abschnitt Warnung von ?factor :

Insbesondere ist _as.numeric_, das auf einen Faktor angewendet wird, bedeutungslos und kann durch impliziten Zwang geschehen. Um einen Faktor f in ungefähr seine ursprünglichen numerischen Werte umzuwandeln, wird as.numeric(levels(f))[f] empfohlen und ist geringfügig effizienter als as.numeric(as.character(f)).

Die FAQ auf R hat ähnliche Ratschläge .


Warum ist as.numeric(levels(f))[f] wirksamer als as.numeric(as.character(f))?

as.numeric(as.character(f)) ist effektiv as.numeric(levels(f)[f]), sodass Sie die Umwandlung in numerische Werte für length(x) und nicht für nlevels(x) durchführen. Der Geschwindigkeitsunterschied ist am deutlichsten bei langen Vektoren mit wenigen Pegeln. Wenn die Werte größtenteils eindeutig sind, gibt es keinen großen Geschwindigkeitsunterschied. Bei der Konvertierung ist es unwahrscheinlich, dass dieser Vorgang den Engpass in Ihrem Code darstellt. Machen Sie sich also keine allzu großen Sorgen.


Einige Zeiten

_library(microbenchmark)
microbenchmark(
  as.numeric(levels(f))[f],
  as.numeric(levels(f)[f]),
  as.numeric(as.character(f)),
  paste0(x),
  paste(x),
  times = 1e5
)
## Unit: microseconds
##                         expr   min    lq      mean median     uq      max neval
##     as.numeric(levels(f))[f] 3.982 5.120  6.088624  5.405  5.974 1981.418 1e+05
##     as.numeric(levels(f)[f]) 5.973 7.111  8.352032  7.396  8.250 4256.380 1e+05
##  as.numeric(as.character(f)) 6.827 8.249  9.628264  8.534  9.671 1983.694 1e+05
##                    paste0(x) 7.964 9.387 11.026351  9.956 10.810 2911.257 1e+05
##                     paste(x) 7.965 9.387 11.127308  9.956 11.093 2419.458 1e+05
_
641
Joshua Ulrich

R bietet eine Reihe von (undokumentierten) Komfortfunktionen zur Umrechnung von Faktoren:

  • as.character.factor
  • as.data.frame.factor
  • as.Date.factor
  • as.list.factor
  • as.vector.factor
  • ...

Aber ärgerlich ist nichts mit der factor -> numeric -Konvertierung zu tun. Als Erweiterung der Antwort von Joshua Ulrich würde ich vorschlagen, diese Auslassung mit der Definition Ihrer eigenen idiomatischen Funktion zu überwinden:

as.numeric.factor <- function(x) {as.numeric(levels(x))[x]}

das Sie am Anfang Ihres Skripts speichern können, oder noch besser in Ihrer .Rprofile -Datei.

74
Jealie

Am einfachsten wäre es, die unfactor-Funktion aus dem Paket varhandle zu verwenden.

unfactor(your_factor_variable)

Dieses Beispiel kann ein schneller Anfang sein:

x <- rep(c("a", "b", "c"), 20)
y <- rep(c(1, 1, 0), 20)

class(x)  # -> "character"
class(y)  # -> "numeric"

x <- factor(x)
y <- factor(y)

class(x)  # -> "factor"
class(y)  # -> "factor"

library(varhandle)
x <- unfactor(x)
y <- unfactor(y)

class(x)  # -> "character"
class(y)  # -> "numeric"
29

Jede Antwort in diesem Beitrag brachte keine Ergebnisse für mich, NAs wurden generiert.

y2<-factor(c("A","B","C","D","A")); 
as.numeric(levels(y2))[y2] 
[1] NA NA NA NA NA Warning message: NAs introduced by coercion

Was für mich funktioniert hat, ist das - 

as.integer(y2)
# [1] 1 2 3 4 1

Hinweis: Diese spezielle Antwort ist nicht zum Konvertieren von numerisch bewerteten Faktoren in Numerik. Sie dient zum Konvertieren kategorialer Faktoren in ihre entsprechenden Ebenennummern.

16
Indi

Es ist nur nur möglich, wenn die Faktorbeschriftungen mit den ursprünglichen Werten übereinstimmen. Ich werde es an einem Beispiel erklären.

Angenommen, die Daten sind Vektor x:

x <- c(20, 10, 30, 20, 10, 40, 10, 40)

Jetzt werde ich einen Faktor mit vier Labels erstellen:

f <- factor(x, levels = c(10, 20, 30, 40), labels = c("A", "B", "C", "D"))

1) x ist vom Typ double, f ist vom Typ integer. Dies ist der erste unvermeidliche Informationsverlust. Faktoren werden immer als ganze Zahlen gespeichert.

> typeof(x)
[1] "double"
> typeof(f)
[1] "integer"

2) Es ist nicht möglich, auf die ursprünglichen Werte (10, 20, 30, 40) zurückzugreifen, wenn nur f verfügbar ist. Wir sehen, dass f nur die ganzzahligen Werte 1, 2, 3, 4 und zwei Attribute enthält - die Liste der Labels ("A", "B", "C", "D") und das Klassenattribut "Faktor". Nichts mehr.

> str(f)
 Factor w/ 4 levels "A","B","C","D": 2 1 3 2 1 4 1 4
> attributes(f)
$levels
[1] "A" "B" "C" "D"

$class
[1] "factor"

Um zu den ursprünglichen Werten zurückzukehren, müssen wir die Werte der beim Erstellen des Faktors verwendeten Werte kennen. In diesem Fall c(10, 20, 30, 40). Wenn wir die ursprünglichen Werte kennen (in der richtigen Reihenfolge), können wir zu den ursprünglichen Werten zurückkehren.

> orig_levels <- c(10, 20, 30, 40)
> x1 <- orig_levels[f]
> all.equal(x, x1)
[1] TRUE

Dies funktioniert nur, wenn für alle möglichen Werte in den Originaldaten Beschriftungen definiert wurden.

Wenn Sie also die ursprünglichen Werte benötigen, müssen Sie sie beibehalten. Andernfalls besteht eine hohe Chance, dass es nicht möglich ist, nur von einem Faktor auf sie zurückzugreifen.

8
djhurio

Sie können hablar::convert verwenden, wenn Sie einen Datenrahmen haben. Die Syntax ist einfach:

Sample df

library(hablar)
library(dplyr)

df <- dplyr::tibble(a = as.factor(c("7", "3")),
                    b = as.factor(c("1.5", "6.3")))

Lösung

df %>% 
  convert(num(a, b))

gibt Ihnen:

# A tibble: 2 x 2
      a     b
  <dbl> <dbl>
1    7.  1.50
2    3.  6.30

Oder wenn Sie möchten, dass eine Spalte eine ganze Zahl und eine numerische ist:

df %>% 
  convert(int(a),
          num(b))

ergebnisse in:

# A tibble: 2 x 2
      a     b
  <int> <dbl>
1     7  1.50
2     3  6.30
0
davsjob