Visualizando muchas variables en una parcela

25

Me gustaría mostrar cómo los valores de ciertas variables (~ 15) cambian con el tiempo, pero también me gustaría mostrar cómo las variables difieren entre sí en cada año. Entonces creé esta trama:

ingrese la descripción de la imagen aquí

Pero incluso al cambiar el esquema de color o agregar diferentes tipos de línea / forma, esto parece desordenado. ¿Hay una mejor manera de visualizar este tipo de datos?

Datos de prueba con código R:

structure(list(Var = structure(c(1L, 2L, 2L, 2L, 2L, 2L, 2L, 
2L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 5L, 5L, 5L, 5L, 5L, 5L, 5L, 6L, 
6L, 6L, 6L, 6L, 6L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 8L, 8L, 8L, 8L, 
8L, 8L, 8L, 9L, 9L, 9L, 9L, 9L, 9L, 9L, 11L, 11L, 11L, 11L, 11L, 
11L, 11L, 12L, 12L, 12L, 12L, 12L, 12L, 13L, 14L, 14L, 14L, 14L, 
14L, 14L, 14L, 16L, 16L, 16L, 16L, 16L, 16L, 17L, 17L, 17L, 17L, 
17L, 17L, 17L, 18L, 18L, 18L, 18L, 18L, 18L, 18L), .Label = c("A", 
"B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", 
"O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"), class = "factor"), 
    Year = c(2015L, 1991L, 1993L, 1996L, 2000L, 2004L, 2011L, 
    2015L, 1991L, 1993L, 1996L, 2000L, 2004L, 2011L, 2015L, 1991L, 
    1993L, 1996L, 2000L, 2004L, 2011L, 2015L, 1993L, 1996L, 2000L, 
    2004L, 2011L, 2015L, 1991L, 1993L, 1996L, 2000L, 2004L, 2011L, 
    2015L, 1991L, 1993L, 1996L, 2000L, 2004L, 2011L, 2015L, 1991L, 
    1993L, 1996L, 2000L, 2004L, 2011L, 2015L, 1991L, 1993L, 1996L, 
    2000L, 2004L, 2011L, 2015L, 1993L, 1996L, 2000L, 2004L, 2011L, 
    2015L, 2015L, 1991L, 1993L, 1996L, 2000L, 2004L, 2011L, 2015L, 
    1991L, 1993L, 1996L, 2000L, 2011L, 2015L, 1991L, 1993L, 1996L, 
    2000L, 2004L, 2011L, 2015L, 1991L, 1993L, 1996L, 2000L, 2004L, 
    2011L, 2015L), Val = c(25.6, 22.93, 20.82, 24.1, 24.5, 29, 
    25.55, 24.5, 24.52, 20.73, 25.8, 25.5, 29.5, 27.7, 25.1, 
    25, 24.55, 26.75, 25, 30.5, 27.25, 25.1, 22.4, 27.07, 26, 
    29, 27.2, 24.2, 23, 24.27, 27.68, 27, 30.5, 28.1, 24.9, 23.75, 
    22.75, 27.25, 25, 29, 28.45, 24, 20.25, 17.07, 24.45, 25, 
    28.5, 26.75, 24.9, 21.25, 20.65, 25.1, 24.5, 26.5, 25.35, 
    23.5, 21.93, 26.5, 24.5, 29, 29.1, 26.4, 28.1, 23.75, 26.5, 
    28.05, 27, 30.5, 25.65, 23.3, 23.25, 24.57, 26.07, 27.5, 
    28.85, 27.7, 22, 23.43, 26.88, 27, 30.5, 29.25, 28.1, 23, 
    23.8, 28.32, 27, 29.5, 29.15, 27.6)), row.names = c(1L, 4L, 
5L, 6L, 7L, 8L, 9L, 10L, 13L, 14L, 15L, 16L, 17L, 18L, 19L, 20L, 
21L, 22L, 23L, 24L, 25L, 26L, 27L, 28L, 29L, 30L, 31L, 32L, 35L, 
36L, 37L, 38L, 39L, 40L, 41L, 44L, 45L, 46L, 47L, 48L, 49L, 50L, 
53L, 54L, 55L, 56L, 57L, 58L, 59L, 62L, 63L, 64L, 65L, 66L, 67L, 
68L, 69L, 70L, 71L, 72L, 73L, 74L, 75L, 78L, 79L, 80L, 81L, 82L, 
83L, 84L, 87L, 88L, 89L, 90L, 91L, 92L, 95L, 96L, 97L, 98L, 99L, 
100L, 101L, 104L, 105L, 106L, 107L, 108L, 109L, 110L), na.action = structure(c(2L, 
3L, 11L, 12L, 33L, 34L, 42L, 43L, 51L, 52L, 60L, 61L, 76L, 77L, 
85L, 86L, 93L, 94L, 102L, 103L), .Names = c("2", "3", "11", "12", 
"33", "34", "42", "43", "51", "52", "60", "61", "76", "77", "85", 
"86", "93", "94", "102", "103"), class = "omit"), class = "data.frame", .Names = c("Var", 
"Year", "Val"))
ameba dice Reinstate Monica
fuente
2
¿Puedes publicar los datos? Es bastante fácil encontrar ejemplos más o menos similares, pero para mantener el hilo unido, las personas que tienen el mismo entorno limitado para jugar ayudarían. Además, ¿cuál es el significado de la zona verde?
Nick Cox
Ver también sugerencias en stats.stackexchange.com/questions/126480/…
Nick Cox
@NickCox ¡Claro, debería haber pensado en eso antes! Dejé la zona verde ya que no es esencial (solo muestra el rango de valores que se considera "suficiente")

Respuestas:

42

Afortunadamente o no, su ejemplo tiene un tamaño óptimo (hasta 7 valores para cada uno de los 15 grupos) primero, para mostrar que hay un problema gráficamente; y segundo, permitir otras soluciones bastante simples. El gráfico es de un tipo a menudo llamado espagueti por personas en diferentes campos, aunque no siempre está claro si ese término se entiende como afectuoso o abusivo. El gráfico muestra el comportamiento colectivo o familiar de todos los grupos, pero es bastante inútil mostrar los detalles a explorar.

Una alternativa estándar es mostrar los grupos separados en paneles separados, pero eso a su vez puede dificultar las comparaciones precisas de grupo a grupo; cada grupo está separado de su contexto de los otros grupos.

Entonces, ¿por qué no combinar ambas ideas: un panel separado para cada grupo, pero también mostrar a los otros grupos como telón de fondo? Esto depende crucialmente de resaltar el grupo que está enfocado y minimizar los demás, lo cual es bastante fácil en este ejemplo dado el uso del color de línea, grosor, etc. En otros ejemplos, las elecciones de marcadores o símbolos de puntos podrían ser naturales.

ingrese la descripción de la imagen aquí

En este caso, se destacan detalles de posible importancia o interés práctico o científico:

  1. Solo tenemos un valor para A y M.

  2. No tenemos todos los valores para todos los años dados en todos los demás casos.

  3. Algunos grupos trazan alto, algunos bajo, etc.

No intentaré una interpretación aquí: los datos son anónimos, pero esa es la preocupación del investigador en cualquier caso.

Dependiendo de lo que sea fácil o posible en su software, hay margen para cambiar pequeños detalles aquí, como si las etiquetas de los ejes y los títulos se repiten (hay argumentos simples a favor y en contra).

La cuestión más importante es hasta qué punto esta estrategia funcionará de manera más general. El número de grupos es el principal impulsor, más que el número de puntos en cada grupo. Hablando en términos generales, el enfoque podría funcionar hasta aproximadamente 25 grupos (una pantalla de 5 x 5, por ejemplo): con más grupos, no solo los gráficos se vuelven más pequeños y más difíciles de leer, sino que incluso el investigador pierde la inclinación a escanear todos paneles. Si hubiera cientos (miles, ...) de grupos, generalmente sería esencial seleccionar una pequeña cantidad de grupos para mostrar. Sería necesaria una combinación de criterios como la selección de algunos paneles "típicos" y algunos "extremos"; eso debe ser impulsado por los objetivos del proyecto y alguna idea de lo que tiene sentido para cada conjunto de datos. Otro enfoque que puede ser eficiente es enfatizar un pequeño número de series en cada panel. Asi que, Si hubiera 25 grupos amplios, cada grupo amplio podría mostrarse con todos los demás como telón de fondo. Alternativamente, podría haber algún promedio u otro resumen. Usar (por ejemplo) componentes principales o independientes también puede ser una buena idea.

Aunque el ejemplo requiere gráficos de líneas, el principio es naturalmente mucho más general. Los ejemplos pueden ser multiplicados, diagramas de dispersión, diagramas de diagnóstico del modelo, etc.

Algunas referencias para este enfoque [otros son bienvenidos]:

Cox, NJ 2010. Subconjuntos gráficos. Stata Journal 10: 670-681.

Knaflic, CN 2015. Cuentacuentos con datos: una guía de visualización de datos para profesionales de negocios. Hoboken, Nueva Jersey: Wiley.

Koenker, R. 2005. Regresión Cuantil . Cambridge: Cambridge University Press. Ver págs. 12-13.

Schwabish, JA 2014. Una guía del economista para visualizar datos. Journal of Economic Perspectives 28: 209-234.

Unwin, A. 2015. Análisis gráfico de datos con R. Boca Raton, FL: CRC Press.

Wallgren, A., B. Wallgren, R. Persson, U. Jorner y J.-A. Haaland 1996. Graficando estadísticas y datos: creando mejores gráficos. Newbury Park, CA: Sabio.

Nota: El gráfico se creó en Stata. subsetplotdebe instalarse primero con ssc inst subsetplot. Los datos se copiaron y pegaron desde R y las etiquetas de valor se definieron para mostrar años como 90 95 00 05 10 15. El comando principal es

subsetplot connected Val Year, by(Var) c(L) lcolor(gs12) backdrop(line) xtitle("") combine(imargin(small)) subset(lcolor(blue) mcolor(blue))

EDITAR Referencias adicionales mayo, septiembre, diciembre de 2016; Abril, junio de 2017, diciembre de 2018, abril de 2019:

Cairo, A. 2016. The Truthful Art: Data, Charts, and Maps for Communication. San Francisco, CA: Nuevos jinetes. p.211

Camões, J. 2016. Datos en el trabajo: mejores prácticas para crear cuadros efectivos y gráficos de información en Microsoft Excel . San Francisco, CA: Nuevos jinetes. p.354

Carr, DB y Pickle, LW 2010. Visualización de patrones de datos con Micromaps. Boca Ratón, FL: CRC Press. p.85.

Grant, R. 2019. Visualización de datos: gráficos, mapas y gráficos interactivos. Boca Ratón, FL: CRC Press. p.52.

Koponen, J. y Hildén, J. 2019. Manual de visualización de datos. Espoo: Aalto ARTS Books. Ver p.101.

Kriebel, A. y Murray, E. 2018. #MakeoverMonday: Mejorando cómo visualizamos y analizamos datos, un gráfico a la vez. Hoboken, Nueva Jersey: John Wiley. p.303.

Rougier, NP, Droettboom, M. y Bourne, PE 2014. Diez reglas simples para mejores cifras. PLOS Biología Computacional 10 (9): e1003833. doi: 10.1371 / journal.pcbi.1003833 enlace aquí

Schwabish, J. 2017. Mejores presentaciones: una guía para académicos, investigadores y wonks. Nueva York: Columbia University Press. Ver p.98.

Wickham, H. 2016. ggplot2: Gráficos elegantes para el análisis de datos. Cham: Springer. Ver p.157.

Nick Cox
fuente
+1, maravilloso, ¿hay una función R o SAS que sea capaz de hacer este tipo de gráfico? Es realmente genial.
pronosticador
¡Realmente me gusta esta idea! Solo me pregunto cuál es la mejor manera de trazar esto en R usando ggplot2. Solo esperaré un poco antes de aceptar la respuesta, espero que esté bien.
2
Lo siento, no tengo idea de cómo hacer algo en SAS. Seguramente cualquier cosa que Stata pueda hacer, R puede hacerlo igual o mejor, o eso dicen sus usuarios ...
Nick Cox
@NickCox No es un problema en absoluto, lo descubrí, se ve muy bien y es perfecto para mi propósito.
@NickCox, dos referencias más son 1. Los elementos de la representación gráfica de datos de WS Cleveland . Un nuevo libro, 2. Cuentacuentos con datos: una guía de visualización de datos para profesionales de negocios de Cole Nussbaumer Knaflic . Este libro (# 2) tiene un estudio de caso capítulo llamado "Estrategias para evitar el gráfico de espagueti".
pronosticador
22

Como complemento a la respuesta de Nick, aquí hay un código R para hacer un diagrama similar usando datos simulados:

library(ggplot2)

get_df <- function(label="group A", n_obs=10, drift=runif(1)) {
    df <- data.frame(time=seq(1, n_obs), label=label)
    df$y <- df$time * drift + cumsum(rnorm(n_obs))
    return(df)
}
df_list <- lapply(sprintf("group %s", toupper(letters[1:9])),
                  function(label) { get_df(label) })
df <- do.call(rbind, df_list)
df$label2 <- df$label

p <- (ggplot(df, aes(x=time, y=y, group=label2)) +
      geom_line(size=0.9, alpha=0.8,
                data=df[, c("time", "y", "label2")], color="grey") +
      geom_line(size=1.1, color="black") +
      ylab("") +
      theme_bw() +
      theme(panel.border=element_blank()) +
      theme(strip.background=element_blank()) +
      facet_wrap(~ label))
p
ggsave("example_facet.png", p, width=10, height=8)

trama de ejemplo

Adrian
fuente
6

Para aquellos que quieran utilizar un ggplot2enfoque en R, considere la facetshadefunción en el paquete extracat. Esto ofrece un enfoque general, no solo para gráficos de líneas. Aquí hay un ejemplo con diagramas de dispersión (desde el pie de esta página ):

data(olives, package="extracat")
library(scales)
fs1 <- facetshade(data = olives,
                  aes(x = palmitic, y = palmitoleic), f = .~Area)
fs1 + geom_point(colour = alpha("black", 0.05)) +
      geom_point(data = olives, colour = "red") +
      facet_wrap(f=~Area, nrow=3) + theme(legend.position="none")

ingrese la descripción de la imagen aquí


EDITAR: Usando el conjunto de datos simulados de Adrian de su respuesta anterior:

library(extracat)
facetshade(df, aes(x=time, y=y), f = .~label, bg.all = FALSE, keep.orig = TRUE) +
           geom_line(aes(x=time, y=y, group=orig.label),colour = alpha(1,0.3)) +
           geom_line(data=df, aes(colour=label), size = 1.2) + xlab("") + ylab("")

Otro enfoque es dibujar dos capas separadas, una para el fondo y otra para los casos resaltados. El truco es dibujar la capa de fondo usando el conjunto de datos sin la variable de facetado. Para el conjunto de datos de aceite de oliva, el código es:

data(olives, package="extracat")
ggplot(olives, aes(palmitic, palmitoleic)) + 
  facet_wrap(~Area, nrow=3) + 
  geom_point(data=olives %>% select(-Area), colour=alpha("black", 0.05)) + 
  geom_point(data=olives, colour="red") + 
  theme(legend.position="none")
Antony Unwin
fuente
1
Esto parece un buen enfoque general (+1), pero el ejemplo particular está más relacionado con un problema diferente. Un montón de diagramas de dispersión repetidos con regiones resaltadas de manera diferente no funcionará para la pregunta que trata sobre series de tiempo.
Sextus Empiricus
@martin En realidad lo es y esa es también la solución de Adrian. Tenga en cuenta que usa dos variables de etiquetado idénticas para que se pueda soltar en la capa de fondo. La idea de codificación es más obvia con la notación tidyverse a continuación y, como a menudo, el formato elegante de los gráficos puede enmascarar las partes importantes del código. ggplot(df %>% select(-label), aes(x=time, y=y, group=label2)) + geom_line(alpha=0.8, color="grey") + labs(y=NULL) + geom_line(data=df, color="red") + facet_wrap(~ label)
Antony Unwin
5

Aquí hay una solución inspirada en el cap. 11.3, la sección sobre "Datos de vivienda de Texas", en el libro de Hadley Wickham sobre ggplot2 . Aquí ajusto un modelo lineal a cada serie de tiempo, tomo los residuos (que se centran alrededor de la media 0) y dibujo una línea de resumen en un color diferente.

library(ggplot2)
library(dplyr)
#works with dplyr version 0.4.3.9000 from Github (hadley/dplyr@4f2d7f8), or higher

df1 <- as.data.frame(list(Var = structure(c(1L, 2L, 2L, 2L, 2L, 2L, 2L, 
                                 2L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 5L, 5L, 5L, 5L, 5L, 5L, 5L, 6L, 
                                 6L, 6L, 6L, 6L, 6L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 8L, 8L, 8L, 8L, 
                                 8L, 8L, 8L, 9L, 9L, 9L, 9L, 9L, 9L, 9L, 11L, 11L, 11L, 11L, 11L, 
                                 11L, 11L, 12L, 12L, 12L, 12L, 12L, 12L, 13L, 14L, 14L, 14L, 14L, 
                                 14L, 14L, 14L, 16L, 16L, 16L, 16L, 16L, 16L, 17L, 17L, 17L, 17L, 
                                 17L, 17L, 17L, 18L, 18L, 18L, 18L, 18L, 18L, 18L), .Label = c("A", 
                                                                                               "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", 
                                                                                               "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"), class = "factor"), 
               Year = c(2015L, 1991L, 1993L, 1996L, 2000L, 2004L, 2011L, 
                        2015L, 1991L, 1993L, 1996L, 2000L, 2004L, 2011L, 2015L, 1991L, 
                        1993L, 1996L, 2000L, 2004L, 2011L, 2015L, 1993L, 1996L, 2000L, 
                        2004L, 2011L, 2015L, 1991L, 1993L, 1996L, 2000L, 2004L, 2011L, 
                        2015L, 1991L, 1993L, 1996L, 2000L, 2004L, 2011L, 2015L, 1991L, 
                        1993L, 1996L, 2000L, 2004L, 2011L, 2015L, 1991L, 1993L, 1996L, 
                        2000L, 2004L, 2011L, 2015L, 1993L, 1996L, 2000L, 2004L, 2011L, 
                        2015L, 2015L, 1991L, 1993L, 1996L, 2000L, 2004L, 2011L, 2015L, 
                        1991L, 1993L, 1996L, 2000L, 2011L, 2015L, 1991L, 1993L, 1996L, 
                        2000L, 2004L, 2011L, 2015L, 1991L, 1993L, 1996L, 2000L, 2004L, 
                        2011L, 2015L), 
               Val = c(25.6, 22.93, 20.82, 24.1, 24.5, 29, 
                       25.55, 24.5, 24.52, 20.73, 25.8, 25.5, 29.5, 27.7, 25.1, 
                       25, 24.55, 26.75, 25, 30.5, 27.25, 25.1, 22.4, 27.07, 26, 
                       29, 27.2, 24.2, 23, 24.27, 27.68, 27, 30.5, 28.1, 24.9, 23.75, 
                       22.75, 27.25, 25, 29, 28.45, 24, 20.25, 17.07, 24.45, 25, 
                       28.5, 26.75, 24.9, 21.25, 20.65, 25.1, 24.5, 26.5, 25.35, 
                       23.5, 21.93, 26.5, 24.5, 29, 29.1, 26.4, 28.1, 23.75, 26.5, 
                       28.05, 27, 30.5, 25.65, 23.3, 23.25, 24.57, 26.07, 27.5, 
                       28.85, 27.7, 22, 23.43, 26.88, 27, 30.5, 29.25, 28.1, 23, 
                       23.8, 28.32, 27, 29.5, 29.15, 27.6)), 
               row.names = c(1L, 4L, 
                           5L, 6L, 7L, 8L, 9L, 10L, 13L, 14L, 15L, 16L, 17L, 18L, 19L, 20L, 
                           21L, 22L, 23L, 24L, 25L, 26L, 27L, 28L, 29L, 30L, 31L, 32L, 35L, 
                           36L, 37L, 38L, 39L, 40L, 41L, 44L, 45L, 46L, 47L, 48L, 49L, 50L, 
                           53L, 54L, 55L, 56L, 57L, 58L, 59L, 62L, 63L, 64L, 65L, 66L, 67L, 
                           68L, 69L, 70L, 71L, 72L, 73L, 74L, 75L, 78L, 79L, 80L, 81L, 82L, 
                           83L, 84L, 87L, 88L, 89L, 90L, 91L, 92L, 95L, 96L, 97L, 98L, 99L, 
                           100L, 101L, 104L, 105L, 106L, 107L, 108L, 109L, 110L), 
               na.action = structure(c(2L, 
                          3L, 11L, 12L, 33L, 34L, 42L, 43L, 51L, 52L, 60L, 61L, 76L, 77L, 
                          85L, 86L, 93L, 94L, 102L, 103L), 
                .Names = c("2", "3", "11", "12","33", "34", "42", "43", "51", "52", "60", 
                           "61", "76", "77", "85", "86", "93", "94", "102", "103"), class = "omit"), 
                class = "data.frame", .Names = c("Var","Year", "Val"))


df1 %>%
        group_by(Var) %>%
        do(mutate(.,resid = resid(lm(Val ~ Year, data=., na.action = na.exclude)))) %>%
        ggplot(aes(Year, resid)) +
        labs(y=paste0("Val "), x="Year") +
        geom_line(aes(group = Var), alpha = 1/5) +
        geom_line(stat = "summary", fun.y = "mean", colour = "red")

ingrese la descripción de la imagen aquí

knb
fuente
1
La idea principal aquí parece ser que podría agregar una curva de resumen de algún tipo para ayudar a la vista y la mente. De acuerdo, pero en su respuesta, podría explicar la compensación al cambiar a media (o nivel de referencia) 0 en lugar de abandonar las unidades y valores originales. Los expertos en la materia y / o clientes bien podrían pensar en términos de 24 o 28 o cualesquiera que sean los valores. Naturalmente, los datos aquí son solo un vehículo para la discusión, pero el punto es muy general.
Nick Cox