Instalación

Instalamos y cargamos el paquete tidyverse.

if (!require(tidyverse)) { install.packages(tidyverse); library(tidyverse) }
## Loading required package: tidyverse
## -- Attaching packages --------------------------- tidyverse 1.2.1 --
## v ggplot2 3.2.1     v purrr   0.3.2
## v tibble  2.1.3     v dplyr   0.8.3
## v tidyr   0.8.3     v stringr 1.4.0
## v readr   1.3.1     v forcats 0.4.0
## -- Conflicts ------------------------------ tidyverse_conflicts() --
## x dplyr::filter() masks stats::filter()
## x dplyr::lag()    masks stats::lag()

Cargamos el conjunto de datos diamonds disponible en el paquete ggplot2.

library(ggplot2)
data <- ggplot2::diamonds
help("diamonds") # Obtenemos una descripción del conjunto de datos
## starting httpd help server ... done
str(data)
## Classes 'tbl_df', 'tbl' and '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 ...

El conjunto de datos tiene dimensión 53940x10. Recoge información sobre las siguientes variables:

  • price tipo int Precio del diamante en US$
  • carat tipo num Peso del diamante
  • cut tipo Ord.factor Calidad del tallado
  • color tipo Ord.factor Color del diamante
  • clarity tipo Ord.factor Medida de claridad del diamante
  • x tipo num Longitud en mm
  • y tipo num Anchura en mm
  • z tipo num Profundidad en mm
  • depth tipo num Porcentaje de profundidad total. Es una medida derivada de x, y, z.
  • table tipo num Ancho de la parte superior del diamante en relación con el punto más ancho.
head(data, n=10) # Mostramos las 10 primeas filas del data.frame creado
## # A tibble: 10 x 10
##    carat cut       color clarity depth table price     x     y     z
##    <dbl> <ord>     <ord> <ord>   <dbl> <dbl> <int> <dbl> <dbl> <dbl>
##  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.290 Premium   I     VS2      62.4    58   334  4.2   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
##  7 0.24  Very Good I     VVS1     62.3    57   336  3.95  3.98  2.47
##  8 0.26  Very Good H     SI1      61.9    55   337  4.07  4.11  2.53
##  9 0.22  Fair      E     VS2      65.1    61   337  3.87  3.78  2.49
## 10 0.23  Very Good H     VS1      59.4    61   338  4     4.05  2.39

Análisis numérico

i.

Creamos el conjunto data_carat que contiene el precio máximo en función del peso de los diamantes (variable carat).

if (!require(dplyr)) { install.packages(dplyr); library(dplyr) }
data_carat <- data %>% group_by(carat) %>% summarize(PrecioMax=max(price))
head(data_carat, n=10)
## # A tibble: 10 x 2
##    carat PrecioMax
##    <dbl>     <int>
##  1 0.2         367
##  2 0.21        394
##  3 0.22        470
##  4 0.23        688
##  5 0.24        963
##  6 0.25       1186
##  7 0.26        814
##  8 0.27        893
##  9 0.28        828
## 10 0.290      1776

ii.

Creamos el conjunto data_color que contiene el precio máximo en función del color de los diamantes (variable color). El color se ha codificado como factor ordenado con 7 niveles desde D(mejor) hasta J(peor).

if (!require(dplyr)) { install.packages(dplyr); library(dplyr) }
data_color <- data %>% group_by(color) %>% summarize(PrecioMax=max(price))
head(data_color, n=7) # El conjunto solo tiene 7 filas, una por cada nivel de color
## # A tibble: 7 x 2
##   color PrecioMax
##   <ord>     <int>
## 1 D         18693
## 2 E         18731
## 3 F         18791
## 4 G         18818
## 5 H         18803
## 6 I         18823
## 7 J         18710

iii.

Creamos el conjunto data_cut que contiene el precio máximo en función de la calidad del tallado de los diamantes (variable cut). La calidad del tallado se ha codificado como factor ordenado con 5 niveles Fair, Good, Very Good, Premium, Ideal

if (!require(dplyr)) { install.packages(dplyr); library(dplyr) }
data_cut <- data %>% group_by(cut) %>% summarize(PrecioMax=max(price))
head(data_cut, n=5) # El conjunto solo tiene 5 filas, una por cada nivel de cut
## # A tibble: 5 x 2
##   cut       PrecioMax
##   <ord>         <int>
## 1 Fair          18574
## 2 Good          18788
## 3 Very Good     18818
## 4 Premium       18823
## 5 Ideal         18806

iv.

Creamos el conjunto data_clarity que contiene el precio máximo en función de la claridad de los diamantes (variable clarity). La claridad se ha codificado como factor ordenado con 8 niveles I1(peor), SI2, SI1, VS2, VS1, VVS2, VVS1, IF(mejor).

if (!require(dplyr)) { install.packages(dplyr); library(dplyr) }
data_clarity <- data %>% group_by(clarity) %>% summarize(PrecioMax=max(price))
head(data_clarity, n=8) # El conjunto solo tiene 8 filas, una por cada nivel de clarity
## # A tibble: 8 x 2
##   clarity PrecioMax
##   <ord>       <int>
## 1 I1          18531
## 2 SI2         18804
## 3 SI1         18818
## 4 VS2         18823
## 5 VS1         18795
## 6 VVS2        18768
## 7 VVS1        18777
## 8 IF          18806

v.

Creamos el conjunto data_ca_co que contiene el precio máximo en función del peso y el color de los diamantes (variables carat y color).

if (!require(dplyr)) { install.packages(dplyr); library(dplyr) }
data_ca_co <- data %>% group_by(carat, color) %>% summarize(PrecioMax=max(price))
head(data_ca_co, n=10)
## # A tibble: 10 x 3
## # Groups:   carat [4]
##    carat color PrecioMax
##    <dbl> <ord>     <int>
##  1  0.2  D           367
##  2  0.2  E           367
##  3  0.2  F           367
##  4  0.21 D           386
##  5  0.21 E           394
##  6  0.22 D           404
##  7  0.22 E           404
##  8  0.22 F           470
##  9  0.23 D           688
## 10  0.23 E           682

vi.

Creamos el conjunto data_ca_cu que contiene el precio máximo en función del peso y el tallado de los diamantes (variables carat y cut).

if (!require(dplyr)) { install.packages(dplyr); library(dplyr) }
data_ca_cu <- data %>% group_by(carat, cut) %>% summarize(PrecioMax=max(price))
head(data_ca_cu, n=10)
## # A tibble: 10 x 3
## # Groups:   carat [4]
##    carat cut       PrecioMax
##    <dbl> <ord>         <int>
##  1  0.2  Very Good       367
##  2  0.2  Premium         367
##  3  0.2  Ideal           367
##  4  0.21 Very Good       386
##  5  0.21 Premium         394
##  6  0.22 Fair            337
##  7  0.22 Premium         470
##  8  0.23 Fair            369
##  9  0.23 Good            537
## 10  0.23 Very Good       682

vii.

Creamos el conjunto data_ca_cla que contiene el precio máximo en función del peso y la claridad de los diamantes (variables carat y clarity).

if (!require(dplyr)) { install.packages(dplyr); library(dplyr) }
data_ca_cla <- data %>% group_by(carat, clarity) %>% summarize(PrecioMax=max(price))
head(data_ca_cla, n=10)
## # A tibble: 10 x 3
## # Groups:   carat [4]
##    carat clarity PrecioMax
##    <dbl> <ord>       <int>
##  1  0.2  SI2           345
##  2  0.2  VS2           367
##  3  0.21 SI2           394
##  4  0.21 SI1           326
##  5  0.21 VS2           386
##  6  0.22 SI1           470
##  7  0.22 VS2           404
##  8  0.23 SI2           449
##  9  0.23 SI1           375
## 10  0.23 VS2           577

Análisis gráfico

Diagrama de puntos price ~ carat

library(ggplot2)
ggplot(data, aes(carat, price)) + 
  geom_point()

Parece haber una relación positiva entre el precio y el peso del diamante. Puede intuirse una relación no lineal y se aprecia un aumento de la dispersión en el precio cuando crece el peso de los diamantes.

En el siguiente gráfico modificamos el anterior para que los puntos tengan un color distinto según la calidad del tallado del diamante (niveles de cut).

library(ggplot2)
ggplot(data, aes(carat, price, colour=cut)) + 
  geom_point()

Las distintas categorías de cut quedan muy solapadas, lo que dificulta la interpretación del gráfico. Sin embargo, sí se puede apreciar que los diamantes con tallado Ideal (el mejor) se sitúan en la franja alta de la nube de puntos (mayor precio para un peso dado), mientras que aquellos con tallado Fair (el peor) se encuentran en la franja baja de la nube de puntos (menor precio para un peso dado).

En el siguiente gráfico separamos el gráfico anterior en cinco nubes de puntos, una para cada categoría de cut. La relación entre precio y peso parece de tipo exponencial positiva independientemente de la calidad del tallado. La calidad de tallado Fair parece mostrar mayor heteroscedasticidad en el precio a medida que el peso del diamante aumenta.

library(ggplot2)
ggplot(data, aes(carat, price, colour=cut)) + 
  geom_point() +
  facet_grid(cols=vars(cut))

El último gráfico de puntos recoge la relación entre precio y peso de los diamantes separando las nubes de puntos según los grupos formados con las categorías de calidad del tallado y color.

La influencia del color sobre la relación entre precio y peso es similar para las distintas calidades del tallado: un mejor color intensifica el grado de relación entre precio y peso. Dicho de otro modo, entre los diamantes con mejor color el aumento del precio ante un aumento del peso es mayor que entre los diamantes con peor color.

library(ggplot2)
ggplot(data, aes(carat, price, colour=cut)) + 
  geom_point() +
  facet_grid(rows=vars(color), cols=vars(cut))

Diagrama de caja price ~ cut

library(ggplot2)
ggplot(data, aes(cut, price)) + 
  geom_boxplot()

Observando el gráfico anterior vemos que la distribución del precio en función de la calidad del tallado es similar para todas las calidades. Los valores de la mediana son muy parecidos salvo para Ideal, donde es algo menor. La categoría Premium presenta una mayor dispersión (con un rango intercuartílico algo mayor). Todas las distribuciones presentan asimetría positiva o hacia la derecha. Además, es en los valores más altos para el precio donde aparecen los outliers de todas las distribuciones.

Diagrama de caja price ~ color

library(ggplot2)
ggplot(data, aes(color, price)) + 
  geom_boxplot()

Del gráfico anterior podemos deducir que las distribuciones del precio según el color presentan mayor variabilidad en la medida en que éste empeora. Además, el precio mediano es mayor entre los diamantes con peor color.1 Al igual que en el diagrama de caja según la calidad del tallado, en este caso todas las distribuciones son asimétricas positivas y presentan outliers en la cola derecha de la distribución.


Cuestiones finales

i. ¿Es lineal la relación entre price con respecto a cut y color?

Existe dependencia lineal con ambos factores. Si consideramos la relación entre price y carat se observa en los gráficos de puntos que ésta cambia tanto en función de cut como en función de color. En mi opinión, lo más destacable en cuanto a la influencia de cut es el aumento de heteroscedasticidad en el precio en función de carat cuando consideramos categorías con peor calidad del tallado. En cuanto a la influencia de color, el grado de la relación precio/peso se hace más fuerte entre las categorías con mejor color respecto a las de peor color.

ii. ¿Dirías que hay outliers en alguna de las combinaciones? Razona tu respuesta.

Atendiendo a los boxplots que hemos realizado observamos que hay outliers entre los precios altos tanto para los grupos formados por cut como para los formados por color.

iii. Para describir matemáticamente la relación entre price y las variables cuty color, ¿qué tipo de modelo aplicarías entonces? Razona tu respuesta.

Empezaría por ajustar un modelo de regresión lineal múltiple para price en función de carat y de un conjunto de variables ficticias o dummies construidas para los factores cut y color.


  1. Nota para el profesor: Me han sorprendido los resultados obtenidos en los diagramas de caja. En el primer gráfico el precio mediano más bajo es el de la categoría con mejor calidad de tallado (Fair) y en el segundo el precio mediano más bajo es el de la categoría con mejor color (D). ¿No son estos resultados contraintuitivos? ¿Hay algo que no esté considerando o se trata de algún error en mi código? Le agradecería si pudiera responderme estas cuestiones en los comentarios de su evaluación.