separate - paquete tidyr en r
RemodelaciĆ³n de data.frame de formato ancho a largo (5)
Tengo algunos problemas para convertir mi data.frame
de una amplia mesa a una larga. Por el momento se ve así:
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
Ahora me gusta transformar este data.frame
en un largo data.frame
. Algo como esto:
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
Ya lo busqué y probé con las funciones melt()
y reshape()
, como algunas personas sugerían a preguntas similares. Sin embargo, hasta ahora solo obtengo resultados desordenados.
Si es posible, me gustaría hacerlo con la función reshape()
ya que se ve un poco más agradable de manejar.
Aquí hay otro ejemplo que muestra el uso de gather
de tidyr
. Puede seleccionar las columnas para gather
eliminándolas individualmente (como hago aquí), o incluyendo los años que desea explícitamente.
Tenga en cuenta que, para manejar las comas (y las X añadidas si check.names = FALSE
no está configurado), también estoy usando dplyr
''s parse_number
con parse_number
from readr
para convertir los valores de texto a números. Todos estos son parte del tidyverse
y pueden cargarse junto con la library(tidyverse)
wide %>%
gather(Year, Value, -Code, -Country) %>%
mutate(Year = parse_number(Year)
, Value = parse_number(Value))
Devoluciones:
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
Como esta respuesta está etiquetada con r-faq , sentí que sería útil compartir otra alternativa desde la base R: stack
.
Tenga en cuenta, sin embargo, que la stack
no funciona con el factor
s; solo funciona si is.vector
es TRUE
, y de la documentación para is.vector
, encontramos que:
is.vector
devuelveTRUE
si x es un vector del modo especificado que no tiene otros atributos que los nombres . DevuelveFALSE
contrario.
Estoy usando los datos de muestra de la respuesta de @Jaap , donde los valores en las columnas del año son factor
s.
Aquí está el enfoque 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
Tres soluciones alternativas:
1: con reshape2
library(reshape2)
long <- melt(wide, id.vars = c("Code", "Country"))
dando:
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
Algunas anotaciones alternativas que dan el mismo resultado:
# 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: con data.table
Puede usar la misma función de melt
que en el paquete reshape2
(que es una implementación extendida y mejorada). melt
de data.table
también tiene más parámetros que melt
de reshape2
. Puede, por ejemplo, especificar el nombre de la variable-columna:
library(data.table)
long <- melt(setDT(wide), id.vars=c("Code","Country"), variable.name="year")
Algunas anotaciones alternativas:
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: con tidyr
library(tidyr)
long <- wide %>% gather(year, value, -c(Code, Country))
Algunas anotaciones alternativas:
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 desea excluir los valores de NA
, puede agregar na.rm = TRUE
a la melt
, así como a las funciones de gather
.
Otro problema con los datos es que los valores serán leídos por R como valores-caracteres (como resultado de ,
en los números). Puede reparar eso con gsub
y as.numeric
:
long$value <- as.numeric(gsub(",", "", long$value))
O directamente con data.table
o 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)))
Datos:
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)
Usando el paquete de remodelación :
#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"]))
reshape()
tarda un tiempo en acostumbrarse, al igual que melt
/ cast
. Aquí hay una solución con una nueva forma, asumiendo que su marco de datos se llama d
:
reshape(d, direction = "long", varying = list(names(d)[3:7]), v.names = "Value",
idvar = c("Code","Country"), timevar = "Year", times = 1950:1954)