Reformar data.frame de formato ancho a largo
Tengo algunos problemas para convertir data.frame
una mesa ancha a una mesa 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 gustaría transformar esto 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
Miré y ya intenté usar las funciones melt()
y reshape()
como sugerían algunas personas en preguntas similares. Sin embargo, hasta ahora sólo obtengo resultados desordenados.
Si es posible, me gustaría hacerlo con la reshape()
función ya que parece un poco más agradable de manejar.
Dos soluciones alternativas:
1) contabla de datos:
Puedes usar la melt
función:
library(data.table)
long <- melt(setDT(wide), id.vars = c("Code","Country"), variable.name = "year")
lo que da:
> long
Code Country year 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 notaciones 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")
2) conordenado:
Usar pivot_longer()
:
library(tidyr)
long <- wide %>%
pivot_longer(
cols = `1950`:`1954`,
names_to = "year",
values_to = "value"
)
Nota:
names_to
yvalues_to
el valor predeterminado es"name"
y"value"
, respectivamente, por lo que podría escribir esto de manera más sucinta comowide %>% pivot_longer(`1950`:`1954`)
.- El
cols
argumento utiliza el DSL tidyselect altamente flexible , por lo que puede seleccionar las mismas columnas usando una selección negativa (!c(Code, Country)
), un ayudante de selección (starts_with("19")
;matches("^\\d{4}$")
), índices numéricos (3:7
) y más. tidyr::pivot_longer()
es el sucesor detidyr::gather()
yreshape2::melt()
, que ya no están en desarrollo.
Transformando valores
Otro problema con los datos es que R leerá los valores como valores de caracteres (como resultado de los ,
números). Puedes reparar con gsub
y as.numeric
, ya sea antes de remodelar:
long$value <- as.numeric(gsub(",", "", long$value))
O durante la remodelación, con data.table
o tidyr
:
# data.table
long <- melt(setDT(wide),
id.vars = c("Code","Country"),
variable.name = "year")[, value := as.numeric(gsub(",", "", value))]
# tidyr
long <- wide %>%
pivot_longer(
cols = `1950`:`1954`,
names_to = "year",
values_to = "value",
values_transform = ~ as.numeric(gsub(",", "", .x))
)
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)
reshape()
Toma un tiempo acostumbrarse, al igual que melt
/ cast
. Aquí hay una solución con remodelación, suponiendo que su marco de datos se llame d
:
reshape(d,
direction = "long",
varying = list(names(d)[3:7]),
v.names = "Value",
idvar = c("Code", "Country"),
timevar = "Year",
times = 1950:1954)
Con tidyr_1.0.0
, otra opción espivot_longer
library(tidyr)
pivot_longer(df1, -c(Code, Country), values_to = "Value", names_to = "Year")
# A tibble: 10 x 4
# Code Country Year Value
# <fct> <fct> <chr> <fct>
# 1 AFG Afghanistan 1950 20,249
# 2 AFG Afghanistan 1951 21,352
# 3 AFG Afghanistan 1952 22,532
# 4 AFG Afghanistan 1953 23,557
# 5 AFG Afghanistan 1954 24,555
# 6 ALB Albania 1950 8,097
# 7 ALB Albania 1951 8,986
# 8 ALB Albania 1952 10,058
# 9 ALB Albania 1953 11,123
#10 ALB Albania 1954 12,246
datos
df1 <- structure(list(Code = structure(1:2, .Label = c("AFG", "ALB"), class = "factor"),
Country = structure(1:2, .Label = c("Afghanistan", "Albania"
), class = "factor"), `1950` = structure(1:2, .Label = c("20,249",
"8,097"), class = "factor"), `1951` = structure(1:2, .Label = c("21,352",
"8,986"), class = "factor"), `1952` = structure(2:1, .Label = c("10,058",
"22,532"), class = "factor"), `1953` = structure(2:1, .Label = c("11,123",
"23,557"), class = "factor"), `1954` = structure(2:1, .Label = c("12,246",
"24,555"), class = "factor")), class = "data.frame", row.names = c(NA,
-2L))