wide long r reshape r-faq

wide - long table r



¿Cómo remodelar datos de formato largo a ancho? (9)

El nuevo paquete tidyr (en 2014) también lo hace de manera simple, con tidyr gather() / spread() siendo los términos para melt / cast .

library(tidyr) spread(dat1, key = numbers, value = value)

Desde github ,

tidyr es un replanteamiento de reshape2 diseñado para acompañar el marco de datos tidy, y para trabajar mano a mano con magrittr y dplyr para construir un dplyr sólido para el análisis de datos.

Del mismo modo que reshape2 hizo menos que reformar, tidyr hace menos que reshape2 . Está diseñado específicamente para ordenar datos, no para la remodelación general que remodela2 o la agregación general que remodelaba. En particular, los métodos incorporados solo funcionan para marcos de datos, y tidyr no proporciona márgenes ni agregación.

Tengo problemas para reorganizar el siguiente cuadro de datos:

set.seed(45) dat1 <- data.frame( name = rep(c("firstName", "secondName"), each=4), numbers = rep(1:4, 2), value = rnorm(8) ) dat1 name numbers value 1 firstName 1 0.3407997 2 firstName 2 -0.7033403 3 firstName 3 -0.3795377 4 firstName 4 -0.7460474 5 secondName 1 -0.8981073 6 secondName 2 -0.3347941 7 secondName 3 -0.5013782 8 secondName 4 -0.1745357

Quiero reformularlo para que cada variable única de "nombre" sea un nombre conocido, con los "valores" como observaciones a lo largo de esa fila y los "números" como nombres. Algo así como esto:

name 1 2 3 4 1 firstName 0.3407997 -0.7033403 -0.3795377 -0.7460474 5 secondName -0.8981073 -0.3347941 -0.5013782 -0.1745357

He visto melt y cast y algunas otras cosas, pero ninguna parece hacer el trabajo.


Hay un nuevo y muy poderoso paquete de científicos de datos geniales en Win-Vector (gente que hizo vtreat , seplyr y replyr ) llamado cdata . Implementa los principios de "datos coordinados" descritos en este documento y también en esta publicación de blog . La idea es que, independientemente de cómo organice sus datos, debería ser posible identificar puntos de datos individuales utilizando un sistema de "coordenadas de datos". Aquí hay un extracto de la reciente publicación del blog de John Mount:

Todo el sistema se basa en dos primitivos u operadores cdata :: moveValuesToRowsD () y cdata :: moveValuesToColumnsD (). Estos operadores tienen pivote, no pivote, codificación en caliente, transposición, moviendo múltiples filas y columnas, y muchas otras transformaciones como simples casos especiales.

Es fácil escribir muchas operaciones diferentes en términos de los primitivos cdata. Estos operadores pueden trabajar en la memoria oa gran escala de datos (con bases de datos y Apache Spark; para datos grandes, use las variantes cdata :: moveValuesToRowsN () y cdata :: moveValuesToColumnsN ()). Las transformaciones están controladas por una tabla de control que en sí misma es un diagrama de (o imagen de) la transformación.

Primero construiremos la tabla de control (consulte la publicación del blog para obtener detalles) y luego realizaremos el movimiento de los datos de filas a columnas.

library(cdata) # first build the control table pivotControlTable <- buildPivotControlTableD(table = dat1, # reference to dataset columnToTakeKeysFrom = ''numbers'', # this will become column headers columnToTakeValuesFrom = ''value'', # this contains data sep="_") # optional for making column names # perform the move of data to columns dat_wide <- moveValuesToColumnsD(tallTable = dat1, # reference to dataset keyColumns = c(''name''), # this(these) column(s) should stay untouched controlTable = pivotControlTable# control table above ) dat_wide #> name numbers_1 numbers_2 numbers_3 numbers_4 #> 1 firstName 0.3407997 -0.7033403 -0.3795377 -0.7460474 #> 2 secondName -0.8981073 -0.3347941 -0.5013782 -0.1745357


La función de cambio de base funciona perfectamente bien:

df <- data.frame( year = c(rep(2000, 12), rep(2001, 12)), month = rep(1:12, 2), values = rnorm(24) ) df_wide <- reshape(df, idvar="year", timevar="month", v.names="values", direction="wide", sep="_") df_wide

Dónde

  • idvar es la columna de clases que separa las filas.
  • timevar es la columna de clases para timevar de ancho.
  • v.names es la columna que contiene valores numéricos
  • direction especifica formato ancho o largo
  • el argumento sep opcional es el separador utilizado entre los nombres de clase de v.names y v.names en el data.frame salida.

Si no existe idvar , cree uno antes de usar la función reshape() :

df$id <- c(rep("year1", 12), rep("year2", 12)) df_wide <- reshape(df, idvar="id", timevar="month", v.names="values", direction="wide", sep="_") df_wide

Solo recuerda que se requiere idvar ! La parte timevar y v.names es fácil. La salida de esta función es más predecible que algunas de las otras, ya que todo está explícitamente definido.


Otra opción si el rendimiento es una preocupación es usar la extensión reshape2 de las reshape2 de fusión y difusión de reshape2

( Referencia: remodelación eficiente utilizando data.tables )

library(data.table) setDT(dat1) dcast(dat1, name ~ numbers, value.var = "value") # name 1 2 3 4 # 1: firstName 0.1836433 -0.8356286 1.5952808 0.3295078 # 2: secondName -0.8204684 0.4874291 0.7383247 0.5757814

Y, a partir de data.table v1.9.6, podemos convertir en múltiples columnas

## add an extra column dat1[, value2 := value * 2] ## cast multiple value columns dcast(dat1, name ~ numbers, value.var = c("value", "value2")) # name value_1 value_2 value_3 value_4 value2_1 value2_2 value2_3 value2_4 # 1: firstName 0.1836433 -0.8356286 1.5952808 0.3295078 0.3672866 -1.6712572 3.190562 0.6590155 # 2: secondName -0.8204684 0.4874291 0.7383247 0.5757814 -1.6409368 0.9748581 1.476649 1.1515627


Otras dos opciones:

Paquete base:

df <- unstack(dat1, form = value ~ numbers) rownames(df) <- unique(dat1$name) df

paquete sqldf :

library(sqldf) sqldf(''SELECT name, MAX(CASE WHEN numbers = 1 THEN value ELSE NULL END) x1, MAX(CASE WHEN numbers = 2 THEN value ELSE NULL END) x2, MAX(CASE WHEN numbers = 3 THEN value ELSE NULL END) x3, MAX(CASE WHEN numbers = 4 THEN value ELSE NULL END) x4 FROM dat1 GROUP BY name'')


Puede hacer esto con la función reshape() , o con las funciones de melt() / cast() en el paquete remodelado. Para la segunda opción, el código de ejemplo es

library(reshape) cast(dat1, name ~ numbers)

O usando reshape2

library(reshape2) dcast(dat1, name ~ numbers)


Usando aggregate función aggregate base R:

aggregate(value ~ name, dat1, I) # name value.1 value.2 value.3 value.4 #1 firstName 0.4145 -0.4747 0.0659 -0.5024 #2 secondName -0.8259 0.1669 -0.8962 0.1681


Usando la función de reshape :

reshape(dat1, idvar = "name", timevar = "numbers", direction = "wide")


Usando su marco de datos de ejemplo, podríamos:

xtabs(value ~ name + numbers, data = dat1)