Como reto para este foro les proponemos que elijan un conjunto de datos de su preferencia y hagan un pequeño análisis del mismo, indicando los resultados más relevantes encontrados.
Pueden utilizar el dataset de su interés, ejemplo los disponibles en páginas como Kaggle.
Recuerden la importancia de comentar los trabajos de sus compañeros aportando nuevas ideas (siempre de forma constructiva). No es necesario hacer un análisis extenso del conjunto de datos ya que para eso tienen que realizar un trabajo de forma grupal.
Esto les servirá como entrenamiento previo al trabajo. El estudio debe hacerse obligatoriamente con la herramienta RStudio. Por favor, compartan el código utilizado y el conjunto de datos cuando posteen su contribución. Por ejemplo, pueden elegir una variable y realizar test de normalidad, ver cómo se distribuyen los datos, correlación entre variables, ajustes lineales, etc. Todo con RStudio.
Para este estudio me he basado en el siguiente dataset de kaggle.com:
https://www.kaggle.com/datasets/alexracape/lego-sets-and-prices-over-time
que nos proporciona información sobre los juegos de LEGO (nº de piezas, nº de minifiguras incluidas, …) y sus precios de venta a lo largo de los años, entre otros datos.
Aclaración sobre el significado de algunas variables que aparecen en la tabla original, aunque no las he utilizado para mi estudio:
El objetivo de este análisis es evaluar la variable USD_MSRP (precio) desde el año 2000 y su posible dependencia respecto del número de piezas contenidas en cada set.
NOTA: Se trata de un chunk genérico que tengo preparado, de ahí que se instalen más librerías de las necesarias para este estudio.
## Warning: package 'tidyverse' was built under R version 4.3.2
## Warning: package 'ggplot2' was built under R version 4.3.2
## Warning: package 'tidyr' was built under R version 4.3.2
## Warning: package 'readr' was built under R version 4.3.2
## Warning: package 'purrr' was built under R version 4.3.2
## Warning: package 'dplyr' was built under R version 4.3.2
## Warning: package 'forcats' was built under R version 4.3.2
## Warning: package 'lubridate' was built under R version 4.3.2
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr 1.1.3 ✔ readr 2.1.4
## ✔ forcats 1.0.0 ✔ stringr 1.5.0
## ✔ ggplot2 3.4.4 ✔ tibble 3.2.1
## ✔ lubridate 1.9.3 ✔ tidyr 1.3.0
## ✔ purrr 1.0.2
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag() masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
## Warning: package 'modeest' was built under R version 4.3.2
##
## Attaching package: 'moments'
##
## The following object is masked from 'package:modeest':
##
## skewness
## Warning: package 'plotrix' was built under R version 4.3.2
## Warning: package 'car' was built under R version 4.3.2
## Loading required package: carData
## Warning: package 'carData' was built under R version 4.3.2
##
## Attaching package: 'car'
##
## The following object is masked from 'package:dplyr':
##
## recode
##
## The following object is masked from 'package:purrr':
##
## some
## Warning: package 'tidytext' was built under R version 4.3.2
## Warning: package 'naivebayes' was built under R version 4.3.2
## naivebayes 0.9.7 loaded
## Warning: package 'tm' was built under R version 4.3.2
## Loading required package: NLP
##
## Attaching package: 'NLP'
##
## The following object is masked from 'package:ggplot2':
##
## annotate
## Warning: package 'caret' was built under R version 4.3.2
## Loading required package: lattice
##
## Attaching package: 'caret'
##
## The following object is masked from 'package:purrr':
##
## lift
## Warning: package 'corrplot' was built under R version 4.3.2
## corrplot 0.92 loaded
## Warning: package 'data.table' was built under R version 4.3.2
##
## Attaching package: 'data.table'
##
## The following object is masked from 'package:naivebayes':
##
## tables
##
## The following objects are masked from 'package:lubridate':
##
## hour, isoweek, mday, minute, month, quarter, second, wday, week,
## yday, year
##
## The following objects are masked from 'package:dplyr':
##
## between, first, last
##
## The following object is masked from 'package:purrr':
##
## transpose
## Warning: package 'vcd' was built under R version 4.3.2
## Loading required package: grid
## Warning: package 'gplots' was built under R version 4.3.2
##
## Attaching package: 'gplots'
##
## The following object is masked from 'package:plotrix':
##
## plotCI
##
## The following object is masked from 'package:stats':
##
## lowess
setwd("C:/Users/Usuario/Documents/Beatriz/CV cursos y ofertas/2_cursos/20231010 master BIG DATA/modulo 2/z_mis pruebas con R/lego")
lego = read.csv(file="LEGO.csv", header = TRUE, sep = ",")
str(lego)
## 'data.frame': 14936 obs. of 17 variables:
## $ Set_ID : chr "75-1" "77-1" "077-1" "78-1" ...
## $ Name : chr "PreSchool Set" "PreSchool Set" "Pre-School Set" "PreSchool Set" ...
## $ Year : int 1975 1975 1975 1975 1975 1975 1975 1975 1975 1975 ...
## $ Theme : chr "PreSchool" "PreSchool" "Duplo" "PreSchool" ...
## $ Theme_Group : chr "Pre-school" "Pre-school" "Pre-school" "Pre-school" ...
## $ Subtheme : chr "" "" "" "" ...
## $ Category : chr "Normal" "Normal" "Normal" "Normal" ...
## $ Packaging : chr "{Not specified}" "{Not specified}" "{Not specified}" "{Not specified}" ...
## $ Num_Instructions: int 0 0 0 0 0 0 0 0 0 0 ...
## $ Availability : chr "{Not specified}" "{Not specified}" "{Not specified}" "{Not specified}" ...
## $ Pieces : num 16 20 21 32 330 87 86 83 82 293 ...
## $ Minifigures : num NA NA NA NA NA NA NA NA NA 5 ...
## $ Owned : num 10 11 10 8 10 279 252 404 299 479 ...
## $ Rating : num 0 0 0 0 0 0 0 0 0 0 ...
## $ USD_MSRP : num NA NA NA NA NA NA NA NA NA NA ...
## $ Total_Quantity : num NA NA 0 NA 0 0 0 0 0 0 ...
## $ Current_Price : num NA NA NA NA NA NA NA NA NA NA ...
En primer lugar, como hay muchos datos, voy a convertirlo a data.table para que trabaje más rápido y voy a seleccionar solo algunas variables (columnas).
lego_dt = as.data.table(lego)
str(lego_dt)
## Classes 'data.table' and 'data.frame': 14936 obs. of 17 variables:
## $ Set_ID : chr "75-1" "77-1" "077-1" "78-1" ...
## $ Name : chr "PreSchool Set" "PreSchool Set" "Pre-School Set" "PreSchool Set" ...
## $ Year : int 1975 1975 1975 1975 1975 1975 1975 1975 1975 1975 ...
## $ Theme : chr "PreSchool" "PreSchool" "Duplo" "PreSchool" ...
## $ Theme_Group : chr "Pre-school" "Pre-school" "Pre-school" "Pre-school" ...
## $ Subtheme : chr "" "" "" "" ...
## $ Category : chr "Normal" "Normal" "Normal" "Normal" ...
## $ Packaging : chr "{Not specified}" "{Not specified}" "{Not specified}" "{Not specified}" ...
## $ Num_Instructions: int 0 0 0 0 0 0 0 0 0 0 ...
## $ Availability : chr "{Not specified}" "{Not specified}" "{Not specified}" "{Not specified}" ...
## $ Pieces : num 16 20 21 32 330 87 86 83 82 293 ...
## $ Minifigures : num NA NA NA NA NA NA NA NA NA 5 ...
## $ Owned : num 10 11 10 8 10 279 252 404 299 479 ...
## $ Rating : num 0 0 0 0 0 0 0 0 0 0 ...
## $ USD_MSRP : num NA NA NA NA NA NA NA NA NA NA ...
## $ Total_Quantity : num NA NA 0 NA 0 0 0 0 0 0 ...
## $ Current_Price : num NA NA NA NA NA NA NA NA NA NA ...
## - attr(*, ".internal.selfref")=<externalptr>
lego_red = select(lego_dt, Set_ID, Name, Year, Pieces, Minifigures, Rating, USD_MSRP, Current_Price)
str(lego_red)
## Classes 'data.table' and 'data.frame': 14936 obs. of 8 variables:
## $ Set_ID : chr "75-1" "77-1" "077-1" "78-1" ...
## $ Name : chr "PreSchool Set" "PreSchool Set" "Pre-School Set" "PreSchool Set" ...
## $ Year : int 1975 1975 1975 1975 1975 1975 1975 1975 1975 1975 ...
## $ Pieces : num 16 20 21 32 330 87 86 83 82 293 ...
## $ Minifigures : num NA NA NA NA NA NA NA NA NA 5 ...
## $ Rating : num 0 0 0 0 0 0 0 0 0 0 ...
## $ USD_MSRP : num NA NA NA NA NA NA NA NA NA NA ...
## $ Current_Price: num NA NA NA NA NA NA NA NA NA NA ...
## - attr(*, ".internal.selfref")=<externalptr>
Para reducir el número de observaciones y teniendo en cuenta que no se dispone de información de precios de venta (USD_MSRP) durante gran parte de los años iniciales, voy a centrar el análisis a partir del año 2000.
Para ello, creo un subconjunto, dentro del cual me quedo solo con aquellos casos en que el precio es conocido (descarto NAs):
unique(lego_red$Year)
## [1] 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989
## [16] 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004
## [31] 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019
## [46] 2020 2021 2022 2023
lego_red_2000 = lego_red %>%
subset(Year>1999) %>%
filter(!is.na(USD_MSRP))
summary(is.na(lego_red_2000)) #vemos que variables tienen NAs
## Set_ID Name Year Pieces
## Mode :logical Mode :logical Mode :logical Mode :logical
## FALSE:5822 FALSE:5822 FALSE:5822 FALSE:5215
## TRUE :607
## Minifigures Rating USD_MSRP Current_Price
## Mode :logical Mode :logical Mode :logical Mode :logical
## FALSE:3560 FALSE:5822 FALSE:5822 FALSE:3604
## TRUE :2262 TRUE :2218
str(lego_red_2000)
## Classes 'data.table' and 'data.frame': 5822 obs. of 8 variables:
## $ Set_ID : chr "3458-1" "3461-1" "3462-1" "3470-1" ...
## $ Name : chr "2x4 Black Bricks" "2x4 Dark Green Bricks" "2x4 Red Bricks" "1x4 White Bricks" ...
## $ Year : int 2000 2000 2000 2000 2000 2000 2000 2000 2000 2000 ...
## $ Pieces : num 50 50 50 50 100 25 87 24 20 NA ...
## $ Minifigures : num NA NA NA NA NA NA NA NA NA NA ...
## $ Rating : num 0 0 0 0 0 0 0 0 0 0 ...
## $ USD_MSRP : num 6.99 6.99 6.99 5.99 8.99 4.99 9.99 4.99 5.99 4.99 ...
## $ Current_Price: num NA NA NA NA NA NA NA 10 NA NA ...
## - attr(*, ".internal.selfref")=<externalptr>
Paso a estudiar la variable USD_MSRP, que es cuantitativa contínua:
summary(lego_red_2000$USD_MSRP)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 1.49 9.99 19.99 40.03 49.99 849.99
Se observa que el rango de precios es muy amplio (entre 1.49USD y 849.99USD) y además, teniendo en cuenta los valores de los cuantiles, media y mediana, queda claro que hay mucha más densidad en el rango de precios bajos, lo cual es lógico por otra parte, ya que gran parte de estos set están dirigidos a niños y por lo tanto, tienen que tener precios asequibles, mientras que los modelos más caros corresponden a series especiales y/o de coleccionista, con mucha probabilidad.
Compruebo la normalidad gráficamente:
hist(lego_red_2000$USD_MSRP, freq=FALSE, main = "Histograma de Precios de venta en USD", col="cyan")
lines(density(lego_red_2000$USD_MSRP), col="red")
y si lo hago desde un punto de vista analítico:
g1=skewness(lego_red_2000$USD_MSRP)
paste ("Asimetría (g1)=", g1)
## [1] "Asimetría (g1)= 4.6628312942893"
g2=kurtosis(lego_red_2000$USD_MSRP)
paste ("Curtosis (g2) =", g2)
## [1] "Curtosis (g2) = 37.6750948245125"
Aquí se confirma lo ya visto gráficamente de manera muy evidente: - g1>0 –> Asimetría positiva (cola a la derecha) - g2>0 –> Leptocúrtica. Además, como es >2 no podemos asumir el supuesto de normalidad de los residuos.
Voy a intentar ahora analizar si hay alguna dependencia entre el precio y el número de piezas
En primer lugar, preparo una matriz de correlación de todas las variables numéricas, donde confirmo que la elección de dichas variables cuya dependencia quiero analizar es correcta:
M_cor_total = cor(lego_red_2000[,3:8], use = "complete.obs")
corrplot(M_cor_total,title="Matriz de correlación LEGO")
Efectivamente, parecen ser buenas candidatas, así que profundizamos en el análisis:
plot(lego_red_2000$Pieces,lego_red_2000$USD_MSRP)
abline()
Aunque hay cierta dispersión, sí parece haber relación de dependencia en el gráfico anterior.
Creo la matriz de correlación:
M_cor = cor(lego_red_2000[ ,c("USD_MSRP", "Pieces")], use = "complete.obs")
M_cor
## USD_MSRP Pieces
## USD_MSRP 1.0000000 0.8766067
## Pieces 0.8766067 1.0000000
Para tener el valor de r guardado:
r=cor(lego_red_2000$USD_MSRP,lego_red_2000$Pieces,use = "complete.obs")
r
## [1] 0.8766067
A continuación paso a calcular los coeficiones de la línea de regresión:
regresion_lego = lm(USD_MSRP~Pieces, data=lego_red_2000)
summary(regresion_lego)
##
## Call:
## lm(formula = USD_MSRP ~ Pieces, data = lego_red_2000)
##
## Residuals:
## Min 1Q Median 3Q Max
## -655.21 -10.53 -5.38 4.61 346.32
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 1.337e+01 4.411e-01 30.31 <2e-16 ***
## Pieces 7.626e-02 5.798e-04 131.53 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 27.42 on 5213 degrees of freedom
## (607 observations deleted due to missingness)
## Multiple R-squared: 0.7684, Adjusted R-squared: 0.7684
## F-statistic: 1.73e+04 on 1 and 5213 DF, p-value: < 2.2e-16
Con los datos obtenidos, quedaría la fórmula:
USD_MSRP = 0.07626 * Pieces + 13.37
Como datos significativos:
El coeficiente de determinación R^2 = 0.7684 es decir, el número de piezas explica en un 76,84% de los casos cómo varía el precio de venta (PVP en USD) (R^2 coincide con el valor de r^2 = 0.8766067^2=0.7684 como era de esperar)
Además p-value < nivel de significación (α), es decir, se confirma que el predictor sí que explica el modelo.
A modo de resumen, éstas son las conclusiones que he obtenido del presente estudio respecto a los juegos de LEGO:
Existe una gran variedad de precios, pero una amplia mayoría se concentran en la zona de “precios bajos”, lo cual es lógico por otra parte, ya que gran parte de estos juegos están dirigidos a niños y, por lo tanto, tienen que tener precios “asequibles”, mientras que los modelos más caros corresponden a series especiales y/o de coleccionista, “juegos” más exclusivos (no entrarían ya en la consideración de juguetes).
Existe una relación de dependencia bastante clara y lineal entre el número de piezas del juego y el precio del mismo.