“Una imagen vale más que mil palabras” es una expresión común que afirma que cualquier tipo de representación visual puede transmitir información de manera más efectiva que una descripción verbal o un texto. De hecho, esta afirmación se sustenta en razones biológicas: la vista es uno de los sentidos más desarrollados de la especie humana, y la transmisión de información al cerebro humano es más sencilla cuando media una imagen, pues la comprensión de un texto requiere una mayor capacidad intelectual. Usualmente, cuando se abre un documento, la primera mirada se focaliza en los gráficos.
Esta razón explica la utilidad de los gráficos en cualquier estudio estadístico. Son otra manera de presentar los datos y ayudan a detectar relaciones, estructuras, patrones y tendencias. La elaboración de gráficos es, por tanto, muy importante en el proceso de comunicación de la información analizada.
Pero realizar un buen gráfico no es tan sencillo, pues requiere:
Captar la atención del lector;
Presentar la información de forma sencilla, clara y precisa;
No inducir a error;
Facilitar la comparación de datos y destacar tanto coincidencias como diferencias;
Ilustrar el mensaje, tema o trama del texto al que acompaña.
Comenzaremos la actividad estableciendo la carpeta de trabajo, sino se ha realizado previamente.
# setwd("...")
A continuación, se cargará el fichero alumnos_UC.RData. Este fichero puede descargarse en el disco duro y cargarse en R a continuación.
load("alumnos_UC.Rdata")
set.seed(123)
Son esencialmente 3, aunque presentan diferentes variantes:
El gráfico de tallos y hojas.
El gráfico de barras.
El gráfico circular o de sectores.
Es una de las representaciones clásicas de datos cuantitativos, similar a un diagrama de barras pero en forma de texto. Para construirlo basta separar de cada dato el último dígito de la derecha (que constituye la hoja) del bloque de cifras restantes (que formará el tallo).
Figura 1: gráfico de tallo y hojas
Fue una de las herramientas propuestas por Tukey (1977) y muestra:
El centro de la distribución.
La forma general de la distribución, que puede ser:
Simétrica: las porciones a cada lado del centro son muy similares (forma de campana).
Sesgada: si la cola izquierda/derecha (los valores menores/mayores) es mucho más larga que los de la derecha/izquierda (los valores mayores/menores).
Outliers: observaciones individuales alejadas del patrón general de los datos.
Datos ausentes: aparecen como huecos sin datos en el gráfico.
Es un gráfico simple, fácil de realizar (incluso a mano) pero su uso no es habitual, en parte porque no es muy útil cuando el número de observaciones es elevado.
Figura 2: sintaxis de la función
stem()
Ejemplo
<- c(12, 15, 16, 21, 24, 29, 30, 31, 32, 33, 45, 46, 49, 50, 52, 58, 60, 63, 64, 65)
datos stem(datos)
Por defecto, los datos aparecen agrupados. El argumento
scale = 2
sirve para desagruparlos:
stem(datos,
scale = 2)
De acuerdo con este gráfico, la mayor frecuencia de valores corresponde a la decena de 30 y la distribución no es totalmente simétrica, ya que la cola se desplaza hacia la derecha.
rm(datos)
Se utiliza para representar las frecuencias absolutas o relativas de una variable cualitativa (a veces, una cuantitativa discreta con un número reducido de categorías).
Se elabora a partir de una tabla de frecuencias. Constituye un gráfico cartesiano; habitualmente en el eje horizontal se ubican las categorías o niveles de la variable, mientras que en el vertical se representa la cantidad (frecuencia absoluta) o la frecuencia relativa de cada categoría. Las categorías pueden ordenarse alfabéticamente, facilitando la comparación de los datos.
Figura 3: gráfico de barras`
El diagrama de barras también puede adoptar una orientación horizontal: en este caso las categorías se sitúan en el eje vertical y las barras crecen horizontalmente. Suelen usarse cuando hay muchas categorías o sus nombres son largos.
Tipos de gráficos de barras:
Básico: representa una única variable.
Agrupadas: representa simultáneamente diferentes variables, mediante barras de diferente color o textura.
Figura 4: gráfico de barras apiladas`
Figura 5: gráfico de barras apiladas`
La función de R que genera gráficos de barras es
barplot()
seguido de una serie de argumentos, tomando como
fuente una tabla de frecuencias. La tabla de frecuencias pueden
proporcionar tanto la frecuencia absoluta o como la relativa. Por
defecto, R crea el diagrama de barras con frecuencias absolutas.
Dos opciones:
<- table(df$grupo_sanguineo) # Paso 1: creación de un objeto tabla
tabla_sang
barplot(tabla_sang, # Paso 2: dibujamos el diagrama de barras a partir de la tabla
main = "Frequencia absoluta", # Título del gráfico.
col = rainbow(8)) # Cada barra -4- con un color diferente (arcoiris)
table()
en barplotbarplot(table(df$grupo_sanguineo),
main = "Frecuencia absoluta",
col = rainbow(8)) # Cada barra -4- con un color diferente (arcoiris)
Argumentos opcionales para la configuración del diagrama de barras
Figura 6: argumentos de la función
barplot()
Para elaborar un gráfico de barras que incluya las
frecuencias relativas la función barplot()
se aplica a una tabla creada con la función prop.table()
,
debiendo multiplicarse el resultado por 100.
barplot(prop.table(tabla_sang) * 100,
main = "Frequencia relativa (%)",
ylim = c(0,50),
col = rainbow(8))
Dos posibles mejoras consisten en la inclusión de los valores correspondientes a la altura de las barras (frecuencia absoluta o relativa) y dibujar una línea de rejilla debajo de las barras del gráfico. Para ello, debe recurrirse a un pequeño truco, dibujando primero el gráfico de barras lo más simple posible e ir superponiendo el resto de mejoras visuales.
# Gráfico de barras inicial
barplot(tabla_sang,
ylim = c(0,50),
xlab = "Rama de conocimiento",
ylab = "Número de alumnos")
# Líneas de rejilla superpuestas
grid(nx = NA,
ny = NULL,
lty = 2,
col = "black", lwd = 1)
# Gráfico de barras sobreimpuesto en forma de objeto
<- barplot(tabla_sang,
barp col = rainbow(8),
ylim = c(0,50),
add = TRUE)
# Valores de la altura de las variables
text(barp,
+ 1.5,
tabla_sang labels = tabla_sang) # Creamos un texto.
Uno de los problemas más comunes con los gráficos de barras es la superposición de la leyenda al gráfico, como en el siguiente ejemplo.
barplot(tabla_sang,
col = rainbow(8)) # Color de las barras. Uno por cada barra
legend("top",
legend = rownames(tabla_sang),
fill = rainbow(8))
Una posible solución es dibujar el gráfico sin leyenda y crear a
continuación una leyenda ex-profeso. Podemos mover la leyenda a la
derecha, fuera del gráfico de barras utilizando el argumento
inset
dentro de una lista pasada como parámetro al
argumento args.legend de la siguiente manera.
par(mar = c(5, 5, 4, 11)) # márgenes del lienzo según líneas. Por defecto mar = c(5, 4, 4, 2) abajo, izda, arriba, dcha.
barplot(tabla_sang,
xlab = "Grupo sanguíneo",
col = rainbow(8),
legend.text = rownames(tabla_sang), # Valores de la leyenda
args.legend = list(x = "right", inset = c(-0.30, 0))) # Argumentos de la leyenda
Volvemos a continuación a configurar el lienzo con sus valores por defecto.
par(mar = c(5, 4, 4, 2))
También es posible elaborar un gráfico de barras directamente a partir de un dataframe o de una lista. En el ejemplo que aparece a continuación los datos del dataframe no son los datos en bruto, sino que han sido previamente elaborados (en realidad, es una tabla de frecuencias convertida en dataframe)
<- data.frame(ColorCoche = c("rojo", "verde", "blanco", "azul"),
borrame num = c(3, 5, 9, 1))
barplot(height = borrame$num,
names = borrame$ColorCoche,
col = c("red", "green", "white", "blue"))
Es posible transformar una variable continua en discreta y
representarla por medio de un gráfico de barras. El procedimiento
consisten en anidar la función cut()
dentro de la función
table()
, para categorizar los datos, e incluir el argumento
breaks
indicando los límites inferior y superior de cada
categoría.
barplot(table(cut(df$peso,
breaks = seq(40, 100, by = 10))))
Para elaborar un gráfico con las barras horizontales
se establece el argumento horiz = TRUE
.
barplot(tabla_sang,
main="Grupo sanguíneo",
col=c("red","green","yellow", "pink", "blue", "purple", "magenta", "black"),
las = 1, #Etiquetas del eje vertical horizontales
horiz = TRUE)
De nuevo, en este caso es común que las etiquetas del eje vertical queden fuera del área de trabajo.
par(mar = c(5, 14, 4, 2)) # márgenes del lienzo según líneas. Por defecto mar = c(5, 4, 4, 2) abajo, izda, arriba, dcha.
<- table(df$rama_conocimiento_let)
tabla_rama
barplot(tabla_rama,
main="Grupo sanguíneo",
col=c("red","green","yellow", "blue", "purple", "magenta"),
las = 1, #Etiquetas del eje vertical horizontales
horiz = TRUE)
par(mar = c(5, 4, 4, 2))
rm(tabla_sang, tabla_rama, borrame, barp)
Desafío
A partir del dataframe zonas_verdes
:
Crea un diagrama de barras clásico representando la frecuencia absoluta de parques con obras y sin obras.
El gráfico deberá tener por título “Parques de Madrid en obras”.
El eje X deberá tener la etiqueta “Estado actual”.
La etiqueta del eje Y deberá ser “Número de parques”.
Ajusta los valores del eje Y para que la altura de las barras no sobresalga por encima del valor máximo de dicho eje.
La barra correspondiente a los valor “No” tendrá un color verde y la barra “Si” un color rojo.
Crea un diagrama de barras horizontal representando la frecuencia
relativa de la variable barrios
.
El gráfico deberá tener por título “Número de Parques según barrios de Madrid”.
El eje X deberá tener la etiqueta “Porcentaje sobre el total”.
Ajusta los valores del eje X para que la longitud de las barras no sobresalga por encima del valor máximo de dicho eje.
Utiliza la gama de colores del arcoiris para que cada una de las barras tenga un color diferente.
Se obtiene cuando se aplica la función barplot()
a una
tabla con dos variables (bidimensional), con dos posibilidades
dependiendo del argumento beside
:
Si es “FALSE” barras apiladas;
Si “TRUE” barras yuxtapuestas.
Primero debe crearse una tabla denominada “de doble entrada”, con dos variables simultáneas:
<- table(df$genero,
tabla_procedencia_genero $rama_conocimiento_let) df
barplot(tabla_procedencia_genero,
main = "Gráfico de barras apiladas",
sub = "Subtítulo",
col = c("red", "yellow"),
ylim = c(0, 30),
xlab = "Etiqueta eje X",
ylab = "Etiqueta eje Y",
axes = TRUE)
OPCION 2: barras yuxtapuestas
barplot(tabla_procedencia_genero,
main = "Gráfico de barras yuxtapuestas",
sub = "Subtítulo",
xlab = "Etiqueta eje X",
ylab = "Etiqueta eje Y",
axes = TRUE,
col = c("Green", "Blue"),
beside = TRUE)
Desafío
A partir de una tabla que combine la frecuencia de valores de las
variables rama_conocimiento_let
y genero
del
dataframe df
crea un gráfico de barras
apiladas con la frecuencia de ambas variables y las siguientes
características:
El gráfico deberá tener por título “Elección de la rama de conocimiento según género”.
La etiqueta del eje X es “Género” y deberá estar acompañada por un subtítulo con la siguiente inscripción “Curso 2022-2023”.
Ajusta los valores del eje X para que la longitud de las barras no sobresalga por encima del valor máximo de dicho eje.
La etiqueta del eje Y es “Porcentaje de alumnos”.
Utiliza la siguiente gama de colores: c(“red”,“green”,“yellow”, “blue”, “purple”, “magenta”, “orange”).
Incluye una leyenda a la derecha, que no invada las columnas, en la que aparezcan los nombres de las ramas de conocimiento con sus respectivos colores.
A partir de una tabla que combine la frecuencia de valores de las
variables barrio
y obras
del dataframe
zonas_verdes
crea un gráfico de barras
yuxtapuestas con las siguientes características:
El gráfico deberá tener por título “Estado de las obras en los parques de Madrid”.
La etiqueta del eje X es “Parques” y deberá estar acompañada por un subtítulo con la siguiente inscripción “Año 2023”.
Ajusta los valores del eje X para que la longitud de las barras no sobresalga por encima del valor máximo de dicho eje.
La etiqueta del eje Y es “Número de parques”.
Utiliza la siguiente gama de colores: c(“red”,“green”,“yellow”, “blue”, “purple”, “magenta”, “orange”).
Incluye una leyenda a la derecha, que no invada las columnas, en la que aparezcan los nombres de los barrios con sus respectivos colores.
Los spineplots son una generalización de los gráficos de barras apilados. Un gráfico de mosaico es un spineplot para dos o más variables. Como en los casos anteriores, se requiere una tabla de frecuencias.
spineplot(tabla_procedencia_genero,
col = c("yellow", "orange", "red", "magenta", "green"),
border = c("darkblue", "black")) # Color del borde de las barras
Un spine plot transpuesto es un gráfico de barras clásico.
spineplot(t(tabla_procedencia_genero)) # Trasposición de variables
Por defecto, la función spineplot()
crea un spineplot,
pero estableciendo off = 0
se creará una variante,
denominada “espinograma”, eliminando la distancia entre las barras.
spineplot(tabla_procedencia_genero,
off = 0)
rm(tabla_procedencia_genero)
También conocidos como gráfico de Marimekko, o gráfico de barras apiladas porcentuales. Es una extensión multidimensional de los gráficos de barras al permitir la visualización de dos o más variables cualitativas. Permite reconocer relaciones entre diferentes variables; por ejemplo, la independencia se muestra cuando las casillas de las categorías tienen todas las mismas áreas.
Al igual que con los gráficos de barras, en este caso es el área de los mosaicos, también conocida como tamaño del contenedor, el que es proporcional al número de observaciones dentro de esa categoría, es decir, que en la tabla de frecuencias original, cada entrada corresponde a un rectángulo cuyo área es proporcional a ese valor
mosaicplot(procedencia ~ genero,
data=df,
main="gráfico de Mosaico",
cex.axis=1, # TamaÁ±o de las etiquetas ejes X e Y
las=1,
col=c("pink","lightblue","red","green"))
El diagrama de Pareto, también llamado curva cerrada o Distribución A-B-C, combina barras y líneas.
Como en el gráfico de barras clásico, en el eje horizontal se representan las categorías de la variable que queremos estudiar y la altura de las barras es proporcional al valor de cada categoría, pero están ordenadas por frecuencias de forma descendente.
En el eje vertical derecho se muestra la escala de porcentajes
En el eje vertical izquierdo se representa la escala de frecuencias.
La línea representa el porcentaje acumulado de dichas frecuencias respecto el total.
Figura 3: gráfico de barras`
Este gráfico se fundamenta en el principio de Pareto.
Principio de Pareto:
El principio de Pareto, también conocido como la regla del 80-20 y ley de los pocos vitales, describe el fenómeno estadístico por el que, en cualquier población que contribuye a un efecto común, una proporción pequeña de casos (20 % de los casos) contribuye a la mayor parte (el 80%) de los efectos, ya que la distribución de los efectos como sus posibles causas no es un proceso lineal.
Recibe uno de sus nombres en honor a Vilfredo Pareto, que lo enunció por primera vez en su Cours d’économie politique (Curso de economía política) de 1896. Pareto formuló este principio tras un estudio acerca de la distribución de la riqueza con el que estableció que la desigualdad económica es inevitable en cualquier sociedad.
El principal uso de este tipo de gráfico es establecer un orden de prioridades en la toma de decisiones (asignar un orden de prioridades), ya que en el gráfico los “pocos vitales” aparecen a la izquierda y los “muchos triviales” a la derecha.
En R se puede elaborar con la función pareto.chart()
del
paquete qcc
.
library(qcc)
Podemos seguir diferentes opciones:
table()
y posterior activación de la función pareto.chart()
sobre
esa tabla.<- table(df$grupo_sanguineo)
tabla_gs
pareto.chart(tabla_gs,
main="Diagrama de Pareto",
xlab="Grupo sanguíneo",
ylab="Frecuencia absoluta",
ylab2="Frecuencia relativa acumulada",
las = 1,
col=heat.colors(length(df$procedencia)))
pareto.chart(table(df$grupo_sanguineo))
pareto.chart(table(df$grupo_sanguineo),
plot=FALSE)
rm(tabla_gs)
Un gráfico de sectores es una representación circular de las frecuencias de una variable cualitativa o discreta. El círculo representa todos los valores analizados y cada porción, también llamada sector, representan la proporción de cada categoría de la variable. Aunque las frecuencias pueden aparecer en forma absoluta, el gráfico circular suele expresarse en porcentajes. Sólo es útil cuando el número de categorías es pequeño.
En R este tipo de gráfico también se realiza a partir de una tabla; esta puede haber sido creada previamente o se pueden crear también anidando, como en el caso del gráfico de barras
<- table(df$uso_movil) tabla_movil
Ejemplo desarrollado con argumentos opcionales
pie(tabla_movil,
main="Uso del móvil por los alumnoas de la UC",
radius = 1.05, # Tamaño del gráfico de -1 a 1 (por defecto 0.8). Etiquetas largas necesitan radios pequeños.
edges = 200, # Aproxima la linea exterior circular mediante un polígono con el número de lados especificado (por defecto 200). Con edges = 10 se obtiene un políogono.
init.angle = 95, # Ánngulo inicial de las porciones
clockwise = TRUE, # TRUE el orden de las porciones se dibuja según las agujas del reloj.
labels = c("Escaso","Moderado","Intenso"), # Etiquetas (siempre caracteres " ") de cada porción. En caso de querer que aparezca el número labels = count
cex = 2, # Tamaño de las etiquetas.
col = c("Green", "Yellow","red"), # Colores de relleno.
density = 50, # Densidad de las líneas de sombreado
angle = 45, # Ángulo de las líneas del sombreado.
border = "black", # Color del borde de cada porción. Para que el color sea igual al color del área border = color.
lty = 2) # Tipo de línea de los bordes del gráfico
Es muy habitual que el gráfico de sectores incluya las frecuencias relativas (porcentajes) en el gráfico. Dos opciones.
<- round(prop.table(tabla_movil) * 100, 2)
tabla_movil2 pie(tabla_movil2,
labels = paste0(tabla_movil2, "%"))
<- round(tabla_movil/sum(tabla_movil)*100) # Cálculo de los porcentajes
pct <- paste(names(tabla_movil), pct, "%") # Añadimos los porcentajes a las etiquetas
etiquetas pie(tabla_movil,
col=gray(seq(0.2, 1.0, length = 3)),
labels=etiquetas)
Para mostrar a la vez números y etiquetas
<- paste0(tabla_movil, " = ", round(100 * tabla_movil/sum(tabla_movil), 2), "%")
etiq pie(tabla_movil, labels = etiq)
Es una variante del gráfico de sectores. Para ello es necesario
cargar el paquete plotrix, que contiene la función
pie3D()
.
install.packages("plotrix")
library("plotrix")
library("RColorBrewer")
display.brewer.all()
pie3D(tabla_movil,
main="Diagrama circular en 3D", # Título del gráfico
col=brewer.pal(n = 3, name = "RdBu"), # Colores para rellenar o sombrear las porciones
labels = names(tabla_movil), # Etiquetas de las porciones
radius = 1.0, # Radio de la tarta
labelcex = 1, # Factor de expansión de las etiquetas
border = "yellow", # Color del borde de los sectores
shade = 0.3, # Sombreado del borde de los sectores
explode=0.1, # Cantidad de apertura de las porciones
height = 0.2, # Altura (grosor) del diagrama
theta = 0.8) # Ángulo de visión (radianes)
Como en el caso anterior, se pueden añadir los porcentajes, cambiar su color y tamaño etc.
<- paste0(round(tabla_movil/sum(tabla_movil) * 100, 2), "%")
lab pie3D(tabla_movil,
col = hcl.colors(length(tabla_movil), "Spectral"),
labels = lab,
labelcol = "red",
labelcex = 1.75)
rm(tabla_movil, tabla_movil2, etiquetas, pct)
Este tipo de gráfico (también conocido como gráfico de rosquilla) son otra variante de los gráficos de sectores. Para constuirlo se necesita el paquete lessR. Atención, en este caso no es necesario crear una tabla previa.
# install.packages(lessR)
library(lessR)
La función que crea este gráfico de donut es
pieChart()
.
PieChart(grupo_sanguineo,
data = df,
main = NULL)
La sintaxis anteriores es equivalente a:
pc(grupo_sanguineo, data = df,
main = NULL)
Es posible incluir una serie de argumentos adicionales para personalizar el gráfico
PieChart(grupo_sanguineo,
data = df,
fill = "viridis", # Color de los sectores mediante una paleta de colores prespecificadas (cambia a "blues" o "heat")
hole = 0.5, # Tamaño del agujero central: 0, un gráfico de sectores) a 0.99. El valor por defecto es 0.68.
color = "black", # Color de la línea del borde
lwd = 2, # Ancho de la línea del borde
lty = 1, # Tipo de línea del borde
hole_fill = "#B7E3E0", # Color del agujero central (blanco por defecto)
main = NULL)
También se puede crear una paleta de colores especial. Esta paleta debe ser de la misma longitud que el número de porciones.
<- hcl.colors(length(unique(df$grupo_sanguineo)), "Zissou 1")
col PieChart(grupo_sanguineo,
data = df,
fill = col,
main = NULL)
Personalización de las etiquetas de los valores. El argumento
values
se usa para:
Mantener los valores originales.
Eliminar los valores del gráfico.
Transformarlos en proporciones.
También puedes usar los argumentos values_size, values_digits, values_color y values_position para personalizarlos.
PieChart(grupo_sanguineo,
data = df,
fill = "viridis",
values = "input", # gráfico con los valores originales (input). Otras posibilidades: "off" sin datos, "prop" proporciones
main = NULL)
# Ejemplo adicional
PieChart(grupo_sanguineo,
data = df,
fill = "viridis",
main = NULL,
color = "black",
lwd = 1.5,
values_color = c(rep("white", 4), 1), # Personalización de los valores
values_size = 0.85)
Argumento rows: crea un subconjunto de los datos.
PieChart(grupo_sanguineo,
data = df,
rows = (procedencia == "Bahía" & genero == "Masculino"),
main = NULL)
Para este tipo de variables los gráficos más utilizados son:
El histograma.
El polígono de frecuencias.
El gráfico de caja y bigotes (“box-plot”).
Es uno de los tipos de gráficos más utilizados, y recuerda a simple vista el diagrama de barras, pero presenta algunas diferentes sustanciales.
El histograma representa la distribución de frecuencias de una variable cuantitativa continua, en la que, además de la altura el área de las columnas es proporcional a la frecuencia de un determinado intervalo de valores, y refleja la probabilidad con la que dicho intervalo puede presentarse.
Desde el punto de vista formal, además, las columnas están juntas y el punto medio de la columna sería el que identifica al intervalo. Éstos últimos no tienen por qué ser todos iguales (aunque es lo más habitual), pero siempre tendrán un área mayor aquellos intervalos con mayor frecuencia.
Gracias a este tipo de gráfico se obtiene una “primera impresión” de la distribución de una variable, deduciendo inicialmente su grado de dispersión, posibles sesgos etc… Su utilidad se hace más evidente cuando se cuenta con un gran número de datos, que se agrupan en intervalos de clase.
La función hist()
elabora un histograma, acompañado de
una serie de argumentos para modificar el histograma.
hist(df$peso,
main = "Título del histograma", # Título
freq = TRUE, # Si TRUE distribución de frecuencias, si FALSE distribución de densidad.
sub = "Subtítulo", # Subtítulo
xlab = "Etiqueta eje X", # Etiqueta eje X
ylab = "Etiqueta eje Y", # Etiqueta eje Y
ylim = c(0,25), # Valores del eje Y
col = "blue", # Color de las barras
border = "red", # Color del borde de las barras
density = 10, # Líneas de sombreado
angle = 20) # Ángulo de las líneas
Con el argumento plot = FALSE
podemos obtener los datos
numéricos resultado de la construcción del histograma
hist(df$peso,
plot = FALSE)
La función histograma sin gráfico devuelve una lista de 6 elementos
$breaks: intervalos.
$counts: número de observaciones en cada intervalo.
$density: frecuencia de valores de cada intervalo.
$mids: marcas
$xname : nombre de la variable en el eje horizontal
$equidist: valor lógico indicando si los intervalos estÁ¡n espaciados regularmente
Aunque el uso más frecuente implica dibujar un gráfico por variable, es posible la elaboración de histograma con dos variables simultáneas. Esto permite comparar la distribución de ambas variables al mismo tiempo.
<- subset(df,
masc =="Masculino")
genero<- subset(df,
fem =="Femenino")
genero
hist(masc$peso,
main = "Distribución del peso según el género",
ylab = "Frecuencia",
ylim = c(0, 15))
hist(fem$peso, add = TRUE, col = rgb(1, 0, 0, alpha = 0.5))
Pero como en el caso de las tablas para variables continuas, la creación de un histograma debería seguir los siguientes pasos.
- PASO 1: Número de clases (intervalos).
- PASO 2: Amplitud de los intervalos.
- PASO 3: Límites (superior e inferior de los intervalos)
- PASO 4: Valor representativo de cada intervalo (marca de clase)
La selección del número de clases es clave:
- Pocas clases agruparán demasiado las observaciones.
- Con demasiadas clases habrá pocas observaciones en cada una de ellas.
Ejemplo de estas circunstancias son los siguientes gráficos
# Una fila, dos columnas
par(mfrow = c(1, 2))
# Los siguientes gráficos se combinarán
hist(df$peso, breaks = 5, main = "Pocas clases", ylab = "Frecuencia")
hist(df$peso, breaks = 15, main = "Demasiadas clases", ylab = "Frecuencia")
# Volvemos al estado original
par(mfrow = c(1, 1))
El número de clases es controlado por el argumento
breaks
. Este argumento puede ser aplicado de diferentes
maneras.
<- min(df$peso)
min <- max(df$peso)
max
hist(df$peso,
breaks=c(50,65,80,95, 110), #Alternativa: crear objeto limites <- seq(50,110, by = 15) y sustituir breaks = limites
freq= TRUE, # Opción por defecto frecuencia relativa; FALSE absoluta.
ylim=range(0:60), # Atención: rango del eje vertical, que varía si es freq. abs o rel
col="lightblue",
right=FALSE,
main="Distribución del peso",
include.lowest=TRUE,
plot=TRUE)
abline(v=mean(df$peso), # v: valor del eje X por donde queremos que pase una recta vertical.
col="red",
lty=2,
lwd=2)
hist()
,
aplicando los algorítmos de Sturges (por defecto), Scott o
Fiedman-Diaconis.hist(df$peso,
breaks = "Sturges")
Una alternativa a los métodos precedentes para seleccionar el número
de clases es el método plug-in
que se utiliza para calcular
el tamaño de la ventana (intervalo) óptima (Wand, 1995).
# install.packages("KernSmooth")
library(KernSmooth)
<- dpih(df$peso) # Ventana óptima
ancho_barras
<- seq(min(df$peso) - ancho_barras, # Número de clases
nclases max(df$peso) + ancho_barras,
by = ancho_barras)
hist(df$peso, # Histograma
breaks = nclases,
main = "Método plug-in")
El paquete fdth()
permite reducir el tiempo empleado en
el análisis de variables cuantitativas, al proporcionar tanto una tabla
numérica como los gráficos correspondientes. - Instalación del
paquete
library(fdth)
<- fdt(df$peso, breaks = "Sturges") # calcula la distribución de frecuencias utilizando la regla Sturgess
tabla # Proporciona una tabla con los calculos de la distribución de frecuencias. tabla
par(mfrow=c(2,2)) # Fraccionamos la ventana grafica en 2x2.
plot(tabla, type="fh", main = "Histograma de frecuencias relativas")
plot(tabla, type="cfh", main = "Histograma de frecuencias acumuladas")
plot(tabla, type="fp", main = "Gráfico de líneas frecuencias relativas")
plot(tabla, type="cfp", main = "Gráfico de líneas frecuencias acumuladas")
# Dos opciones para volver a la distribución original de la pantalla (1 gráfico)
par(mfrow=c(1,1)) # Vuelve a la pantalla original
rm(ancho_barras, col, etiq, etiquetas, lab, max, min, nclases, pct,tabla)
Los polígonos de frecuencia se crean a partir de los histograma, uniendo el punto medio del techo de cada columna mediante segmentos de recta. Ese punto es siempre el intervalo de mayor frecuencia del conjunto. No es un gráfico con un gran uso.
library(agricolae)
En el siguiente ejemplo
Proporcionamos al programa los intervalos (limites
)
y las frecuencias absolutas (frecuencias
).
Con la función graph.freq()
se crea el histograma,
convertido en objeto z
, y sobre él se calcula el polígono
de frecuencias con la función polygon.freq()
.
<- seq(50,120,10)
limites <- c(8,10,16,14,10,5,2)
frecuencias <- graph.freq(limites,
z counts = frecuencias,
main="Polígono de frecuencias",
ylab = "Frecuencia")
polygon.freq(z,
frequency=1, # (1) recuento, (2) frecuencia relativa, (3) densidad
col="red",
lwd = 3)
Con los datos de peso y sustituyendo graph.freq
por
hist
.
<- hist(df$peso,
h1 col = "white",
border= "black")
polygon.freq(h1,
frequency = 1, # (1) recuento, (2) frecuencia relativa, (3) densidad
col="red",
lwd = 3)
rm(limites, frecuencias, z, h1)
Una curva de densidad es una representación idealizada de la distribución de una variable en la que el área bajo la curva equivale a 1 (o el 100%). La curva de densidad representa la función de densidad de una variable: esta a su vez refleja la probabilidad de que dicha variable alcance un valor determinado. La función de densidad se calcula mediante la siguiente fórmula:
(Número de observaciones en el intervalo/Número total de observaciones)/Longitud del intervalo.
La función hist()
crea por defecto un histograma de
frecuencias, que se transforma en un histograma de
densidad estableciendo prob = TRUE
.
hist(df$peso,
prob = TRUE,
ylim = c(0, 0.05),
main = "Histograma de densidad",
ylab = "Densidad")
O con el argumento freq = FALSE
.
hist(df$peso,
ylim = c(0,0.05),
main = "Histograma de densidad",
freq = FALSE)
Puede considerarse la función de densidad de probabilidad empírica
como una versión suavizada del histograma. Esta suavización también se
conoce como estimador de Parzen-Rosenblatt o estimador kernel.Para
agregar una curva de densidad se puede utilizar la
función density()
, con diferentes opciones:
hist(df$peso,
freq = FALSE,
main = "Histograma con gráfico de densidad superpuesto")
<- density(df$peso)
dens_peso lines(dens_peso,
lwd = 2,
col = "red")
plot(dens_peso,
lwd = 2,
col = "red",
main = "gráfico de densidad")
rug(jitter(df$peso)) # Añadir los datos en el eje X
Sobre estas dos opciones se puede incluir información adicional, por ejemplo, la curva de densidad de una distribución normal o el valor medio de esa variable.
hist(df$peso,
prob = TRUE,
ylim = c(0,0.05),
main = "Histograma con curva de densidad")
grid(nx = NA, ny = NULL, lty = 2, col = "gray", lwd = 1) # Superposición de un grid
lines(density(df$peso), col = "red", lwd = 2) # Curva de densidad
curve(dnorm(x,
mean=mean(df$peso), # Curva normal
sd=sd(df$peso)),
add=TRUE,
col="#00ff00",
lwd=3)
abline(v=mean(df$peso), # Línea vertical representando la media
lwd=2,
lty=3,
col="darkblue")
legend("topleft", # Leyenda
col=c("red","#00ff00"),
legend =c("Densidad normal estimada","Distribución normal"),
lwd=2,
bty = "n")
También se puede utilizar la siguiente función para crear automáticamente un histograma al que se le superpone una curva normal y otra de densidad.
<- function (x, ...) {
histDenNorm hist(x, ...) # Histograma
lines(density(x), col = "blue", lwd = 2) # Densidad
<- seq(min(x), max(x), length = 40)
x2 <- dnorm(x2, mean(x), sd(x))
f lines(x2, f, col = "red", lwd = 2) # Normal
legend("topright", c("Histograma", "Densidad", "Normal"), box.lty = 0, # Leyenda
lty = 1, col = c("black", "blue", "red"), lwd = c(1, 2, 2))
}
histDenNorm(df$peso,
prob = TRUE, ylim= c(0,0.05), main = "Histograma")
Una opción alternativa es el uso del paquete EnvStats.
install.packages("EnvStats")
library(EnvStats)
La función requerida para la creación de la curva es
epdfPlot()
.
epdfPlot(df$peso,
epdf.col = "red")
Cuando R dibuja una curva de densidad aparece un número (estimador
kernel) en la parte inferior, que es el valor que sirve para suavizar la
curva a partir de los datos originales. Es posible modificar ese valor
con el argumento bw()
. En general, un valor elevado suaviza
en exceso, mientras que uno pequeño actúa de manera contraria.
par(mfrow = c(1,2))
plot(density(df$peso, bw = 60), lwd = 2,
col = "red",
main = "Ancho de banda elevado")
plot(density(df$peso, bw = 0.05), lwd = 2,
col = "red",
main = "Ancho de banda pequeño")
par(mfrow = c(1,1))
Sintaxis equivalente con el paquete EnvStats
epdfPlot(df$peso,
epdf.col = "red",
density.arg.list = list(bw = 6),
main = "Ancho de banda intermedio")
La selección del ancho de banda depende de la variable que estamos analizando o de los objetivos de nuestro estudio. Pero su elección puede apoyarse en una serie de procedimientos objetivos:
plot(density(df$peso),
main = "Rule of thumb",
cex.lab = 1.5, cex.main = 1.75, lwd = 2)
plot(density(df$peso,
bw = bw.ucv(df$peso)), col = 2,
main = "Cross-validation", cex.lab = 1.5,
cex.main = 1.75, lwd = 2)
plot(density(df$peso,
bw = bw.SJ(df$peso)), col = 4,
main = "Plug-in bandwidth selection",
cex.lab = 1.5, cex.main = 1.75, lwd = 2)
Existen otros estimadores Kernel disponibles (“gaussian”,
“epanechnikov”, “rectangular”, “triangular,”biweight”, “cosine” y
“optcosine”) que se pueden cambiar con el argumento kernel
(por defecto Gaussian).
Con la función lines se pueden superponer diferentes curvas de
densidad en R. El procedimiento consiste en crear inicialmente un
gráfico de densidad y luego añadir la(s) nuevas líneas. En caso de que
no coincidan los valores de los ejes X e Y se deben incluir los xlim e
ylim con los valores máximo y mínimo de cada eje en la función
plot
, porque los límites se establecerán de forma
predeterminada a partir de la primera curva.
<- density(masc$peso)
dens_peso_masc <- density(fem$peso)
dens_peso_fem
plot(dens_peso_masc,
lwd = 2,
col = "red",
main = "Dos curvas superpuestas",
xlab = "",
ylim = c(0, 0.05))
lines(dens_peso_fem,
col = "blue",
lwd = 2)
Hay otras maneras de comparar densidades, por ejemplo la función
densityPlot()
del paquete car. Esta
función crea estimaciones de densidad no paramétricas condicionadas por
un factor.
library(car)
# Para obtener información adicional sobre la función y el método.
?densityPlot
$genero <- as.factor(df$genero)
df
densityPlot(df$peso, # Variable
$genero) # Factor df
Se puede usar la función polygon()
para sombrear el
Á¡rea bajo las curvas de densidad. Usando la función rgb()
en el argumento col
el área del diagrama de densidad puede
adquirir transparencia (argumento alpha
, que va desde 0,
que es transparencia total hasta 1, que dibuja el color opaco.
plot(dens_peso_masc, lwd = 4, main = "", xlab = "",
col = rgb(0, 0, 1, alpha = 0.3),
xlim = c(50, 110))
polygon(dens_peso_masc, col = "red")
lines(dens_peso_fem, lwd = 4, col = "yellow")
polygon(dens_peso_fem,
col = rgb(0, 0, 1, alpha = 0.3))
Alternativa equivalente con el paquete EnvStats
configurando los colores con el argumento curve.fill.col
de
la función epdfPlot()
.
install.packages("EnvStats")
library(EnvStats)
epdfPlot(df$peso, # Vector con datos
xlim = c(50, 110),
curve.fill = TRUE, # Colorear el área
curve.fill.col = rgb(1, 0, 0, alpha = 0.5), # Color del área
epdf.col = "red") # Color de la curva
epdfPlot(df$peso,
curve.fill = TRUE,
curve.fill.col = rgb(0, 0, 1, alpha = 0.5),
epdf.col = "blue",
add = TRUE) # Añade la densidad sobre el plot anterior
Consisten en un gráfico que permite observar algunas propiedades de una variable, como su centralidad (media, moda), su dispersión y su grado de simetría, así como definir valores atípicos.
Figura 6: gráfico de caja y bigotes apiladas`
Consiste en un rectángulo, alineado horizontal o verticalmente, en el que aparecen los tres cuartiles (1º, 2º y 3º), al igual que los valores mínimo y máximo de los datos, a partir de los cuales también se pueden definir el intervalo intercuartílico (ancho de la caja) así como los valores atípicos. Un valor atípico se define como aquel en el que un valor es mayor que Q3 + 1,5 IQR o menor que < Q1 - 1.5 * IQR, siendo Q1 primer cuartil, Q3 tercer cuartil.
par(mfrow=c(1,2)) # Fraccionamos la ventana grafica en 2x2.
boxplot(df$peso,
main = "Vertical")
boxplot(df$peso,
main = "Horizontal",
horizontal = TRUE) # Disposición horizontal
par(mfrow=c(1,1)) # Vuelta al gráfico inicial
Suele ser conveniente añadir una línea con el valor medio de la variable
boxplot(df$peso)
segments(x0 = 0.8, y0 = mean(df$peso), # Los puntos de inicio y de final de la línea se especifican con los argumentos x0, x1, y0 e y1.
x1 = 1.2, y1 = mean(df$peso),
col = "red",
lwd = 2,)
points(mean(df$peso), # Adición de un punto con la media
col = 3, # Color verde
pch = 19) # Tipo de símbolo
Creando un objeto a partir de la función boxplot()
, se
puede acceder a una lista con los diferentes componentes que proporciona
la función. Para ello, primero se crea el diagrama de caja y bigotes,
luego se almacena como objeto.
<- boxplot(df$peso) objeto
Finalmente, se pueden obtener los diferentes componentes de esa lista.
$stats # Cada fila contiene el bigote inferior, el primer cuartil, la mediana, el tercer cuartil y el bigote superior de cada grupo.
objeto$n # Número de observaciones de cada grupo.
objeto$conf # Extremos inferior y superior del intervalo de confianza de la mediana.
objeto$out # Valores atípicos. objeto
Una limitación de los gráficos de caja y bigotes es que no están diseñados para detectar variables con más de una moda (multimodalidad). Por ello, en ocasiones es recomendable combinar un diagrama de caja con un histograma o una curva de densidad.
# Histograma
hist(df$peso,
probability = TRUE,
ylab = "", # Sin etiquetas en el eje y
col = "grey", # Color de las barras del histograma
axes = FALSE, # Sin ejes
main = "") # Sin título
axis(1) # AÁ±adimos eje X
# Curva
lines(density(df$peso), col = "red", lwd = 2)
# Diagrama de caja y bigotes
par(new = TRUE)
boxplot(df$peso, horizontal = TRUE, axes = FALSE,
lwd = 2, col = rgb(0, 1, 1, alpha = 0.15))
Este tipo de gráfico permite analizar y comparar las características de una misma variable según dos o más grupos (factores).
boxplot(df$peso ~ df$genero)
abline(h = mean(df$peso),
col = 2,
lwd = 2) # Añade el valor medio
La sintaxis anterior es equivalente a ésta:
boxplot(peso ~ genero,
data = df,
notch = TRUE) # Intervalos de confianza al 95% para la mediana. Si no se superponen las medianas son diferentes estadísticamente.
Por defecto, los diagramas de caja se dibujan con el orden con el que
aparecen los factores en los datos originales. En ocasiones, puede ser
conveniente modificar dicho orden aplicando la función
reorder()
tomando como referencia la posición de cada grupo
respecto a un estadístico como la mediana o la media de los datos.
<- with(df, reorder(procedencia, peso, median))
mediana boxplot(df$peso ~ mediana,
las = 2)
<- with(df, reorder(procedencia, -peso, median))
mediana boxplot(df$peso ~ mediana,
las = 2)
Son una alternativa a los diagramas de caja que resuelven algunos de los problemas relacionados con la visualización de la distribución de los datos. Por ejemplo, a diferencia del diagrama de caja, que fundamentalmente muestra estadísticos básicos, los gráficos de violín también muestran la curva de densidad de cada variable.
El punto blanco representa la mediana.
La caja representa el rango intercuartílico.
Los límites del violín representan el resto de la distribución. Estos límites constituyen una estimación de una densidad (kernel) para mostrar la forma de la distribución de los datos. La sección ancha representa que esos valores tendran una alta probabilidad, mientras que la zona estrecha una baja probabilidad.
Figura 7: gráfico de violín`
Para dibujar este tipo de gráfico se necesita cargar el paquete vioplot y su función homónima.
install.packages("vioplot")
library("vioplot")
Función básica del paquete:
vioplot(df$peso,
horizontal = TRUE,
col = 2, # Color del área
rectCol = "red", # Color del rectángulo
lineCol = "white", # Color de la línea
colMed = "green", # Color del símmbolo pch
border = "black", # Color del borde del violín
pchMed = 16, # Símbolo pch para la mediana
plotCentre = "points") # Si "line", dibuja una línea en la mediana
Es posible dibujar un violin plot sin tener en cuenta los datos
atípicos. Para ese propósito, se puede asignar a una variable la salida
de la función boxplot()
y luego devolver los valores del
vector original que no son valores atípicos.
<- boxplot(df$peso)
box
<- df$peso[!(df$peso %in% box$out)] # Nos quedamos con los datos no atípicos
z vioplot(z)
Por último, ten en cuenta que puedes dibujar un violin plot sobre un histograma. Considera, por ejemplo, que la distribución subyacente de tus datos presenta multimodalidad. En este caso, un diagrama de caja y bigotes no representa esta condición, mientras que un gráfico de violín sí lo hará.
set.seed(1)
# Creación de un conjunto de datos multimodal.
<- 10000
n <- rbinom(n, 1, 0.5)
ii <- rnorm(n, mean = 130, sd = 10) * ii +
datos rnorm(n, mean = 80, sd = 5) * (1 - ii)
# Histograma
hist(datos, probability = TRUE, col = "grey", axes = FALSE,
main = "", xlab = "", ylab = "")
# Eje X
axis(1)
# Densidad
lines(density(datos), lwd = 2, col = "red")
# Violin plot
par(new = TRUE)
vioplot(datos, horizontal = TRUE, yaxt = "n", axes = FALSE,
col = rgb(0, 1, 1, alpha = 0.15))
Gráfico de violín con datos de dos grupos en lados diferentes
<- df[df$genero == "Masculino", ]
hombres <- df[df$genero == "Femenino", ] mujeres
vioplot(hombres$peso,
plotCentre = "line", # Mediana con una línea
side = "right", # Lado derecho
col = "#5773CC",
xlab = "Peso según sexo",
ylim = c(50, 110)) # Color del lado derecho
vioplot(mujeres$peso,
plotCentre = "line", # Mediana con una línea
side = "left", # Lado izquierdo
col = "#FFB900", # Color del lado izquierdo
add = TRUE) # Sobre el gráfico anterior
legend("topleft",
legend = c("Hombres", "Mujeres"),
fill = c("#5773CC", "#FFB900"))
Debido a que los diagramas de caja suelen dificultar la observación
de la distribución subyacente de los datos, este problema se puede
resolver agregando puntos representando a los datos con la función
stripchart()
.
boxplot(peso ~ procedencia, # Variables a representar
data = df, # Dataframe de origen
col = "white") # Color del fondo de las cajas
stripchart(peso ~ procedencia, # Equivalente
data = df,
vertical = TRUE, # Diagrama vertical
method = "jitter", # Evita dibujar sobre los datos atÁpicos. Distribuye aleatoriamente los puntos
pch = 19, # Tipo de sÁmbolo
add = TRUE, #Superpone el stripchart al diagrama de caja y bigotes
col = "red") # Color del sÁmbolo
Los diagramas de enjambre (“bee swarm”) son similares a los strip charts. Su objetivo es mostrar la distribución subyacente de los datos, pero los datos se agrupan de tal manera que se evita que se solapen.
install.packages("beeswarm")
library(beeswarm)
beeswarm(df$peso,
col = 2, # Color
pch = 18, # Símbolo
cex = 1.5, # Tamaño
method = "swarm")
Hay varios métodos disponibles para ordenar los puntos de datos. Cada método usa un algoritmo diferente que asegura que los puntos de datos no se solapan. El método “swarm” (por defecto) coloca los puntos en orden creciente. Otros métodos son:
“center”: crea un panal simétrico usando una rejilla cuadrada.
“hex”: usa un grid hexagonal para colocar los puntos.
“square”: coloca los puntos en un grid cuadrado.
beeswarm(df$peso ~ df$procedencia,
col = 4, # Color
pch = 18, # SÁmbolo
cex = 1.5, # TamaÁ±o
vertical = FALSE) # Disposición vertical
Cuando las observaciones se extienden por todo el gráfico, se pueden
ajustar usando como argumento corral()
.
beeswarm(df$peso ~ df$procedencia,
pch = 18,
cex = 1.5,
col = c("#800080", "#3FA0FF", "#FFE099", "#F76D5E"),
corral = "wrap") # Otros métodos: "wrap", "random", "omit"
Es posible mostrar solo uno de los lados de un beeswarm.
beeswarm(df$peso ~ df$procedencia,
pch = 19,
col = c("#800080","#3FA0FF", "#FFE099", "#F76D5E"),
side = 1) # Si lado izquierdo = -1
Se puede modificar el orden de la varible categórica (eje X). El método por defecto es “ascending”.
beeswarm(df$peso ~ df$procedencia,
pch = 19,
col = c("#800080","#3FA0FF", "#FFE099", "#F76D5E"),
priority = "descending") # Otros valores: "random", "density", "non"
R soporta varios formatos populares, tales como jpg, png, tiff, pdf. En todos los casos, el procedimiento para exportar consiste en tres pasos:
jpeg("mi_plot.jpeg", # PASO 1: abrimos dispositivo (ejemplo JPEG)
quality = 75)
plot(rnorm(20)) # PASO 2: creamos el gráfico
dev.off() # PASO 3: cerramos el dispositivo
Como alternativa, es posible:
savePlot(filename = "Rplot", # Nombre del archivo a ser guadado
type = c("wmf", "emf", "png", # Tipo de archivo
"jpg", "jpeg", "bmp",
"tif", "tiff", "ps",
"eps", "pdf"),
device = dev.cur(), # Número de dispositivo gráfico a ser exportado
restoreConsole = TRUE)