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?
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
.
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)
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)
.
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
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)
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)
}
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)
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 ... =)
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).
Fügen Sie am Anfang Ihres Datenrahmens stringsAsFactors = FALSE
ein, um alle Missverständnisse zu ignorieren.
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"
Diese Funktion erledigt den Trick
df <- stacomirtools::killfactor(df)
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)
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
Vielleicht eine neuere Option?
library("tidyverse")
bob <- bob %>% group_by_if(is.factor, as.character)
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