Tengo datos de una encuesta en línea donde los encuestados realizan un ciclo de preguntas de 1 a 3 veces. El software de la encuesta (Qualtrics) registra estos datos en varias columnas, es decir, Q3.2 en la encuesta tendrá columnas Q3.2.1.
, Q3.2.2.
y Q3.2.3.
:
df <- data.frame(
id = 1:10,
time = as.Date('2009-01-01') + 0:9,
Q3.2.1. = rnorm(10, 0, 1),
Q3.2.2. = rnorm(10, 0, 1),
Q3.2.3. = rnorm(10, 0, 1),
Q3.3.1. = rnorm(10, 0, 1),
Q3.3.2. = rnorm(10, 0, 1),
Q3.3.3. = rnorm(10, 0, 1)
)
# Sample data
id time Q3.2.1. Q3.2.2. Q3.2.3. Q3.3.1. Q3.3.2. Q3.3.3.
1 1 2009-01-01 -0.2059165 -0.29177677 -0.7107192 1.52718069 -0.4484351 -1.21550600
2 2 2009-01-02 -0.1981136 -1.19813815 1.1750200 -0.40380049 -1.8376094 1.03588482
3 3 2009-01-03 0.3514795 -0.27425539 1.1171712 -1.02641801 -2.0646661 -0.35353058
...
Quiero combinar todas las columnas QN.N * en columnas QN.N individuales ordenadas, y finalmente terminaré con algo como esto:
id time loop_number Q3.2 Q3.3
1 1 2009-01-01 1 -0.20591649 1.52718069
2 2 2009-01-02 1 -0.19811357 -0.40380049
3 3 2009-01-03 1 0.35147949 -1.02641801
...
11 1 2009-01-01 2 -0.29177677 -0.4484351
12 2 2009-01-02 2 -1.19813815 -1.8376094
13 3 2009-01-03 2 -0.27425539 -2.0646661
...
21 1 2009-01-01 3 -0.71071921 -1.21550600
22 2 2009-01-02 3 1.17501999 1.03588482
23 3 2009-01-03 3 1.11717121 -0.35353058
...
La tidyr
biblioteca tiene la gather()
función, que funciona muy bien para combinar un conjunto de columnas:
library(dplyr)
library(tidyr)
library(stringr)
df %>% gather(loop_number, Q3.2, starts_with("Q3.2")) %>%
mutate(loop_number = str_sub(loop_number,-2,-2)) %>%
select(id, time, loop_number, Q3.2)
id time loop_number Q3.2
1 1 2009-01-01 1 -0.20591649
2 2 2009-01-02 1 -0.19811357
3 3 2009-01-03 1 0.35147949
...
29 9 2009-01-09 3 -0.58581232
30 10 2009-01-10 3 -2.33393981
El marco de datos resultante tiene 30 filas, como se esperaba (10 individuos, 3 bucles cada uno). Sin embargo, la recopilación de un segundo conjunto de columnas no funciona correctamente: crea correctamente las dos columnas combinadas Q3.2
y Q3.3
, pero termina con 90 filas en lugar de 30 (todas las combinaciones de 10 personas, 3 bucles de Q3.2 y 3 bucles de Q3 .3; las combinaciones aumentarán sustancialmente para cada grupo de columnas en los datos reales):
df %>% gather(loop_number, Q3.2, starts_with("Q3.2")) %>%
gather(loop_number, Q3.3, starts_with("Q3.3")) %>%
mutate(loop_number = str_sub(loop_number,-2,-2))
id time loop_number Q3.2 Q3.3
1 1 2009-01-01 1 -0.20591649 1.52718069
2 2 2009-01-02 1 -0.19811357 -0.40380049
3 3 2009-01-03 1 0.35147949 -1.02641801
...
89 9 2009-01-09 3 -0.58581232 -0.13187024
90 10 2009-01-10 3 -2.33393981 -0.48502131
¿Hay alguna manera de usar múltiples llamadas para gather()
así, combinando pequeños subconjuntos de columnas como esta mientras se mantiene el número correcto de filas?
df %>% gather(loop_number, Q3.2, starts_with("Q3."))
seperate()
para dividir los valores de Q3.3 (y más allá) en sus propias columnas. Pero eso todavía parece una solución hacky realmente indirecta…spread
Estoy trabajando en una solución ahora: pdf %>% gather(question_number, Q3.2, starts_with("Q3.")) %>% mutate(loop_number = str_sub(question_number,-2,-2), question_number = str_sub(question_number,1,4)) %>% select(id, time, loop_number, question_number, Q3.2) %>% spread(key = question_number, value = Q3.2)
spread()
. Aunque las llamadas múltiples parecen inevitables de todos modos, ya sea que se trate de un montón de correosgenerate()
electrónicos que funcionan o de correosspread()
electrónicos anidados …Respuestas:
Este enfoque me parece bastante natural:
Primero reúna todas las columnas de preguntas, use
extract()
para separar enquestion
yloop_number
, luegospread()
pregunte nuevamente en las columnas.fuente
Esto se puede hacer usando
reshape
. Sindplyr
embargo, es posible .O usando
dplyr
Actualizar
Con
tidyr_0.8.3.9000
, podemos usarpivot_longer
para remodelar varias columnas. (Usando los nombres de columna cambiados degsub
arriba)NOTA: Los valores son diferentes porque no hubo una semilla establecida al crear el conjunto de datos de entrada
fuente
mutate(loop_number = as.numeric(L2))
antes de dejarlo caerL2
, y es perfecto.reshape
método por su código compacto, aunquedplyr
puede ser más rápido para grandes conjuntos de datos.reshape()
función, veo mi solución para lo que me parece una implementación tidyr bastante limpia.Con la actualización reciente de
melt.data.table
, ahora podemos fundir varias columnas. Con eso, podemos hacer:Puede obtener la versión de desarrollo desde aquí .
fuente
No está relacionado en absoluto con "tidyr" y "dplyr", pero aquí hay otra opción a considerar:
merged.stack
de mi paquete "splitstackshape" , V1.4.0 y superior.fuente
En caso de que sea como yo y no pueda averiguar cómo usar "expresión regular con grupos de captura"
extract
, el siguiente código replica laextract(...)
línea en la respuesta de Hadleys:El problema aquí es que la recopilación inicial forma una columna clave que en realidad es una combinación de dos claves. Elegí usar
mutate
en mi solución original en los comentarios para dividir esta columna en dos columnas con información equivalente, unaloop_number
columna y unaquestion_number
columna.spread
luego se puede utilizar para transformar los datos de formato largo, que son pares clave-valor(question_number, value)
en datos de formato amplio.fuente