2010-02-02 7 views
77

Ich habe einige Probleme, um meine data.frame von einem breiten Tisch zu einem langen Tisch zu konvertieren. Im Moment sieht es wie folgt aus:data.frame vom breiten zum langen Format umformen

Code Country  1950 1951 1952 1953 1954 
AFG Afghanistan 20,249 21,352 22,532 23,557 24,555 
ALB Albania  8,097 8,986 10,058 11,123 12,246 

Jetzt möchte ich diesen data.frame in eine lange data.frame verwandeln. Etwas wie folgt aus:

Code Country  Year Value 
AFG Afghanistan 1950 20,249 
AFG Afghanistan 1951 21,352 
AFG Afghanistan 1952 22,532 
AFG Afghanistan 1953 23,557 
AFG Afghanistan 1954 24,555 
ALB Albania  1950 8,097 
ALB Albania  1951 8,986 
ALB Albania  1952 10,058 
ALB Albania  1953 11,123 
ALB Albania  1954 12,246 

ich ausgesehen haben und versuchte es bereits mit dem melt() und den reshape() Funktionen wie einige Leute mit ähnlichen Fragen darauf hindeutet wurden. Aber bis jetzt bekomme ich nur chaotische Ergebnisse.

Wenn es möglich ist, würde ich es gerne mit der reshape() Funktion tun, da es ein bisschen netter zu handhaben aussieht.

+1

Sie wissen nicht, ob das das Problem war, aber die Funktionen in dem reshape Paket sind Schmelze und Guss –

+0

Und das reshape Paket durch abgelöst wurde umformen2. –

+2

Und jetzt wurde reshape2 von tidyr abgelöst. – drhagen

Antwort

54

reshape() dauert eine Weile, sich daran zu gewöhnen, so wie melt/cast. Hier ist eine Lösung mit reshape, Datenrahmen unter der Annahme d genannt:

reshape(d, direction = "long", varying = list(names(d)[3:7]), v.names = "Value", 
     idvar = c("Code","Country"), timevar = "Year", times = 1950:1954) 
27

Mit reshape Paket:

#data 
x <- read.table(textConnection(
"Code Country  1950 1951 1952 1953 1954 
AFG Afghanistan 20,249 21,352 22,532 23,557 24,555 
ALB Albania  8,097 8,986 10,058 11,123 12,246"), header=TRUE) 

library(reshape) 

x2 <- melt(x, id = c("Code", "Country"), variable_name = "Year") 
x2[,"Year"] <- as.numeric(gsub("X", "" , x2[,"Year"])) 
64

Drei alternative Lösungen:

1: Mit reshape2

library(reshape2) 
long <- melt(wide, id.vars = c("Code", "Country")) 

geben:

Code  Country variable value 
1 AFG Afghanistan  1950 20,249 
2 ALB  Albania  1950 8,097 
3 AFG Afghanistan  1951 21,352 
4 ALB  Albania  1951 8,986 
5 AFG Afghanistan  1952 22,532 
6 ALB  Albania  1952 10,058 
7 AFG Afghanistan  1953 23,557 
8 ALB  Albania  1953 11,123 
9 AFG Afghanistan  1954 24,555 
10 ALB  Albania  1954 12,246 

Einige alternative Schreibweisen, die das gleiche Ergebnis:

# you can also define the id-variables by column number 
melt(wide, id.vars = 1:2) 

# as an alternative you can also specify the measure-variables 
# all other variables will then be used as id-variables 
melt(wide, measure.vars = 3:7) 
melt(wide, measure.vars = as.character(1950:1954)) 

2: Mit data.table

können Sie verwenden die gleiche melt Funktion wie in der reshape2 Paket (das ist eine erweiterte & verbesserte Implementierung). melt von data.table hat auch mehr Parameter, die melt von reshape2.Sie können für exaple angeben, kann auch den Namen der Variablen-Spalte:

library(data.table) 
long <- melt(setDT(wide), id.vars=c("Code","Country"), variable.name="year") 

Einige alternativen Schreibweisen:

melt(setDT(wide), id.vars = 1:2, variable.name = "year") 
melt(setDT(wide), measure.vars = 3:7, variable.name = "year") 
melt(setDT(wide), measure.vars = as.character(1950:1954), variable.name = "year") 

3: Mit tidyr

library(tidyr) 
long <- wide %>% gather(year, value, -c(Code, Country)) 

einigen alternativen Schreibweisen:

wide %>% gather(year, value, -Code, -Country) 
wide %>% gather(year, value, -1:-2) 
wide %>% gather(year, value, -(1:2)) 
wide %>% gather(year, value, -1, -2) 
wide %>% gather(year, value, 3:7) 
wide %>% gather(year, value, `1950`:`1954`) 

Wenn Sie NA Werte ausschließen möchten, können Sie na.rm = TRUE zum melt sowie die gather Funktionen hinzuzufügen.


Ein weiteres Problem bei den Daten ist, dass die Werte von R als Zeichen-Werte gelesen werden (als Ergebnis der , in den Zahlen). Sie können das reparieren mit gsub und as.numeric:

long$value <- as.numeric(gsub(",", "", long$value)) 

Oder direkt mit data.table oder dplyr:

# data.table 
long <- melt(setDT(wide), 
      id.vars = c("Code","Country"), 
      variable.name = "year")[, value := as.numeric(gsub(",", "", value))] 

# tidyr and dplyr 
long <- wide %>% gather(year, value, -c(Code,Country)) %>% 
    mutate(value = as.numeric(gsub(",", "", value))) 

Daten:

wide <- read.table(text="Code Country  1950 1951 1952 1953 1954 
AFG Afghanistan 20,249 21,352 22,532 23,557 24,555 
ALB Albania  8,097 8,986 10,058 11,123 12,246", header=TRUE, check.names=FALSE) 
+0

große Antwort, nur noch eine kleine Erinnerung: Stellen Sie keine anderen Variablen als "id" und "time" in Ihrem Datenrahmen, "schmelzen" konnte nicht sagen, was Sie in diesem Fall tun möchten. –

+1

@JasonGoal Könnten Sie das näher erläutern? Wie ich dich interpretiere, sollte es kein Problem sein. Geben Sie einfach die 'id.vars' und die' measure.vars' an. – Jaap

+0

, dann ist das gut für mich, weiß nicht, 'id.vars' und die' measure.vars' können in der ersten Alternative angegeben werden, sorry für das Chaos, es ist mein Fehler. –

1

Hier ein weiteres Beispiel zeigt die Verwendung von gather von tidyr. Sie können die Spalten auf gather entweder durch einzelne entfernen (wie ich hier), oder indem Sie die Jahre, die Sie explizit möchten.

anzumerken, dass die Kommas zu behandeln (und X hinzugefügt, wenn check.names = FALSE ist nicht gesetzt), auch ich bin mit dplyr ‚s mit parse_number von readr mutiert die Textwerte zurück in Zahlen zu umwandeln. Diese sind alle Teil des tidyverse und so zusammen mit library(tidyverse)

wide %>% 
    gather(Year, Value, -Code, -Country) %>% 
    mutate(Year = parse_number(Year) 
     , Value = parse_number(Value)) 

Returns geladen werden:

Code  Country Year Value 
1 AFG Afghanistan 1950 20249 
2 ALB  Albania 1950 8097 
3 AFG Afghanistan 1951 21352 
4 ALB  Albania 1951 8986 
5 AFG Afghanistan 1952 22532 
6 ALB  Albania 1952 10058 
7 AFG Afghanistan 1953 23557 
8 ALB  Albania 1953 11123 
9 AFG Afghanistan 1954 24555 
10 ALB  Albania 1954 12246 
3

Da diese Antwort mit markiert ist, fühlte ich, es wäre sinnvoll sein, eine andere Alternative zu teilen aus Basis R: stack.

Beachten Sie jedoch, dass stack nicht mit factor s arbeiten - es funktioniert nur, wenn is.vectorTRUE ist, und aus der Dokumentation für is.vector, finden wir, dass:

is.vector kehrt TRUE wenn x a Vektor des angegebenen Modus ohne Attribute andere als Namen. Andernfalls wird FALSE zurückgegeben.

Ich verwende die Beispieldaten from @Jaap's answer, wobei die Werte in den Spalten Jahr sind factor s.

Hier ist der stack Ansatz: (. Und Neufassung)

cbind(wide[1:2], stack(lapply(wide[-c(1, 2)], as.character))) 
## Code  Country values ind 
## 1 AFG Afghanistan 20,249 1950 
## 2 ALB  Albania 8,097 1950 
## 3 AFG Afghanistan 21,352 1951 
## 4 ALB  Albania 8,986 1951 
## 5 AFG Afghanistan 22,532 1952 
## 6 ALB  Albania 10,058 1952 
## 7 AFG Afghanistan 23,557 1953 
## 8 ALB  Albania 11,123 1953 
## 9 AFG Afghanistan 24,555 1954 
## 10 ALB  Albania 12,246 1954 
Verwandte Themen