wake-up-neo.com

Verketten Sie die Zeilen eines Datenrahmens

Ich möchte einen Datenrahmen mit Zeichen und Zahlen verwenden und alle Elemente jeder Zeile zu einer einzelnen Zeichenfolge zusammenfügen, die als einzelnes Element in einem Vektor gespeichert würde. Als Beispiel mache ich einen Datenrahmen aus Buchstaben und Zahlen, und dann möchte ich die erste Zeile über die Einfügefunktion verketten und hoffentlich den Wert "A1" zurückgeben.

df <- data.frame(letters = LETTERS[1:5], numbers = 1:5)
df

##   letters numbers
## 1       A       1
## 2       B       2
## 3       C       3
## 4       D       4
## 5       E       5

paste(df[1,], sep =".")
## [1] "1" "1"

Einfügen konvertiert also jedes Element der Zeile in eine Ganzzahl, die dem "Index der entsprechenden Ebene" entspricht, als ob es ein Faktor wäre, und behält einen Vektor der Länge zwei. (Ich weiß/glaube, dass sich Faktoren, die zu Charakteren gezwungen werden, auf diese Weise verhalten, aber da R df [1,] überhaupt nicht als Faktor speichert (getestet von is.factor (), kann ich das nicht überprüfen ist eigentlich ein Index für eine Ebene)

is.factor(df[1,])
## [1] FALSE
is.vector(df[1,])
## [1] FALSE

Wenn es sich also nicht um einen Vektor handelt, ist es sinnvoll, dass er sich seltsam verhält, aber ich kann ihn nicht in einen Vektor zwingen

> is.vector(as.vector(df[1,]))
[1] FALSE

Die Verwendung von as.character schien bei meinen Versuchen nicht zu helfen

Kann jemand dieses Verhalten erklären?

25
Sam

Während andere sich darauf konzentriert haben, warum Ihr Code nicht funktioniert und wie er verbessert werden kann, werde ich mich mehr darauf konzentrieren, das gewünschte Ergebnis zu erzielen. Aus Ihrer Beschreibung scheint es, dass Sie mit Paste die gewünschten Ergebnisse leicht erreichen können:

df <- data.frame(letters = LETTERS[1:5], numbers = 1:5, stringsAsFactors=FALSE)
paste(df$letters, df$numbers, sep=""))

## [1] "A1" "B2" "C3" "D4" "E5"

Sie können df$letters mit df$letters <- as.character(df$letters) in ein Zeichen ändern, wenn Sie das stringsAsFactors-Argument nicht verwenden möchten.

Aber nehmen wir an, es ist nicht das, was Sie wollen. Nehmen wir an, Sie haben Hunderte von Spalten und möchten diese alle zusammenfügen. Das können wir auch mit Ihrem minimalen Beispiel machen:

df_args <- c(df, sep="")
do.call(paste, df_args)

## [1] "A1" "B2" "C3" "D4" "E5"

EDIT: Alternative Methode und Erklärung:

Ich habe erkannt, dass das Problem, das Sie haben, eine Kombination aus der Tatsache ist, dass Sie einen Faktor verwenden, und dass Sie das Argument sep anstelle von collapse (wie @adibender verwendet) verwendet. Der Unterschied ist, dass sep das Trennzeichen zwischen zwei separaten Vektoren und collapse Trennzeichen innerhalb eines Vektors gibt. Wenn Sie df[1,] verwenden, geben Sie paste einen einzelnen Vektor an und müssen daher das Argument collapse verwenden. Mit Ihrer Idee, jede Zeile zu erhalten und sie zu verketten, wird die folgende Codezeile genau das tun, was Sie möchten:

apply(df, 1, paste, collapse="")

Ok, jetzt zu den Erklärungen:

Warum funktioniert as.list nicht?

as.list konvertiert ein Objekt in eine Liste. Es funktioniert also. Ihr Datenrahmen wird in eine Liste konvertiert und anschließend das sep=""-Argument ignoriert. c kombiniert Objekte miteinander. Technisch gesehen ist ein Datenrahmen nur eine Liste, in der jede Spalte ein Element ist und alle Elemente die gleiche Länge haben müssen. Wenn ich es mit sep="" kombiniere, wird es einfach zu einer normalen Liste mit den Spalten des Datenrahmens als Elemente.

Warum do.call verwenden?

Mit do.call können Sie eine Funktion mit einer benannten Liste als Argumente aufrufen. Sie können die Liste nicht einfach direkt in paste werfen, da sie keine Datenrahmen mag. Es ist für die Verkettung von Vektoren konzipiert. Denken Sie daran, dass dfargs eine Liste ist, die einen Vektor aus Buchstaben, einen Vektor aus Zahlen und Sep enthält, wobei der Vektor der Länge 1 nur "" enthält. Wenn ich do.call verwende, ist die resultierende Einfügefunktion im Wesentlichen paste(letters, numbers, sep).
.__ Was aber, wenn mein ursprünglicher Datenrahmen Spalten "letters", "numbers", "squigs", "blargs" hatte, nach denen ich das Trennzeichen wie zuvor hinzugefügt habe? Dann würde die Einfügefunktion durch do.call aussehen:

paste(letters, numbers, squigs, blargs, sep)

Sie sehen also, dass es für eine beliebige Anzahl von Spalten funktioniert.

50
sebastian-c

Das ist zwar ein bisschen komisch, aber auch das soll passieren. Wenn Sie den data.frame wie Sie erstellen, wird die Spalte letters als factor gespeichert. Natürlich haben die Faktoren keine Reihenfolge. Wenn also as.numeric() auf einen Faktor angewendet wird, wird die Reihenfolge des Faktors zurückgegeben. Zum Beispiel: 

> df[, 1]
[1] A B C D E
Levels: A B C D E
> as.numeric(df[, 1])
[1] 1 2 3 4 5

A ist die erste Ebene des Faktors df[, 1]. Daher wird A in den Wert 1 konvertiert, wenn as.numeric angewendet wird. Dies geschieht, wenn Sie paste(df[1, ]) aufrufen. Da die Spalten 1 und 2 unterschiedliche Klassen haben, werden durch das Einfügen zuerst beide Elemente der Zeile 1 in numerische und dann in Zeichen umgewandelt. 

Wenn Sie beide Spalten verketten möchten, müssen Sie zuerst die erste Zeile in ein Zeichen umwandeln: 

df[, 1] <- as.character(df[, 1])
paste(df[1,], collapse = "")

Wie @ sebastian-c hervorgehoben hat, können Sie auch stringsAsFactors = FALSE bei der Erstellung des data.frame verwenden. Dann können Sie den Schritt as.character() weglassen.

4
adibender

Für diejenigen, die eine Bibliothek (Tidyverse) verwenden, können Sie einfach die Unite-Funktion verwenden.

 new.df<-df%>%
 unite(together, letters, numbers, sep="")

Dadurch erhalten Sie eine neue Spalte mit der Bezeichnung "zusammen" mit A1, B2 usw.

3
Shirley

wenn du mit anfangen möchtest

df <- data.frame(letters = LETTERS[1:5], numbers = 1:5, stringsAsFactors=TRUE)

.. dann gibt es keine allgemeine Regel darüber, wie df$letters von einer bestimmten Funktion interpretiert wird. Dies ist ein Faktor für die Modellierung von Funktionen, für einige Zeichen und für andere für ganze Zahlen. Sogar dieselbe Funktion wie Einfügen kann sie je nach Verwendung anders interpretieren:

paste(df[1,], collapse="") # "11"
apply(df, 1, paste, collapse="") # "A1" "B2" "C3" "D4" "E5"

Keine Logik darin, außer dass es wahrscheinlich Sinn macht, wenn Sie das Innere jeder Funktion kennen.

Die Faktoren scheinen in Ganzzahlen umgewandelt zu werden, wenn ein Argument in einen Vektor umgewandelt wird (wie Sie wissen, sind Datenrahmen Listen von Vektoren gleicher Länge. Daher ist die erste Zeile eines Datenrahmens auch eine Liste und wenn dies zwingend ist) ein Vektor, so etwas passiert :)

df[1,]
#    letters numbers
# 1       A       1
unlist(df[1,])
# letters numbers 
#  1       1 

Ich weiß nicht, wie apply das erreicht, was es tut (d. H. Faktoren werden durch Zeichenwerte dargestellt) - wenn Sie interessiert sind, schauen Sie sich den Quellcode an. Es kann jedoch nützlich sein zu wissen, dass Sie (in diesem speziellen Sinne) apply (in diesem speziellen Fall) vertrauen können. Allgemeiner ist es nützlich, jedes Datenelement in einem vernünftigen Format zu speichern, das das Speichern von Strings als Strings umfasst, d. H. Mit stringsAsFactors=FALSE

Übrigens, jedes einführende R-Buch sollte diese Idee in einem Untertitel haben. Zum Beispiel, mein Plan für den Ruhestand ist zu schreiben "Eine (nicht so) sanfte Einführung in den Zen der Datenfischerei mit R, die StringsAsFactors = FALSE way".

0
lebatsnok