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 dereshape2
diseñado para acompañar el marco de datos tidy, y para trabajar mano a mano conmagrittr
ydplyr
para construir undplyr
sólido para el análisis de datos.Del mismo modo que
reshape2
hizo menos que reformar,tidyr
hace menos quereshape2
. 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, ytidyr
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 paratimevar
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 dev.names
yv.names
en eldata.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)