Representando gráficamente conjuntos de datos pequeños

Últimamente me están llegando conjuntos de datos para analizar con muy pocos registros. He aquí un subconjunto de uno de ellos (de hoy y debidamente anonimizado):

nivel.proteina <- c( 11.56, 10.43, 11.00, 10.92, 10.08, 9.98, 10.35,
  9.55, 9.19, 7.00, 6.72, 6.43, 7.43, 7.26, 6.67,  7.49, 8.03, 8.17,
  6.79, 7.68, 7.01, 7.51, 6.90, 7.27, 7.56, 8.61, 8.16, 7.12 )
grupo <- c(0,0,0,0,0,0,0,0,0,
  1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1)
datos <- data.frame( nivel.proteina, grupo )

Le he estado dando vueltas a la manera de representar gráficamente este tipo de conjunto de datos de la manera en que deben hacerse estas cosas: que con un mero golpe de vista pueda hacerse uno con ellos.

Sin pensar demasiado, a uno se le ocurre utilizar diagramas de cajas mediante un —posiblemente demasiado— espartano

boxplot( nivel.proteina ~ grupo, dat = datos )

que genera esto:

Pero para conjuntos de datos tan pequeños, las cajas no acaban de satisfacerme: sustituyen —tal vez demasiado filosóficamente— el dato mismo por una respresentación conceptual suya: es como llamar bosque a un conjunto de tan sólo 18 árboles. Así que utilizando unos gráficos que vi en el libro de Pinheiro y Bates, hice

library( nlme )
datos.agrupados <- groupedData( nivel.proteina ~ 1 | grupo, data = datos )
plot( datos.agrupados )

para obtener

¿A alguien le parece más claro?

¿Conocerá alguno de mis lectores alguna ruta menos intrincada para crear un gráfico análogo?

11 comentarios sobre “Representando gráficamente conjuntos de datos pequeños

  1. esanmiguel 17 septiembre, 2010 6:57

    ¿y el mitico «plot(nivel.proteina , col = (grupo+2) , pch = grupo)» ?

    Un saludo

  2. datanalytics 17 septiembre, 2010 9:58

    ¿Y cuando el grupo es un factor (que, en realidad, lo es)? Ya, supongo que se puede hacer jugando con las etiquetas de los ejes, etc.

    ¡Pero sería aún más «intrincado»!

  3. carlosortega 17 septiembre, 2010 13:21

    Varias cosas:

    1. Puedes utilizar la librería lattice para hacer lo mismo que con la de nlme con strippot.
    2. O sin ninguna librería adicional con esto que creo que hace ganar un poco de entendimiento para el caso en el que los datos lleguen a superponerse:
    datos.m<-tapply(nivel.proteina, grupo, FUN=mean)
    dotchart(
    nivel.proteina, groups=as.factor(grupo),
    xlab="Nivel Proteina", ylab="Grupo",
    gdata=datos.m, gpch=19
    )
    legend(
    "bottomright", c("values", "mean"),pch=c(1,19), bg="white"
    )

  4. rvaquerizo 20 septiembre, 2010 15:03

    Yo pondría densidades. Pero es porque quedan muy bonitas las montañitas:

    d1=subset(datos,grupo==1)
    d1=density(d1$nivel.proteina)
    d0=subset(datos,grupo==0)
    d0=density(d0$nivel.proteina)

    win.graph()
    minimo=floor(min(datos$nivel.proteina))
    maximo=ceiling(max(datos$nivel.proteina))

    plot(d0,xlim=c(minimo,maximo),ylim=c(0,0.7),col=3)
    points(d1,type=»l»,col=4)

  5. datanalytics 21 septiembre, 2010 23:12

    Raúl, pero fíjate que hay una propiedad muy interesante en los datos que no refleja tu gráfico: que están separados, por ejemplo: no hay solape entre los puntos asociados a ambos grupos.

    Tampoco puedes hacerte una idea del tamaño del conjunto de datos, de cuántos puntos forman parte de él.

    Normalmente las densidades y demás pueden servirnos para describir bosques; pero en otras ocasiones merece la pena mostrar los árboles que lo componen en su individualidad. Esto es, de hecho, lo que motivó la entrada: crear un gráfico que permitiese al lector forjarse una idea del conjunto sin perder de vista a sus individuos.

  6. datanalytics 21 septiembre, 2010 23:15

    Bonito el gráfico, Carlos. Hice alguno parecido pero más básico (sin el promedio, etc.), pero buscaba algo más sintético. ¡Convengo en que es cuestión de gustos!

  7. rvaquerizo 1 octubre, 2010 13:02

    library(ggplot2)
    gf <- ggplot(datos, aes(factor(grupo),nivel.proteina))
    gf + geom_boxplot() + geom_jitter()

  8. Emilio 12 marzo, 2011 11:37

    Este gráfico es un poco más complicado que el que propone Vaquerizo y está hecho con lattice.
    Pero creo que los usuarios no estadísticos lo entienden muy bien y normalmente les gusta mucho, sobre todo cuando lo asocias a contrastes de medias o no paramétricos.
    Emilio

    nivel.proteina <- c( 11.56, 10.43, 11.00, 10.92, 10.08, 9.98, 10.35,
    9.55, 9.19, 7.00, 6.72, 6.43, 7.43, 7.26, 6.67, 7.49, 8.03, 8.17,
    6.79, 7.68, 7.01, 7.51, 6.90, 7.27, 7.56, 8.61, 8.16, 7.12 )
    grupo <- c(0,0,0,0,0,0,0,0,0,
    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1)

    x <- as.factor(grupo)
    y <- nivel.proteina

    library(lattice)
    medianasinna <- function(x) median(x, na.rm=TRUE)
    mediasinna <- function(x) mean(x, na.rm=TRUE)

    puntosxy <- stripplot(y ~ x
    , jitter.data = TRUE
    , ylab = "Nivel"
    , xlab = "Grupo"
    , main = "Nivel y grupo"
    , type = c("p", "a")
    , auto.key=list(text=c("Media","Mediana")
    , lines=TRUE
    , points=FALSE
    , space="top"
    , columns=2)
    , panel = function(x, y, jitter.data, …)
    {
    panel.stripplot(x, y,jitter.data=TRUE, …)
    panel.average(x, y, fun= medianasinna, col="red", … )
    panel.average(x, y, fun= mediasinna, col="blue",… )
    }
    )

    print(puntosxy)

  9. Emilio 12 marzo, 2011 12:18

    Carlos,
    perdona, creo que he tenido problema con el navegador y he enviado varias veces lo mismo, Por favor, elimina las diferentes versiones y coge sólo la última Gracias
    Emilio

Los comentarios están desabilitados.