texto separate separar paquete gather funcion columnas r dataframe reshape r-faq

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 devuelve TRUE si x es un vector del modo especificado que no tiene otros atributos que los nombres . Devuelve FALSE 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)