2012-01-13 12 views
8

tengo una bastante grande trama de datos estructurada de esta manera:Cómo remodelar esta trama de datos con el paquete de cambio de forma

id x1 x2 x3 y1 y2 y3 z1 z2 z3  v 
1  2  4  5 10 20 15 200 150 170 2.5 
2  3  7  6 25 35 40 300 350 400 4.2 

Necesito crear una trama de datos de esta manera:

id xsource xvalue yvalue zvalue  v 
1  x1  2  10  200  2.5 
1  x2  4  20  150  2.5 
1  x3  5  15  170  2.5 
2  x1  3  25  300  4.2 
2  x2  7  35  350  4.2 
2  x3  6  40  400  4.2 

estoy muy seguro Tengo que hacerlo con el paquete de remodelación, pero no puedo obtener lo que quiero.

¿Me podría ayudar?

Gracias

Respuesta

7

Aquí está la solución reshape().

La clave es que el argumento varying= puede tomar una lista de vectores de nombres de columnas en el formato ancho que corresponden a variables individuales en el formato largo. En este caso, las columnas "x1", "x2", "x3" en la trama de datos original se envían a una columna en la trama de datos larga, las columnas "y1, y2, y3" entrarán en una segunda columna, y así sucesivamente.

# Read in the original data, x, from Andrie's answer 

res <- reshape(x, direction = "long", idvar = "id", 
       varying = list(c("x1","x2", "x3"), 
           c("y1", "y2", "y3"), 
           c("z1", "z2", "z3")), 
       v.names = c("xvalue", "yvalue", "zvalue"), 
       timevar = "xsource", times = c("x1", "x2", "x3")) 
#  id v xsource xvalue yvalue zvalue 
# 1.x1 1 2.5  x1  2  10 200 
# 2.x1 2 4.2  x1  3  25 300 
# 1.x2 1 2.5  x2  4  20 150 
# 2.x2 2 4.2  x2  7  35 350 
# 1.x3 1 2.5  x3  5  15 170 
# 2.x3 2 4.2  x3  6  40 400 

Por último, se necesita un par de pasos puramente cosméticas para obtener los resultados que mira exactamente como se muestra en su pregunta:

res <- res[order(res$id, res$xsource), c(1,3,4,5,6,2)] 
row.names(res) <- NULL 
res 
# id xsource xvalue yvalue zvalue v 
# 1 1  x1  2  10 200 2.5 
# 2 1  x2  4  20 150 2.5 
# 3 1  x3  5  15 170 2.5 
# 4 2  x1  3  25 300 4.2 
# 5 2  x2  7  35 350 4.2 
# 6 2  x3  6  40 400 4.2 
+0

¡Gracias, Josh! Todavía hay un problema. Su solución funciona perfectamente en este ejemplo, pero cuando la aplico a mi marco de datos real aparece el error "[.data.frame' (datos, variando [[i]] [1L]): columnas indefinidas seleccionadas". ¿Cualquier sugerencia? – corrado

+0

¡Problema resuelto! ¡Muchas gracias, tu solución funciona a la perfección! – corrado

1

Alguien por favor demostrar que estoy equivocado, pero no creo que sea fácil de resolver este problema utilizando el paquete reshape o la función de base reshape.

Sin embargo, es bastante fácil de usar y lapplydo.call:

replicar los datos:

x <- read.table(text=" 
id x1 x2 x3 y1 y2 y3 z1 z2 z3  v 
1  2  4  5 10 20 15 200 150 170 2.5 
2  3  7  6 25 35 40 300 350 400 4.2 
", header=TRUE) 

hacer el análisis

chunks <- lapply(1:nrow(x), 
    function(i)cbind(x[i, 1], 1:3, matrix(x[i, 2:10], ncol=3), x[i, 11])) 
res <- do.call(rbind, chunks) 
colnames(res) <- c("id", "source", "x", "y", "z", "v") 
res 

    id source x y z v 
[1,] 1 1  2 10 200 2.5 
[2,] 1 2  4 20 150 2.5 
[3,] 1 3  5 15 170 2.5 
[4,] 2 1  3 25 300 4.2 
[5,] 2 2  7 35 350 4.2 
[6,] 2 3  6 40 400 4.2 
+0

I De acuerdo, este es un poco más complicado que a primera vista. Aunque creo que te estás perdiendo la columna de ID. Este es un problema interesante y yo también estoy esperando una solución más rápida y ordenada. –

+0

@TylerRinker Gracias por señalar la columna de ID faltante. He editado la respuesta para corregir esto. – Andrie

2

Aquí es uno de los enfoques que utilizan reshape2 y se describe en profundidad en mi documento en tidy data.

Paso 1: identifique las variables que ya están en las columnas. En este caso: Id., Y v Estas son las variables que derretir por

library(reshape2) 
xm <- melt(x, c("id", "v")) 

Paso 2: dividir las variables que se combinan actualmente en una columna. En este caso que es de origen (la parte de caracteres) y el representante (la parte entera):

Hay un montón de maneras de hacer esto, voy a utilizar la extracción de cadena con el stringr paquete

library(stringr) 
xm$source <- str_sub(xm$variable, 1, 1) 
xm$rep <- str_sub(xm$variable, 2, 2) 
xm$variable <- NULL 

paso 3: reorganizar las variables que actualmente en las filas, sino que queremos en columnas:

dcast(xm, ... ~ source) 

# id v rep x y z 
# 1 1 2.5  1 2 10 200 
# 2 1 2.5  2 4 20 150 
# 3 1 2.5  3 5 15 170 
# 4 2 4.2  1 3 25 300 
# 5 2 4.2  2 7 35 350 
# 6 2 4.2  3 6 40 400 
0

Trate de usar el paquete reshapeGUI. Utiliza el paquete plyr y el paquete reshape2 y le proporciona una interfaz fácil de usar que le permite previsualizar su remodelación antes de ejecutarla.También le da el código para la remodelación que está haciendo para que pueda pegarlo en su secuencia de comandos para reproducirlo y para que pueda aprender a usar los comandos fundir y lanzar en reshape2. Es una buena muleta para manipulaciones complejas de datos como esta para aquellos que no cambian la forma de los ninjas.

0

Aquí hay dos enfoques más recientes que podrían ser de interés para alguien que lee esta pregunta:

Opción 1: El tidyverse

library(tidyverse) 
x %>% 
    gather(var, val, -id, -v) %>% 
    extract(var, into = c("header", "source"), regex = "([a-z])([0-9])") %>% 
    spread(header, val) 
# id v source x y z 
# 1 1 2.5  1 2 10 200 
# 2 1 2.5  2 4 20 150 
# 3 1 2.5  3 5 15 170 
# 4 2 4.2  1 3 25 300 
# 5 2 4.2  2 7 35 350 
# 6 2 4.2  3 6 40 400 

Opción 2: data.table

library(data.table) 
setDT(x) 
melt(x, measure.vars = patterns("x", "y", "z"), 
    value.name = c("x", "y", "z"), 
    variable.name = "source") 
# id v source x y z 
# 1: 1 2.5  1 2 10 200 
# 2: 2 4.2  1 3 25 300 
# 3: 1 2.5  2 4 20 150 
# 4: 2 4.2  2 7 35 350 
# 5: 1 2.5  3 5 15 170 
# 6: 2 4.2  3 6 40 400 
Cuestiones relacionadas