34 votos

¿Línea gráfico tiene demasiadas líneas, hay una solución mejor?

Estoy tratando de graficar el número de acciones por parte de los usuarios (en este caso, "me gusta") a lo largo del tiempo.

Así que tengo "Número de acciones" como mi eje, mi eje x es el tiempo (semanas), y cada línea representa a un usuario.

Mi problema es que quiero ver en este tipo de datos para un conjunto de alrededor de 100 usuarios. Un gráfico de líneas, rápidamente se convierte en un lío embarullado con 100 líneas. Existe una mejor tipo de gráfico que puede utilizar para mostrar esta información? O debo buscar en ser capaz de alternar líneas individuales de encendido/apagado?

Me gustaría ver todos los datos a la vez, sino de ser capaz de discernir el número de acciones con alta precisión no es muy importante.

¿Por qué estoy haciendo esto

Para un subconjunto de mis usuarios (los usuarios), quiero encontrar a los que no han gustado a una nueva versión de la aplicación que fue implementado en una fecha determinada. Estoy buscando las caídas significativas en el número de acciones por parte de usuarios individuales.

32voto

jldugger Puntos 7490

Me gustaría sugerir un (estándar) análisis preliminar para eliminar los efectos principales de (a) la variación entre los usuarios, (b) la respuesta típica entre todos los usuarios para el cambio, y (c) la variación típica de un período de tiempo para el siguiente.

Un simple (por no decir la mejor) forma de hacerlo es realizar un par de iteraciones de "mediana polaco" en los datos para el barrido de usuario de las medianas y el periodo de tiempo en los camellones, luego suave de los residuos a lo largo del tiempo. Identificar el suaviza que cambiar mucho: son los usuarios a los que queremos destacar en el gráfico.

Debido a que estos son los datos de recuento, es una buena idea para re-expresar mediante una raíz cuadrada.

Como un ejemplo de lo que puede dar lugar, aquí es una simulación de 60 semanas conjunto de datos de 240 usuarios que normalmente realizan de 10 a 20 acciones por semana. Un cambio en todos los usuarios se produjo después de la semana 40. Tres de ellas fueron ", dijo" a responder negativamente para el cambio. La izquierda del gráfico muestra los datos en bruto: los recuentos de acción por el usuario (con los usuarios distinguen por el color) a lo largo del tiempo. Como se afirma en la pregunta, es un desastre. El derecho del gráfico muestra los resultados de este EDA-en los mismos colores como antes, con la inusualmente sensible a los usuarios automáticamente identificados y resaltado. La identificación--aunque es un poco ad hoc--es completa y correcta (en este ejemplo).

Figure 1

Aquí es el R código que genera estos datos y realizar el análisis. Se podría mejorar de varias maneras, incluyendo

  • Con un total mediana de polaco a encontrar los residuos, en lugar de sólo una iteración.

  • Suavizado de los residuos por separado antes y después del punto de cambio.

  • Tal vez el uso más sofisticado algoritmo de detección de outliers. La actual simplemente banderas de todos los usuarios cuya área de distribución de los residuos es más que el doble de la gama media. Aunque simple, es robusto y parece que funciona bien. (Configurable por el usuario valor, threshold, se puede ajustar para hacer esta identificación más o menos estrictas.)

Las pruebas sugiere sin embargo esta solución funciona bien para una amplia gama de cuentas de usuario, de 12 de 240 o más.

n.users <- 240        # Number of users (here limited to 657, the number of colors)
n.periods <- 60       # Number of time periods
i.break <- 40         # Period after which change occurs
n.outliers <- 3       # Number of greatly changed users
window <- 1/5         # Temporal smoothing window, fraction of total period
response.all <- 1.1   # Overall response to the change
threshold <- 2        # Outlier detection threshold

# Create a simulated dataset
set.seed(17)
base <- exp(rnorm(n.users, log(10), 1/2))
response <- c(rbeta(n.users - n.outliers, 9, 1),
              rbeta(n.outliers, 5, 45)) * response.all
actual <- cbind(base %o% rep(1, i.break), 
                base * response %o% rep(response.all, n.periods-i.break))
observed <- matrix(rpois(n.users * n.periods, actual), nrow=n.users)

# ---------------------------- The analysis begins here ----------------------------#
# Plot the raw data as lines
set.seed(17)
colors = sample(colors(), n.users) # (Use a different method when n.users > 657)
par(mfrow=c(1,2))
plot(c(1,n.periods), c(min(observed), max(observed)), type="n",
     xlab="Time period", ylab="Number of actions", main="Raw data")
i <- 0
apply(observed, 1, function(a) {i <<- i+1; lines(a, col=colors[i])})
abline(v = i.break, col="Gray")  # Mark the last period before a change

# Analyze the data by time period and user by sweeping out medians and smoothing
x <- sqrt(observed + 1/6)                        # Re-express the counts
mean.per.period <- apply(x, 2, median)
residuals <- sweep(x, 2, mean.per.period)
mean.per.user <- apply(residuals, 1, median)
residuals <- sweep(residuals, 1, mean.per.user)

smooth <- apply(residuals, 1, lowess, f=window)  # Smooth the residuals
smooth.y <- sapply(smooth, function(s) s$y)      # Extract the smoothed values
ends <- ceiling(window * n.periods / 4)          # Prepare to drop near-end values
range <- apply(smooth.y[-(1:ends), ], 2, function(x) max(x) - min(x))

# Mark the apparent outlying users
thick <- rep(1, n.users)
thick[outliers <- which(range >= threshold * median(range))] <- 3
type <- ifelse(thick==1, 3, 1)

cat(outliers) # Print the outlier identifiers (ideally, the last `n.outliers`)

# Plot the residuals
plot(c(1,n.periods), c(min(smooth.y), max(smooth.y)), type="n",
     xlab="Time period", ylab="Smoothed residual root", main="Residuals")
i <- 0
tmp <- lapply(smooth, 
       function(a) {i <<- i+1; lines(a, lwd=thick[i], lty=type[i], col=colors[i])})
abline(v = i.break, col="Gray")

16voto

Ted Puntos 854

En general me parece más de dos o tres líneas en una sola faceta de la trama empieza a ser difícil de leer (aunque todavía lo hago todo el tiempo). Así que este es un interesante ejemplo de lo que debe hacer cuando usted tiene algo que conceptualmente podría ser un 100 faceta de la parcela. Una manera posible es dibujar todas las 100 facetas, pero en lugar de tratar de llegar a todos ellos en la página a la vez, mirando de uno en uno en una animación.

De hecho, hemos utilizado esta técnica en mi trabajo - que originalmente hizo la animación que muestra de 60 diferentes gráficos de línea de fondo para un evento (el lanzamiento de una nueva serie de datos), entonces encontramos que, al hacerlo, en realidad nos recogió algunas de las características de los datos que no habían sido visibles en facetas parcelas con 15 o 30 facetas por página.

Así que aquí es una forma alternativa de presentar los datos en bruto, antes de empezar a extraer el usuario y típico de efectos en tiempo según lo recomendado por @whuber. Esto se presenta como una alternativa adicional para la presentación de los datos en bruto - estoy totalmente de recomendar que, a continuación, proceder con el análisis a lo largo de las líneas, tales como aquellos que él sugiere.

Una manera de conseguir alrededor de este problema es la de producir el 100 (o 240 en @whuber ejemplo de series de tiempo de las parcelas por separado y tejer juntos en una animación. El código de abajo va a producir 240 separado las imágenes de este tipo y, a continuación, puede usar gratis la película de lo que el software para convertir eso en una película. Por desgracia, la única manera de que yo pueda hacer esto y mantener una calidad aceptable era un 9MB archivo, pero si usted no necesita enviar a través de internet que puede no ser un problema y, de todos modos estoy seguro de que hay maneras de evitar que con un poco más de animación inteligente. El paquete de animación en R podría ser útil aquí (te permite hacer todo en una llamada de R), pero me he mantenido simple para esta ilustración.

He hecho la animación tal que atrae cada línea negra gruesa, a continuación, deja un pálido semi-transparente de color verde sombra detrás por lo que el ojo recibe un gradual de la imagen de la acumulación de datos. Hay tanto de los riesgos y las oportunidades en este - el orden en que las líneas se agregan dejará una impresión diferente, así que usted debe considerar lo que es significativo de alguna manera.

Aquí están algunos de los fotogramas de la película, que utiliza los mismos datos que @whuber generado: enter image description hereenter image description hereenter image description hereenter image description hereenter image description here

# ---------------------------- Data generation - by @whuber ----------------------------#

n.users <- 240        # Number of users (here limited to 657, the number of colors)
n.periods <- 60       # Number of time periods
i.break <- 40         # Period after which change occurs
n.outliers <- 3       # Number of greatly changed users
window <- 1/5         # Temporal smoothing window, fraction of total period
response.all <- 1.1   # Overall response to the change
threshold <- 2        # Outlier detection threshold

# Create a simulated dataset
set.seed(17)
base <- exp(rnorm(n.users, log(10), 1/2))
response <- c(rbeta(n.users - n.outliers, 9, 1),
              rbeta(n.outliers, 5, 45)) * response.all
actual <- cbind(base %o% rep(1, i.break), 
                base * response %o% rep(response.all, n.periods-i.break))
observed <- matrix(rpois(n.users * n.periods, actual), nrow=n.users)

# ---------------------------- The analysis begins here ----------------------------#

# Alternative presentation of original data 
# 
setwd("eg animation")

for (i in 1:n.users){
    png(paste("line plot", i, ".png"),600,600,res=60)
    plot(c(1,n.periods), c(min(observed), max(observed)), 
        xlab="Time period", ylab="Number of actions", 
        main="Raw data", bty="l", type="n")
    if(i>1){apply(observed[1:i,], 1, function(a) {lines(a, col=rgb(0,100,0,50,maxColorValue=255))})}
    lines(observed[i,], col="black", lwd=2)
    abline(v = i.break, col="Gray")  # Mark the last period before a change
    text(1,60,i)
    dev.off()
}

##
# Then proceed to further analysis eg as set out by @whuber

7voto

Zizzencs Puntos 1358

Seguro. En primer lugar, ordenados por el número promedio de acciones. Luego realizar gráficos de (digamos) 4, cada uno con 25 líneas, uno para cada cuartil. Esto significa que usted puede encoger los ejes (pero la etiqueta de la axis y claro). Con 25 líneas, se les pueden variar por tipo de línea y color y tal vez trazar el símbolo y Obtén cierta claridad

Luego Apile los gráficos verticalmente con el eje de una sola vez.

Esto sería bastante fácil en R o SAS (por lo menos si tiene v. 9 de SAS).

7voto

jem77bfp Puntos 344

Una de las cosas más fáciles a la es un boxplot. Usted puede ver inmediatamente cómo se mueven tus medias de la muestra y qué días tienen los valores más extremos.

day <- rep(1:10, 100)
likes <- rpois(1000, 10)
d <- data.frame(day, likes)
library(ggplot2)
qplot(x=day, y=likes, data=d, geom="boxplot", group=day)

enter image description here

Para el análisis individual sugiero tomando una pequeña muestra al azar de los datos y el análisis de series de tiempo separan.

0voto

James Baker Puntos 2936

Considero que cuando tu agotando si opciones tipo si gráfico configuración de gráfico introducción del tiempo a través de la animación es la mejor manera de mostrar porque te da un extra para trabajar con la dimensión y permite mostrar más información en una forma fácil de seguir. Su enfoque principal debe estar en la experiencia del usuario final.

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X