Remodeler data.frame du format large au format long

J’ai du mal à convertir mes data.frame d’une table large à une table longue. En ce moment, cela ressemble à ceci:

 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 

Maintenant j’aime transformer ce data.frame en un long data.frame . Quelque chose comme ça:

 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 

Je l’ai déjà examiné et essayé avec les fonctions melt() et reshape() , car certaines personnes suggéraient des questions similaires. Cependant, jusqu’à présent, je n’ai que des résultats désordonnés.

Si c’est possible, je voudrais le faire avec la fonction reshape() car elle est un peu plus agréable à gérer.

reshape() prend un certain temps pour s’y habituer, juste comme melt / cast . Voici une solution avec remodeler, en supposant que votre bloc de données s’appelle d :

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

Trois solutions alternatives:

1: avec reshape2

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

donnant:

  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 

Quelques notations alternatives qui donnent le même résultat:

 # 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: avec data.table

Vous pouvez utiliser la même fonction de melt que dans le package reshape2 (qui est une implémentation étendue et améliorée). melt de data.table a également plus de parameters que la fonction de melt de reshape2 . Vous pouvez par exemple spécifier également le nom de la variable-colonne:

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

Quelques notations alternatives:

 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: avec tidyr

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

Quelques notations alternatives:

 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`) 

Si vous voulez exclure les valeurs NA , vous pouvez append na.rm = TRUE à la melt ainsi que les fonctions de gather .


Un autre problème avec les données est que les valeurs seront lues par R comme valeurs de caractères (à la suite des , dans les nombres). Vous pouvez réparer cela avec gsub et as.numeric :

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

Ou directement avec data.table ou 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))) 

Les données:

 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) 

Utilisation du package de remodelage :

 #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"])) 

Comme cette réponse est étiquetée avec r-faq , j’ai pensé qu’il serait utile de partager une autre alternative avec la base R: stack .

Notez, cependant, que cette stack ne fonctionne pas avec le factor s – elle ne fonctionne que si is.vector TRUE et que la documentation de is.vector que:

is.vector renvoie TRUE si x est un vecteur du mode spécifié n’ayant aucun atsortingbut autre que des noms . Il retourne FALSE sinon.

J’utilise les exemples de données de la réponse de @Jaap , où les valeurs des colonnes de l’année sont des factor s.

Voici l’approche de la stack :

 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 

Voici un autre exemple montrant l’utilisation de gather de tidyr . Vous pouvez sélectionner les colonnes à gather en les supprimant individuellement (comme je le fais ici) ou en incluant les années que vous souhaitez explicitement.

Notez que pour gérer les virgules (et les X ajoutés si check.names = FALSE n’est pas défini), j’utilise également dplyr de parse_number avec parse_number de readr pour convertir les valeurs de texte en nombres. Celles-ci font toutes partie du tidyverse et peuvent donc être chargées avec la library(tidyverse)

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

Résultats:

  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