2017-08-16 2 views
0

Ich habe einige Ergebnisse, die ich in einen Datenrahmen eingegeben habe. Ich habe einige Faktorspalten und viele numerische Spalten. Ich kann die numerischen Spalten leicht in numerische mit Indexierung umwandeln, wie in der Antwort auf this Frage.Konvertieren von Datenrahmenspalten in Faktor mit Indizierung

#create example data 
df = data.frame(replicate(1000,sample(1:10,1000,rep=TRUE))) 
df$X1 = LETTERS[df$X1] 
df$X2 = LETTERS[df$X2] 
df$X3 = LETTERS[df$X3] 
df[-1] <- sapply(df[-1], function(x) ifelse(runif(length(x)) < 0.1, NA, x)) 

#find columns that are factors 
factornames = c("X1", "X2", "X3") 
factorfilt = names(df) %in% factornames 

#convert non-factor columns to numeric 
df[, !factorfilt] = as.numeric(as.character(unlist(df[, !factorfilt]))) 

Aber wenn ich das gleiche für meinen Faktor Spalten tun will, kann ich nicht die gleiche Indizierung an der Arbeit:

#convert factor columns to factor 
df[, factorfilt] = as.factor(as.character(unlist(df[, factorfilt]))) 
class(df$X1) 

[1] "character" 

df[, factorfilt] = as.factor(as.character(df[, factorfilt])) 
class(df$X1) 

[1] "character" 

df[, factorfilt] = as.factor(unlist(df[, factorfilt])) 
class(df$X1) 

[1] "character" 

df[, factorfilt] = as.factor(df[, factorfilt]) 

Error in sort.list(y) : 'x' must be atomic for 'sort.list' 
Have you called 'sort' on a list? 

All diese Rückkehr "character" wenn ich class(df$X1) rufen, während, wenn ich laufe df$X1= as.factor(df$X1) gibt es "factor" zurück.

Warum funktioniert die Indizierung auf diese Weise nicht, wenn ich as.factor rufe, aber wenn ich rufe as.numeric?

+2

Der 'as.factor' oder' as.character' usw. funktioniert auf einem 'vector' und nicht auf' dat.frame'. Sie müssen die Spalten durchlaufen und dann 'factor' machen. – akrun

+0

Ist das nicht der Grund, warum 'unlist' da drin ist? – Leo

+1

Nach dem Kommentar von akrun, benutze 'lapply', um durch die ausgewählten Spalten zu laufen und den Zwang auszuführen:' df [, faktorfilz] <- lapply (df [, faktorfilz], as.factor) '. – lmo

Antwort

2

Sie sollten einige Verhaltensaspekte beobachten, was Sie tun. Definieren Sie Ihre Daten, wie Sie tat:

df = data.frame(replicate(1000,sample(1:10,1000,rep=TRUE))) 
df$X1 = LETTERS[df$X1] 
df$X2 = LETTERS[df$X2] 
df$X3 = LETTERS[df$X3] 
df[-1] <- sapply(df[-1], function(x) ifelse(runif(length(x)) < 0.1, NA, x)) 

factornames = c("X1", "X2", "X3") 
factorfilt = names(df) %in% factornames 
df[, !factorfilt] = as.numeric(as.character(unlist(df[, !factorfilt]))) 

Kommen wir nun zu dem Ergebnis, werfen Sie einen Blick die X1, machen X2 und X3 Faktoren wie Sie taten, aber wir es noch nicht neu zuweisen.

test <- as.factor(as.character(df[, factorfilt])) 
class(test) # "factor" 
length(test) # 3 

Wichtig ist hier zu bemerken ist, dass test kein Datenrahmen ist. Es ist ein Vektor, den Sie versuchen, über drei Spalten eines Datenrahmens zu speichern. Ich denke, wir sollten die Weisheit in Frage stellen, einen Datenrahmen in einen Vektor umzuwandeln, um ihn in einem Datenrahmen zu speichern.

dann Ihre zweite Zuordnung zu berücksichtigen:

test2 <- as.factor(as.character(unlist(df[, factorfilt]))) 
class(test2) # factor 
length(test2) # 3000 

Wieder ist es ein Faktor ist, aber es hat eine ganz andere Länge als test. R ist nett, indem man sie in df zurückversetzt und tut dies nur, weil sie erkennt, dass sie die Dimensionen abstimmen kann. Aber wenn Sie versuchen, die Faktoren in X1, X2 und X3 zu schieben, gibt es eine große Frage darüber, was mit den Faktorstufen zu tun ist. Sollten alle drei Variablen die gleichen Werte haben? Sollte jede Variable nur die Ebenen in sich haben? Anstatt zu versuchen zu deklarieren, was die "richtige" Wahl ist, ignoriert R es einfach und wandelt es zurück in einen Charakter, mit dem Sie alleine fertig werden.

Die Tatsache, dass das Manipulieren von Spalten auf diese Weise das Potenzial hat, Klassen unerwartet zu ändern, ist ein guter Grund, dies nicht zu tun. Dies zeigt sich in Ihrer Zuordnung der s. Lassen Sie uns wieder besuchen:

df = data.frame(replicate(1000,sample(1:10,1000,rep=TRUE))) 
df$X1 = LETTERS[df$X1] 
df$X2 = LETTERS[df$X2] 
df$X3 = LETTERS[df$X3] 

An diesem Punkt X4 durch X1000 sind alle integer Klasse Spalten. Wenn Sie

df[-1] <- sapply(df[-1], function(x) ifelse(runif(length(x)) < 0.1, NA, x)) 

laufen, sind sie alle jetzt character s, und Sie gehen, sie zu numeric konvertieren. Sie sind nicht einmal mehr ihre ursprüngliche Klasse.

Wenn stattdessen verwenden wir lapply

df[-1] <- lapply(df[-1], function(x) ifelse(runif(length(x)) < 0.1, NA, x)) 

die ursprünglichen Klassen erhalten werden und es gibt keine Notwendigkeit, sie in einen numerischen Klasse zu konvertieren zurück. In ähnlicher Weise können wir leicht X1 durch X3 Faktoren konvertieren mit

df[, factorfilt] <- lapply(df[, factorfilt], as.factor) 

Als allgemeine Regel ist es besser, die Daten in den Spalten als getrennte Spalten zu manipulieren. Sobald Sie beginnen, einen einzelnen Vektor über mehrere Spalten zu verteilen, betreten Sie eine dunkle Welt des Unfugs.

+0

Hmm, ich war mir dieser Dinge überhaupt nicht bewusst, danke. Wenn man von 'sapply' und' lapply' liest, scheint es, dass sie gleich sind. – Leo

+2

Es gibt einen Unterschied in dem, was sie zurückgeben. 'sapply' gibt entweder einen Vektor oder eine Matrix zurück (in diesem speziellen Fall denke ich, dass es ein wirklich langer Vektor ist). 'lapply' gibt eine Liste zurück, die die Spalten Ihres Datenrahmens korrekt partitioniert. – Benjamin

Verwandte Themen