diamonds## carat cut color clarity depth table price x y z
## 1 0,23 Ideal E SI2 61,5 55 326 3,95 3,98 2,43
## 2 0,21 Premium E SI1 59,8 61 326 3,89 3,84 2,31
## 3 0,23 Good E VS1 56,9 65 327 4,05 4,07 2,31
## 4 0,29 Premium I VS2 62,4 58 334 4,20 4,23 2,63
## 5 0,31 Good J SI2 63,3 58 335 4,34 4,35 2,75
## 6 0,24 Very Good J VVS2 62,8 57 336 3,94 3,96 2,48
Este informe analiza la base diamonds,
una base de datos pública que viene incluida en el
paquete ggplot2 de R y que es de las más usadas en el mundo
para enseñar estadística descriptiva.
| Nombre | diamonds |
| Fuente | Paquete ggplot2 (R). Datos de precios reales de
diamantes recopilados por Hadley Wickham |
| Acceso | Pública y gratuita:
library(ggplot2); data(diamonds) |
| Documentación | ?diamonds en la consola de R |
| Unidad de observación | Un diamante |
| Tamaño | 53.940 diamantes y 10 variables |
| Precios | En dólares estadounidenses (USD) |
Cada fila es un diamante puesto a la venta, con su precio y sus cuatro características de calidad, conocidas en el mercado como “las 4 C”: carat (quilates), cut (corte), color y clarity (claridad).
Esta es una duda muy común: el archivo no se descarga de
internet, porque la base viene adentro del paquete
ggplot2, que ya está instalado en el computador.
Cuando se escribe data(diamonds), R la saca de ahí.
1. Dónde está físicamente en el computador. Está
guardada en formato interno de R (.rdb/.rdx),
dentro de la carpeta del paquete. Para ver la ruta exacta en cualquier
computador:
system.file("data", package = "ggplot2") # carpeta donde vive la base
.libPaths() # carpeta de todos los paquetes de REn el computador donde se hizo este informe, la ruta es:
/Users/.../Library/R/x86_64/4.4/library/ggplot2/data/
Esa carpeta cambia según el usuario y el sistema operativo, por eso
no se debe escribir la ruta a mano: siempre es mejor
cargar la base con data(diamonds).
2. Cómo verla como archivo de Excel. Si se necesita
el archivo .csv (por ejemplo, para adjuntarlo o abrirlo en
Excel), se exporta así:
Eso crea el archivo diamonds.csv (unos 2,6 MB) en la
carpeta de trabajo del proyecto, que se puede consultar
con getwd().
3. Documentación oficial. Escribiendo
?diamonds en la consola de R aparece la ficha técnica de la
base. Su título oficial es “Prices of over 50,000 round cut
diamonds” y ahí se describe cada una de las 10 variables. La base
fue recopilada por Hadley Wickham, autor de ggplot2, a
partir de precios reales publicados por un buscador de diamantes en
línea.
La actividad pide analizar al menos dos variables cualitativas y dos cuantitativas. Aquí se analizan tres cualitativas y dos cuantitativas:
| Tipo | Variable | Nombre en la base | Escala de medición |
|---|---|---|---|
| Cualitativa | Calidad del corte | cut |
Ordinal (5 categorías) |
| Cualitativa | Claridad (pureza) | clarity |
Ordinal (8 categorías) |
| Cualitativa | Color | color |
Ordinal (7 categorías) |
| Cuantitativa | Precio en dólares | price |
Continua, de razón |
| Cuantitativa | Peso en quilates | carat |
Continua, de razón |
Las tres cualitativas son ordinales: sus categorías no son simples nombres, sino que tienen un orden de calidad claro. Por eso sus tablas de frecuencia sí incluyen frecuencias acumuladas (\(N_i\) y \(F_i\)), algo que no tendría sentido en una variable nominal como el género o el color de un carro.
# Si algún paquete no está instalado, ejecute una vez en la consola:
# install.packages(c("ggplot2", "dplyr", "knitr", "kableExtra"))
library(ggplot2) # contiene la base 'diamonds' y sirve para los gráficos
library(dplyr) # manipulación de datos
library(knitr) # tablas
library(kableExtra) # formato de tablasLa base se carga directamente desde el paquete, así que no hay que descargar ningún archivo ni preocuparse por rutas:
data(diamonds)
diamantes <- as.data.frame(diamonds)
dim(diamantes) # filas (diamantes) y columnas (variables)## [1] 53940 10
## 'data.frame': 53940 obs. of 10 variables:
## $ carat : num 0,23 0,21 0,23 0,29 0,31 0,24 0,24 0,26 0,22 0,23 ...
## $ cut : Ord.factor w/ 5 levels "Fair"<"Good"<..: 5 4 2 4 2 3 3 3 1 3 ...
## $ color : Ord.factor w/ 7 levels "D"<"E"<"F"<"G"<..: 2 2 2 6 7 7 6 5 2 5 ...
## $ clarity: Ord.factor w/ 8 levels "I1"<"SI2"<"SI1"<..: 2 3 5 4 2 6 7 3 4 5 ...
## $ depth : num 61,5 59,8 56,9 62,4 63,3 62,8 62,3 61,9 65,1 59,4 ...
## $ table : num 55 61 65 58 58 57 57 55 61 61 ...
## $ price : int 326 326 327 334 335 336 336 337 337 338 ...
## $ x : num 3,95 3,89 4,05 4,2 4,34 3,94 3,95 4,07 3,87 4 ...
## $ y : num 3,98 3,84 4,07 4,23 4,35 3,96 3,98 4,11 3,78 4,05 ...
## $ z : num 2,43 2,31 2,31 2,63 2,75 2,48 2,47 2,53 2,49 2,39 ...
La base trae 53.940 diamantes y 10 variables.
Note que R ya reconoce cut, color y
clarity como factores ordenados
(Ord.factor), es decir, como variables ordinales.
head(diamantes, 5) %>%
kable(caption = "Primeras 5 filas de la base de datos") %>%
kable_styling(full_width = FALSE, bootstrap_options = c("striped", "condensed"),
latex_options = c("striped", "hold_position"))| carat | cut | color | clarity | depth | table | price | x | y | z |
|---|---|---|---|---|---|---|---|---|---|
| 0,23 | Ideal | E | SI2 | 61,5 | 55 | 326 | 3,95 | 3,98 | 2,43 |
| 0,21 | Premium | E | SI1 | 59,8 | 61 | 326 | 3,89 | 3,84 | 2,31 |
| 0,23 | Good | E | VS1 | 56,9 | 65 | 327 | 4,05 | 4,07 | 2,31 |
| 0,29 | Premium | I | VS2 | 62,4 | 58 | 334 | 4,20 | 4,23 | 2,63 |
| 0,31 | Good | J | SI2 | 63,3 | 58 | 335 | 4,34 | 4,35 | 2,75 |
Antes de analizar hay que revisar la calidad de los datos. Se verifican tres cosas: datos faltantes, duplicados y valores imposibles.
# 1. Datos faltantes
cat("Total de datos faltantes (NA) en toda la base:", sum(is.na(diamantes)), "\n")## Total de datos faltantes (NA) en toda la base: 0
## Filas duplicadas: 146
# 3. Valores imposibles: un diamante no puede medir 0 mm
cat("Diamantes con alguna dimensión igual a 0 (x, y o z):",
sum(diamantes$x == 0 | diamantes$y == 0 | diamantes$z == 0), "\n")## Diamantes con alguna dimensión igual a 0 (x, y o z): 20
Decisiones tomadas:
diamantes <- diamantes %>%
filter(x > 0, y > 0, z > 0)
# Etiquetas en español para el corte (se conserva el orden de calidad)
diamantes <- diamantes %>%
mutate(corte = factor(
as.character(cut),
levels = c("Fair", "Good", "Very Good", "Premium", "Ideal"),
labels = c("Regular (Fair)", "Bueno (Good)",
"Muy bueno (Very Good)", "Premium", "Ideal"),
ordered = TRUE))
cat("Diamantes que quedan para el análisis:", nrow(diamantes), "\n")## Diamantes que quedan para el análisis: 53920
El análisis se hace entonces sobre 53.920 diamantes.
Para no repetir el mismo código en cada variable, se definen unas funciones. Una tabla de frecuencias tiene estas columnas:
# ---- Tabla de frecuencias ----
tabla_frec <- function(x, nombre, ordenar = FALSE, acumuladas = TRUE) {
x <- x[!is.na(x)]
t <- as.data.frame(table(x), stringsAsFactors = FALSE)
names(t) <- c(nombre, "ni")
if (ordenar) t <- t[order(-t$ni), ]
t$fi <- round(100 * t$ni / sum(t$ni), 2)
if (acumuladas) {
t$Ni <- cumsum(t$ni)
t$Fi <- round(100 * t$Ni / sum(t$ni), 2)
}
total <- t[1, ]; total[1, ] <- NA
total[[nombre]] <- "Total"; total$ni <- sum(t$ni); total$fi <- 100
t <- rbind(t, total)
rownames(t) <- NULL
names(t)[names(t) == "fi"] <- "fi (%)"
if (acumuladas) names(t)[names(t) == "Fi"] <- "Fi (%)"
t
}
mostrar <- function(t, titulo) {
kable(t, caption = titulo, align = c("l", rep("r", ncol(t) - 1)),
format.args = list(big.mark = ".", decimal.mark = ",")) %>%
kable_styling(full_width = FALSE,
bootstrap_options = c("striped", "hover", "condensed"),
latex_options = c("striped", "hold_position")) %>%
row_spec(nrow(t), bold = TRUE)
}
# ---- Moda: el valor que más se repite ----
moda <- function(x) {
x <- x[!is.na(x)]
tt <- table(x)
names(tt)[tt == max(tt)]
}
# Moda para variables numéricas.
# Se calcula sin convertir a texto: con options(OutDec = ",") el nombre de la
# tabla sería "0,3" y as.numeric("0,3") daría NA.
moda_num <- function(x) {
x <- x[!is.na(x)]
vals <- unique(x)
vals[which.max(tabulate(match(x, vals)))]
}
# ---- Asimetría y curtosis ----
# Se escriben con las fórmulas de los momentos para no depender de otro paquete.
# m_k = sum((x - media)^k) / n
# Asimetría = m3 / m2^(3/2) Curtosis = m4 / m2^2
skewness <- function(x) {
x <- x[!is.na(x)]; n <- length(x); m <- mean(x)
(sum((x - m)^3) / n) / (sum((x - m)^2) / n)^(3/2)
}
kurtosis <- function(x) {
x <- x[!is.na(x)]; n <- length(x); m <- mean(x)
(sum((x - m)^4) / n) / ((sum((x - m)^2) / n)^2)
}
# ---- Indicadores estadísticos de una variable cuantitativa ----
indicadores <- function(x) {
x <- x[!is.na(x)]
q <- quantile(x, c(0.25, 0.50, 0.75, 0.90))
data.frame(
Indicador = c("n (datos válidos)", "Media", "Mediana", "Moda",
"Mínimo", "Máximo", "Rango",
"Cuartil 1 (Q1)", "Cuartil 3 (Q3)",
"Rango intercuartílico (RIC)",
"Percentil 90", "Varianza", "Desviación estándar",
"Coeficiente de variación (%)",
"Coeficiente de asimetría", "Curtosis (exceso)"),
Valor = c(length(x), mean(x), median(x), moda_num(x),
min(x), max(x), max(x) - min(x),
q[1], q[3], q[3] - q[1], q[4],
var(x), sd(x), 100 * sd(x) / mean(x),
skewness(x), kurtosis(x) - 3)
)
}
# ---- Tabla de frecuencias por intervalos ----
tabla_intervalos <- function(x, cortes, etiquetas, nombre) {
x <- x[!is.na(x)]
clase <- cut(x, breaks = cortes, labels = etiquetas,
right = TRUE, include.lowest = TRUE)
tabla_frec(clase, nombre, ordenar = FALSE, acumuladas = TRUE)
}
# ---- Formato de números para el texto ----
fmt <- function(x, d = 2) format(round(x, d), big.mark = ".", decimal.mark = ",",
nsmall = 0, scientific = FALSE)
# Variante con dos decimales fijos, para los pesos en quilates (1 -> "1,00")
fmt_q <- function(x) format(round(x, 2), nsmall = 2,
decimal.mark = ",", big.mark = ".")
# Formato de los números de los ejes de los gráficos
fmt_eje <- function(x) format(x, big.mark = ".", scientific = FALSE)¿Qué mide? El corte indica qué tan bien fue tallado el diamante, lo que determina cuánta luz refleja. Es una variable cualitativa ordinal con 5 categorías, de peor a mejor: Regular (Fair) < Bueno (Good) < Muy bueno (Very Good) < Premium < Ideal.
tab_corte <- tabla_frec(diamantes$corte, "Calidad del corte")
mostrar(tab_corte,
"Tabla 1. Distribución de los diamantes según la calidad del corte")| Calidad del corte | ni | fi (%) | Ni | Fi (%) |
|---|---|---|---|---|
| Regular (Fair) | 1.609 | 2,98 | 1.609 | 2,98 |
| Bueno (Good) | 4.902 | 9,09 | 6.511 | 12,08 |
| Muy bueno (Very Good) | 12.081 | 22,41 | 18.592 | 34,48 |
| Premium | 13.780 | 25,56 | 32.372 | 60,04 |
| Ideal | 21.548 | 39,96 | 53.920 | 100,00 |
| Total | 53.920 | 100,00 |
diamantes %>%
count(corte) %>% mutate(p = n / sum(n)) %>%
ggplot(aes(x = corte, y = n, fill = corte)) +
geom_col(show.legend = FALSE, width = 0.7) +
geom_text(aes(label = paste0(format(n, big.mark = "."), "\n(",
round(100 * p, 1), "%)")),
vjust = -0.3, size = 3.2, lineheight = 0.9) +
scale_fill_brewer(palette = "Blues") +
scale_y_continuous(expand = expansion(mult = c(0, 0.18))) +
labs(title = "Diamantes según la calidad del corte",
x = "Calidad del corte (de menor a mayor)", y = "Número de diamantes") +
theme_minimal()Indicadores:
Interpretación: la distribución está concentrada en las calidades altas. El corte Ideal es el más frecuente (40 %) y, sumado a Premium y Muy bueno, concentra cerca del 87,9 % del total. En cambio, el corte Regular (Fair) apenas representa el 3 %. Esto tiene sentido comercial: los diamantes que llegan al mercado ya pasaron por un proceso de tallado profesional, y un corte deficiente destruye valor, así que es raro.
¿Qué mide? La claridad indica qué tan libre de impurezas internas está el diamante. Es ordinal, con 8 categorías de peor a mejor:
| Código | Significado |
|---|---|
| I1 | Con inclusiones visibles (la peor) |
| SI2, SI1 | Inclusiones pequeñas |
| VS2, VS1 | Inclusiones muy pequeñas |
| VVS2, VVS1 | Inclusiones sumamente pequeñas |
| IF | Internamente impecable (la mejor) |
tab_clar <- tabla_frec(diamantes$clarity, "Claridad")
mostrar(tab_clar, "Tabla 2. Distribución de los diamantes según la claridad")| Claridad | ni | fi (%) | Ni | Fi (%) |
|---|---|---|---|---|
| I1 | 738 | 1,37 | 738 | 1,37 |
| SI2 | 9.185 | 17,03 | 9.923 | 18,40 |
| SI1 | 13.063 | 24,23 | 22.986 | 42,63 |
| VS2 | 12.254 | 22,73 | 35.240 | 65,36 |
| VS1 | 8.170 | 15,15 | 43.410 | 80,51 |
| VVS2 | 5.066 | 9,40 | 48.476 | 89,90 |
| VVS1 | 3.654 | 6,78 | 52.130 | 96,68 |
| IF | 1.790 | 3,32 | 53.920 | 100,00 |
| Total | 53.920 | 100,00 |
diamantes %>%
count(clarity) %>% mutate(p = n / sum(n)) %>%
ggplot(aes(x = clarity, y = n)) +
geom_col(fill = "#2A9D8F", width = 0.7) +
geom_text(aes(label = paste0(round(100 * p, 1), "%")),
vjust = -0.35, size = 3.3) +
scale_y_continuous(expand = expansion(mult = c(0, 0.15))) +
labs(title = "Diamantes según la claridad",
x = "Claridad (de peor a mejor)", y = "Número de diamantes") +
theme_minimal()Indicadores:
Interpretación: la distribución tiene forma de campana asimétrica: las categorías intermedias (SI1, VS2, SI2, VS1) concentran la mayoría de los diamantes, mientras que los extremos son escasos. Solo el 1,4 % tiene la peor claridad (I1) y apenas el 3,3 % alcanza la mejor (IF). Según la columna \(F_i\), el 65,4 % de los diamantes tiene claridad VS2 o inferior. La lectura de mercado es clara: los diamantes perfectos son rarezas, y el grueso del comercio ocurre en calidades medias.
¿Qué mide? En los diamantes blancos, el color se mide por ausencia de color: la escala va de D (incoloro, el mejor) hasta J (con tono amarillento, el peor de esta base).
tab_color <- tabla_frec(diamantes$color, "Color")
mostrar(tab_color, "Tabla 3. Distribución de los diamantes según el color")| Color | ni | fi (%) | Ni | Fi (%) |
|---|---|---|---|---|
| D | 6.774 | 12,56 | 6.774 | 12,56 |
| E | 9.797 | 18,17 | 16.571 | 30,73 |
| F | 9.538 | 17,69 | 26.109 | 48,42 |
| G | 11.284 | 20,93 | 37.393 | 69,35 |
| H | 8.298 | 15,39 | 45.691 | 84,74 |
| I | 5.421 | 10,05 | 51.112 | 94,79 |
| J | 2.808 | 5,21 | 53.920 | 100,00 |
| Total | 53.920 | 100,00 |
diamantes %>%
count(color) %>% mutate(p = n / sum(n)) %>%
ggplot(aes(x = color, y = n)) +
geom_col(fill = "#E9C46A", color = "#B8860B", width = 0.7) +
geom_text(aes(label = paste0(round(100 * p, 1), "%")),
vjust = -0.35, size = 3.3) +
scale_y_continuous(expand = expansion(mult = c(0, 0.15))) +
labs(title = "Diamantes según el color",
x = "Color (D = incoloro, el mejor; J = el más amarillento)",
y = "Número de diamantes") +
theme_minimal()Indicadores:
Interpretación: el color más común es el G (20,9 %), una calidad intermedia. La frecuencia disminuye hacia los extremos: los incoloros perfectos (D) son el 12,6 % y los más amarillentos (J) solo el 5,2 %. Igual que con la claridad, el mercado se concentra en calidades medias.
En las variables cuantitativas hay demasiados valores distintos para hacer una tabla valor por valor, así que los datos se agrupan en intervalos (clases).
La regla de Sturges, \(k = 1 + 3{,}322 \log_{10}(n)\), sugiere cuántos intervalos de igual amplitud usar:
n <- nrow(diamantes)
k <- 1 + 3.322 * log10(n)
cat("n =", n, " -> k sugerido por Sturges =", round(k, 1), "intervalos\n")## n = 53920 -> k sugerido por Sturges = 16,7 intervalos
Sturges sugiere unos 17 intervalos de igual amplitud. Sin embargo, las dos variables son muy asimétricas (la mayoría de los diamantes son pequeños y baratos, y unos pocos valen una fortuna). Con intervalos de igual amplitud, casi todos los diamantes caerían en las primeras clases y las últimas quedarían casi vacías. Por eso se usan intervalos con sentido comercial (rangos de precio y de peso que un joyero reconocería), que resumen mejor la información.
¿Qué mide? El precio de venta del diamante en dólares (USD). Es una variable cuantitativa continua de razón.
tab_precio <- tabla_intervalos(
diamantes$price,
cortes = c(-Inf, 1000, 2500, 5000, 10000, Inf),
etiquetas = c("Hasta 1.000", "Más de 1.000 a 2.500", "Más de 2.500 a 5.000",
"Más de 5.000 a 10.000", "Más de 10.000"),
nombre = "Precio (USD)"
)
mostrar(tab_precio,
"Tabla 4. Distribución de los diamantes según el precio (USD)")| Precio (USD) | ni | fi (%) | Ni | Fi (%) |
|---|---|---|---|---|
| Hasta 1.000 | 14.524 | 26,94 | 14.524 | 26,94 |
| Más de 1.000 a 2.500 | 13.015 | 24,14 | 27.539 | 51,07 |
| Más de 2.500 a 5.000 | 11.678 | 21,66 | 39.217 | 72,73 |
| Más de 5.000 a 10.000 | 9.489 | 17,60 | 48.706 | 90,33 |
| Más de 10.000 | 5.214 | 9,67 | 53.920 | 100,00 |
| Total | 53.920 | 100,00 |
ind_precio <- indicadores(diamantes$price)
ind_precio %>% mutate(Valor = round(Valor, 2)) %>%
kable(caption = "Tabla 5. Indicadores estadísticos del precio (USD)",
format.args = list(big.mark = ".", decimal.mark = ",")) %>%
kable_styling(full_width = FALSE, bootstrap_options = c("striped", "condensed"),
latex_options = c("striped", "hold_position"))| Indicador | Valor |
|---|---|
| n (datos válidos) | 53.920,00 |
| Media | 3.930,99 |
| Mediana | 2.401,00 |
| Moda | 605,00 |
| Mínimo | 326,00 |
| Máximo | 18.823,00 |
| Rango | 18.497,00 |
| Cuartil 1 (Q1) | 949,00 |
| Cuartil 3 (Q3) | 5.323,25 |
| Rango intercuartílico (RIC) | 4.374,25 |
| Percentil 90 | 9.818,10 |
| Varianza | 15.898.405,35 |
| Desviación estándar | 3.987,28 |
| Coeficiente de variación (%) | 101,43 |
| Coeficiente de asimetría | 1,62 |
| Curtosis (exceso) | 2,18 |
ggplot(diamantes, aes(x = price)) +
geom_histogram(binwidth = 500, boundary = 0,
fill = "#264653", color = "white") +
geom_vline(aes(xintercept = mean(price), color = "Media"),
linewidth = 1, linetype = "dashed") +
geom_vline(aes(xintercept = median(price), color = "Mediana"), linewidth = 1) +
scale_color_manual(values = c(Media = "#E76F51", Mediana = "#2A9D8F"),
name = NULL) +
scale_x_continuous(labels = fmt_eje) +
labs(title = "Histograma del precio de los diamantes",
x = "Precio (USD)", y = "Número de diamantes") +
theme_minimal() + theme(legend.position = "top")ggplot(diamantes, aes(x = price, y = "")) +
geom_boxplot(fill = "#8ECAE6", outlier.color = "#E76F51", outlier.alpha = 0.2) +
scale_x_continuous(labels = fmt_eje) +
labs(title = "Diagrama de caja del precio", x = "Precio (USD)", y = NULL) +
theme_minimal()¿Qué mide? El peso del diamante en quilates (1 quilate = 0,2 gramos). Es cuantitativa continua de razón.
tab_carat <- tabla_intervalos(
diamantes$carat,
cortes = c(-Inf, 0.3, 0.5, 1.0, 1.5, 2.0, Inf),
etiquetas = c("Hasta 0,30", "Más de 0,30 a 0,50", "Más de 0,50 a 1,00",
"Más de 1,00 a 1,50", "Más de 1,50 a 2,00", "Más de 2,00"),
nombre = "Peso (quilates)"
)
mostrar(tab_carat,
"Tabla 6. Distribución de los diamantes según el peso en quilates")| Peso (quilates) | ni | fi (%) | Ni | Fi (%) |
|---|---|---|---|---|
| Hasta 0,30 | 4.203 | 7,79 | 4.203 | 7,79 |
| Más de 0,30 a 0,50 | 14.729 | 27,32 | 18.932 | 35,11 |
| Más de 0,50 a 1,00 | 17.502 | 32,46 | 36.434 | 67,57 |
| Más de 1,00 a 1,50 | 12.051 | 22,35 | 48.485 | 89,92 |
| Más de 1,50 a 2,00 | 3.552 | 6,59 | 52.037 | 96,51 |
| Más de 2,00 | 1.883 | 3,49 | 53.920 | 100,00 |
| Total | 53.920 | 100,00 |
ind_carat <- indicadores(diamantes$carat)
ind_carat %>% mutate(Valor = round(Valor, 3)) %>%
kable(caption = "Tabla 7. Indicadores estadísticos del peso en quilates",
format.args = list(big.mark = ".", decimal.mark = ",")) %>%
kable_styling(full_width = FALSE, bootstrap_options = c("striped", "condensed"),
latex_options = c("striped", "hold_position"))| Indicador | Valor |
|---|---|
| n (datos válidos) | 53.920,000 |
| Media | 0,798 |
| Mediana | 0,700 |
| Moda | 0,300 |
| Mínimo | 0,200 |
| Máximo | 5,010 |
| Rango | 4,810 |
| Cuartil 1 (Q1) | 0,400 |
| Cuartil 3 (Q3) | 1,040 |
| Rango intercuartílico (RIC) | 0,640 |
| Percentil 90 | 1,510 |
| Varianza | 0,224 |
| Desviación estándar | 0,474 |
| Coeficiente de variación (%) | 59,395 |
| Coeficiente de asimetría | 1,116 |
| Curtosis (exceso) | 1,255 |
ggplot(diamantes, aes(x = carat)) +
geom_histogram(binwidth = 0.05, boundary = 0,
fill = "#6A4C93", color = "white") +
geom_vline(aes(xintercept = mean(carat), color = "Media"),
linewidth = 1, linetype = "dashed") +
geom_vline(aes(xintercept = median(carat), color = "Mediana"), linewidth = 1) +
scale_color_manual(values = c(Media = "#E76F51", Mediana = "#2A9D8F"),
name = NULL) +
coord_cartesian(xlim = c(0, 3)) +
labs(title = "Histograma del peso en quilates (hasta 3 quilates)",
x = "Peso (quilates)", y = "Número de diamantes") +
theme_minimal() + theme(legend.position = "top")ggplot(diamantes, aes(x = carat, y = "")) +
geom_boxplot(fill = "#C8B6E2", outlier.color = "#6A4C93", outlier.alpha = 0.2) +
labs(title = "Diagrama de caja del peso en quilates",
x = "Peso (quilates)", y = NULL) +
theme_minimal()Hasta aquí cada variable se analizó por separado. Ahora se cruzan una cualitativa y una cuantitativa.
diamantes %>%
group_by(Corte = corte) %>%
summarise(Diamantes = n(),
`Precio mediano` = median(price),
`Precio medio` = round(mean(price), 0),
`Quilates (mediana)` = median(carat)) %>%
kable(caption = "Tabla 8. Precio (USD) y peso según la calidad del corte",
format.args = list(big.mark = ".", decimal.mark = ",")) %>%
kable_styling(full_width = FALSE,
bootstrap_options = c("striped", "hover", "condensed"),
latex_options = c("striped", "hold_position"))| Corte | Diamantes | Precio mediano | Precio medio | Quilates (mediana) |
|---|---|---|---|---|
| Regular (Fair) | 1.609 | 3.282,0 | 4.358 | 1,000 |
| Bueno (Good) | 4.902 | 3.050,5 | 3.926 | 0,820 |
| Muy bueno (Very Good) | 12.081 | 2.647,0 | 3.982 | 0,710 |
| Premium | 13.780 | 3.182,0 | 4.580 | 0,855 |
| Ideal | 21.548 | 1.809,5 | 3.457 | 0,540 |
ggplot(diamantes, aes(x = corte, y = price, fill = corte)) +
geom_boxplot(show.legend = FALSE, outlier.alpha = 0.1) +
scale_fill_brewer(palette = "Blues") +
scale_y_continuous(labels = fmt_eje) +
labs(title = "Precio según la calidad del corte",
x = "Calidad del corte (de menor a mayor)", y = "Precio (USD)") +
theme_minimal()La tabla 8 muestra algo que contradice la intuición: los diamantes de peor corte (Regular/Fair) tienen un precio mediano de USD 3.282, mientras que los de mejor corte (Ideal) cuestan apenas USD 1.810. ¿El mejor corte se vende más barato?
La explicación está en la última columna: los diamantes de corte Regular pesan en mediana 1,00 quilates y los de corte Ideal solo 0,54. Es decir, los diamantes mal cortados de esta base son mucho más grandes, y el peso influye tanto en el precio que tapa completamente el efecto del corte.
Esto ocurre porque tallar un diamante con corte Ideal exige desperdiciar más material: para lograr las proporciones perfectas hay que sacrificar peso. Cuando la piedra en bruto es grande y valiosa, el joyero prefiere conservar el tamaño aunque el corte quede regular.
En estadística esto se llama variable de confusión: el peso está detrás de los dos fenómenos y distorsiona la comparación. Al comparar diamantes de un tamaño parecido, el efecto real del corte aparece:
diamantes %>%
# se comparan solo diamantes de tamaño parecido
filter(carat >= 0.9, carat <= 1.1) %>%
group_by(Corte = corte) %>%
summarise(Diamantes = n(),
`Precio mediano` = median(price),
`Quilates (mediana)` = median(carat)) %>%
kable(caption = paste("Tabla 9. Precio (USD) según el corte, comparando",
"solo diamantes de 0,9 a 1,1 quilates"),
format.args = list(big.mark = ".", decimal.mark = ",")) %>%
kable_styling(full_width = FALSE,
bootstrap_options = c("striped", "hover", "condensed"),
latex_options = c("striped", "hold_position"))| Corte | Diamantes | Precio mediano | Quilates (mediana) |
|---|---|---|---|
| Regular (Fair) | 589 | 3.730,0 | 1,00 |
| Bueno (Good) | 1.483 | 4.312,0 | 1,00 |
| Muy bueno (Very Good) | 2.715 | 4.690,0 | 1,01 |
| Premium | 2.882 | 4.672,0 | 1,01 |
| Ideal | 2.656 | 5.220,5 | 1,02 |
Ahora sí: a igual tamaño, mejor corte significa mayor precio. Esta es la lección más importante del informe: una tabla descriptiva mal leída puede llevar a una conclusión falsa; siempre hay que preguntarse qué otra variable puede estar detrás.
ggplot(diamantes, aes(x = carat, y = price)) +
geom_point(alpha = 0.08, color = "#264653") +
geom_smooth(method = "loess", se = FALSE, color = "#E76F51", linewidth = 1) +
scale_y_continuous(labels = fmt_eje) +
labs(title = "Relación entre el peso y el precio",
subtitle = "Cada punto es un diamante; la curva muestra la tendencia",
x = "Peso (quilates)", y = "Precio (USD)") +
theme_minimal()cat("Coeficiente de correlación de Pearson (peso vs. precio):",
round(cor(diamantes$carat, diamantes$price), 3), "\n")## Coeficiente de correlación de Pearson (peso vs. precio): 0,922
Interpretación: la correlación es 0,922, muy cercana a 1: el peso y el precio están fuertemente relacionados de forma positiva. Pero la nube de puntos muestra que la relación no es una línea recta: es curva y se abre en abanico. A medida que el diamante crece, el precio sube cada vez más rápido y además se vuelve más impredecible (dos diamantes de 2 quilates pueden tener precios muy distintos según su color y claridad). Por eso el precio tiene un coeficiente de variación tan alto.
Sobre la calidad (variables cualitativas): el mercado de diamantes está sesgado hacia las calidades altas de corte (el 40 % tiene corte Ideal), pero concentrado en calidades medias de claridad y color. La claridad impecable (IF) solo alcanza el 3,3 % de los diamantes, y el color incoloro perfecto (D) el 12,6 %.
Sobre el precio: es una variable extremadamente dispersa y muy asimétrica a la derecha (CV = 101,4 %, asimetría = 1,62). El diamante típico cuesta USD 2.401 (mediana), bastante menos que el promedio de USD 3.931.
Sobre el peso: el diamante típico pesa 0,7 quilates y el 67,6 % pesa 1 quilate o menos. El histograma delata una práctica comercial: los pesos se concentran en cifras redondas de venta.
Sobre la relación entre variables: el peso explica gran parte del precio (correlación de 0,922), pero la relación es no lineal y se vuelve más dispersa en los diamantes grandes.
Lección estadística principal: en distribuciones asimétricas y con valores atípicos, la media engaña. Es mejor reportar la mediana y los cuartiles, acompañados de medidas de dispersión y de forma. Y sobre todo, el caso del corte demuestra que una comparación entre grupos puede invertirse cuando se controla una variable de confusión: los diamantes de mejor corte parecían más baratos solo porque eran más pequeños.
Recomendación para un comprador: dado que el precio se dispara con el peso pero el corte influye menos en él, conviene bajar un poco en peso y subir en calidad de corte: se obtiene un diamante que brilla más por un precio considerablemente menor.