¿Cómo reformar los datos de formato largo a ancho?

Tengo problemas para reorganizar el siguiente dataframe:

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 remodelarlo para que cada variable única de “nombre” sea un nombre de fila, con los “valores” como observaciones a lo largo de esa fila y los “números” como colnames. Más o menos así:

  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.

    Usando la función de reshape :

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

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

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

    De github ,

    tidyr es un reencuadre de reshape2 diseñado para acompañar el dataframe ordenado, y trabajar mano a mano con magrittr y dplyr para construir una tubería sólida para el análisis de datos.

    Así como reshape2 hizo menos que remodelar, tidyr hace menos que reshape2 . Está diseñado específicamente para ordenar datos, no la remodelación general que hace reshape2 , o la agregación general que hizo la remodelación. En particular, los métodos integrados solo funcionan para marcos de datos, y tidyr no proporciona márgenes ni agregaciones.

    Puede hacerlo con la función reshape() o con las funciones melt() / cast() en el paquete de remodelación. 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) 

    Otra opción si el rendimiento es una preocupación es usar la extensión de reshape2 de las reshape2 melt & dcast 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 lanzar 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 

    Usando su dataframe de ejemplo, podríamos:

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

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

    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 

    Hay un nuevo paquete muy poderoso de genios científicos de datos en Win-Vector (gente que creó 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 organices tus datos, debería ser posible identificar puntos de datos individuales usando 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 un pivote, un-pivot, una encoding en caliente, transposición, mover múltiples filas y columnas, y muchas otras transformaciones como casos especiales simples.

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

    Primero construiremos la tabla de control (ver la publicación de blog para más detalles) y luego realizaremos el movimiento de los datos de las filas a las 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 reshape 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 lanzar de ancho
    • v.names es la columna que contiene valores numéricos
    • direction especifica formato ancho o largo
    • el argumento opcional sep es el separador utilizado entre los nombres de clase 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. El resultado de esta función es más predecible que algunos de los otros, ya que todo está explícitamente definido.