wake-up-neo.com

Konvertieren Sie data.frame-Spalten von Faktoren in Zeichen

Ich habe einen Datenrahmen. Nennen wir ihn bob:

> head(bob)
                 phenotype                         exclusion
GSM399350 3- 4- 8- 25- 44+ 11b- 11c- 19- NK1.1- Gr1- TER119-
GSM399351 3- 4- 8- 25- 44+ 11b- 11c- 19- NK1.1- Gr1- TER119-
GSM399352 3- 4- 8- 25- 44+ 11b- 11c- 19- NK1.1- Gr1- TER119-
GSM399353 3- 4- 8- 25+ 44+ 11b- 11c- 19- NK1.1- Gr1- TER119-
GSM399354 3- 4- 8- 25+ 44+ 11b- 11c- 19- NK1.1- Gr1- TER119-
GSM399355 3- 4- 8- 25+ 44+ 11b- 11c- 19- NK1.1- Gr1- TER119-

Ich möchte die Zeilen dieses Datenrahmens verketten (dies wird eine weitere Frage sein). Aber schau:

> class(bob$phenotype)
[1] "factor"

Die Spalten von Bob sind Faktoren. Also zum Beispiel:

> as.character(head(bob))
[1] "c(3, 3, 3, 6, 6, 6)"       "c(3, 3, 3, 3, 3, 3)"      
[3] "c(29, 29, 29, 30, 30, 30)"

Ich fange nicht an, das zu verstehen, aber ich denke, das sind Indizes in den Ebenen der Faktoren der Spalten (des Hofes von König Caractacus) von bob? Nicht was ich brauche.

Seltsamerweise kann ich die Spalten von bob von Hand durchgehen und tun

bob$phenotype <- as.character(bob$phenotype)

was gut funktioniert. Und nach einigem Tippen kann ich einen data.frame erhalten, dessen Spalten eher Zeichen als Faktoren sind. Meine Frage lautet also: Wie kann ich das automatisch tun? Wie konvertiere ich einen data.frame mit Faktorspalten in einen data.frame mit Zeichenspalten, ohne jede Spalte manuell durchgehen zu müssen?

Bonusfrage: Warum funktioniert der manuelle Ansatz?

319
Mike Dewar

Ich folge Matt und Dirk. Wenn Sie Ihren vorhandenen Datenrahmen neu erstellen möchten, ohne die globale Option zu ändern, können Sie ihn mit einer apply-Anweisung neu erstellen:

bob <- data.frame(lapply(bob, as.character), stringsAsFactors=FALSE)

Dadurch werden alle Variablen in die Klasse "Charakter" konvertiert. Wenn Sie nur Faktoren konvertieren möchten, lesen Sie Mareks Lösung unten .

Wie @hadley hervorhebt, ist das Folgende prägnanter.

bob[] <- lapply(bob, as.character)

In beiden Fällen gibt lapply eine Liste aus. Aufgrund der magischen Eigenschaften von R behält die Verwendung von [] im zweiten Fall die data.frame-Klasse des bob -Objekts bei as.data.frame mit dem Argument stringsAsFactors = FALSE.

341
Shane

Um nur Faktoren zu ersetzen:

i <- sapply(bob, is.factor)
bob[i] <- lapply(bob[i], as.character)

Im Paket dplyr in Version 0.5.0 wurde die neue Funktion mutate_if eingeführt :

library(dplyr)
bob %>% mutate_if(is.factor, as.character) -> bob

Paket purrr von RStudio gibt eine andere Alternative:

library(purrr)
library(dplyr)
bob %>% map_if(is.factor, as.character) %>% as_data_frame -> bob

(Denken Sie daran, es ist frisch Paket)

280
Marek

Die globale Option

stringsAsFactors: Die Standardeinstellung für Argumente von data.frame und read.table.

möglicherweise möchten Sie FALSE in Ihren Startdateien festlegen (z. B. ~/.Rprofile). Bitte siehe help(options).

39

Wenn Sie wissen, wie Faktoren gespeichert werden, können Sie die Verwendung anwendungsbasierter Funktionen vermeiden, um dies zu erreichen. Was keineswegs bedeutet, dass die Apply-Lösungen nicht gut funktionieren.

Faktoren sind als numerische Indizes strukturiert, die an eine Liste von Ebenen gebunden sind. Dies ist sichtbar, wenn Sie einen Faktor in einen numerischen Faktor umwandeln. Damit:

> fact <- as.factor(c("a","b","a","d")
> fact
[1] a b a d
Levels: a b d

> as.numeric(fact)
[1] 1 2 1 3

Die in der letzten Zeile zurückgegebenen Zahlen entsprechen den Stufen des Faktors.

> levels(fact)
[1] "a" "b" "d"

Beachten Sie, dass levels() ein Array von Zeichen zurückgibt. Sie können diese Tatsache nutzen, um Faktoren einfach und kompakt in Zeichenfolgen oder Zahlen wie folgt umzuwandeln:

> fact_character <- levels(fact)[as.numeric(fact)]
> fact_character
[1] "a" "b" "a" "d"

Dies funktioniert auch für numerische Werte, sofern Sie Ihren Ausdruck in as.numeric() einschließen.

> num_fact <- factor(c(1,2,3,6,5,4))
> num_fact
[1] 1 2 3 6 5 4
Levels: 1 2 3 4 5 6
> num_num <- as.numeric(levels(num_fact)[as.numeric(num_fact)])
> num_num
[1] 1 2 3 6 5 4
22
Kikapp

Wenn Sie einen neuen Datenrahmen bobc möchten, wobei jeder Faktorvektor in bobf in einen Zeichenvektor konvertiert wird, versuchen Sie Folgendes:

bobc <- rapply(bobf, as.character, classes="factor", how="replace")

Wenn Sie es dann zurückkonvertieren möchten, können Sie einen logischen Vektor erstellen, dessen Spalten Faktoren sind, und diesen verwenden, um den Faktor selektiv anzuwenden

f <- sapply(bobf, class) == "factor"
bobc[,f] <- lapply(bobc[,f], factor)
18
scentoni

Normalerweise trenne ich diese Funktion von all meinen Projekten. Schnell und einfach.

unfactorize <- function(df){
  for(i in which(sapply(df, class) == "factor")) df[[i]] = as.character(df[[i]])
  return(df)
}
13
by0

Eine andere Möglichkeit ist die Konvertierung mit apply

bob2 <- apply(bob,2,as.character)

Und ein besserer (der vorherige ist der Klasse "Matrix")

bob2 <- as.data.frame(as.matrix(bob),stringsAsFactors=F)
8
George Dontas

Oder Sie können transform versuchen:

newbob <- transform(bob, phenotype = as.character(phenotype))

Stellen Sie einfach sicher, dass Sie alle Faktoren angeben, die Sie in Zeichen umwandeln möchten.

Oder Sie können so etwas tun und alle Schädlinge mit einem Schlag töten:

newbob_char <- as.data.frame(lapply(bob[sapply(bob, is.factor)], as.character), stringsAsFactors = FALSE)
newbob_rest <- bob[!(sapply(bob, is.factor))]
newbob <- cbind(newbob_char, newbob_rest)

Es ist nicht eine gute Idee, die Daten in einem Code wie diesem zu verschieben, ich könnte den Teil sapply separat ausführen ( Eigentlich ist es viel einfacher, das so zu machen, aber du verstehst schon ... Ich habe den Code nicht überprüft, weil ich nicht zu Hause bin, also hoffe ich, dass es funktioniert! =)

Dieser Ansatz hat jedoch einen Nachteil: Sie müssen die Spalten anschließend neu organisieren, während Sie mit transform alles tun können, was Sie möchten, jedoch zu einem Preis von "Code im Fußgängerstil -Schreiben " ...

Also da ... =)

7
aL3xa

pdate: Hier ist ein Beispiel für etwas, das nicht funktioniert. Ich habe es mir gedacht, aber ich denke, dass die Option stringsAsFactors nur für Zeichenfolgen funktioniert - die Faktoren bleiben dabei unberührt.

Versuche dies:

bob2 <- data.frame(bob, stringsAsFactors = FALSE)

Im Allgemeinen gibt es, wenn Sie Probleme mit Faktoren haben, die Zeichen sein sollten, eine stringsAsFactors -Einstellung, die Ihnen helfen kann (einschließlich einer globalen Einstellung).

7
Matt Parker

Fügen Sie am Anfang Ihres Datenrahmens stringsAsFactors = FALSE ein, um alle Missverständnisse zu ignorieren.

6
user5462317

Wenn Sie das Paket data.table für die Operationen in data.frame verwenden würden, liegt das Problem nicht vor.

library(data.table)
dt = data.table(col1 = c("a","b","c"), col2 = 1:3)
sapply(dt, class)
#       col1        col2 
#"character"   "integer" 

Wenn Sie bereits Faktorspalten in Ihrem Datensatz haben und diese in Zeichen konvertieren möchten, können Sie Folgendes tun.

library(data.table)
dt = data.table(col1 = factor(c("a","b","c")), col2 = 1:3)
sapply(dt, class)
#     col1      col2 
# "factor" "integer" 
upd.cols = sapply(dt, is.factor)
dt[, names(dt)[upd.cols] := lapply(.SD, as.character), .SDcols = upd.cols]
sapply(dt, class)
#       col1        col2 
#"character"   "integer" 
4
jangorecki

Diese Funktion erledigt den Trick

df <- stacomirtools::killfactor(df)
2
Cedric

Das funktioniert bei mir - ich habe mir endlich einen Einzeiler ausgedacht

df <- as.data.frame(lapply(df,function (y) if(class(y)=="factor" ) as.character(y) else y),stringsAsFactors=F)
2
user1617979

Sie sollten convert in hablar verwenden, was eine lesbare Syntax ergibt, die mit tidyverse Pipes kompatibel ist:

library(dplyr)
library(hablar)

df <- tibble(a = factor(c(1, 2, 3, 4)),
             b = factor(c(5, 6, 7, 8)))

df %>% convert(chr(a:b))

was gibt dir:

  a     b    
  <chr> <chr>
1 1     5    
2 2     6    
3 3     7    
4 4     8   
1
davsjob

Vielleicht eine neuere Option?

library("tidyverse")

bob <- bob %>% group_by_if(is.factor, as.character)
0
rachelette

Dies funktioniert, indem alle Zeichen und dann die Ziffern in Ziffern umgewandelt werden:

makenumcols<-function(df){
  df<-as.data.frame(df)
  df[] <- lapply(df, as.character)
  cond <- apply(df, 2, function(x) {
    x <- x[!is.na(x)]
    all(suppressWarnings(!is.na(as.numeric(x))))
  })
  numeric_cols <- names(df)[cond]
  df[,numeric_cols] <- sapply(df[,numeric_cols], as.numeric)
  return(df)
}

Angepasst von: Spaltentypen von Excel-Tabellen automatisch abrufen

0
Ferroao