1. Introducción

En este trabajo se realiza un análisis exploratorio de la base de datos de títulos disponibles en Netflix. Se analizan las principales características de las variables, su distribución y algunos valores descriptivos.

Posteriormente, se construyen e interpretan cuatro intervalos de confianza con un nivel de confianza del 95%, utilizando diferentes variables de la base de datos.

2. Análisis exploratorio de datos

2.1 Carga y descripción de la base de datos

library(tidyverse)
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr     1.2.1     ✔ readr     2.2.0
## ✔ forcats   1.0.1     ✔ stringr   1.6.0
## ✔ ggplot2   4.0.3     ✔ tibble    3.3.1
## ✔ lubridate 1.9.5     ✔ tidyr     1.3.2
## ✔ purrr     1.2.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
netflix <- read_csv("netflix_titles.csv")
## Rows: 8807 Columns: 12
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (11): show_id, type, title, director, cast, country, date_added, rating,...
## dbl  (1): release_year
## 
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
head(netflix)
## # A tibble: 6 × 12
##   show_id type    title    director cast  country date_added release_year rating
##   <chr>   <chr>   <chr>    <chr>    <chr> <chr>   <chr>             <dbl> <chr> 
## 1 s1      Movie   Dick Jo… Kirsten… <NA>  United… September…         2020 PG-13 
## 2 s2      TV Show Blood &… <NA>     Ama … South … September…         2021 TV-MA 
## 3 s3      TV Show Ganglan… Julien … Sami… <NA>    September…         2021 TV-MA 
## 4 s4      TV Show Jailbir… <NA>     <NA>  <NA>    September…         2021 TV-MA 
## 5 s5      TV Show Kota Fa… <NA>     Mayu… India   September…         2021 TV-MA 
## 6 s6      TV Show Midnigh… Mike Fl… Kate… <NA>    September…         2021 TV-MA 
## # ℹ 3 more variables: duration <chr>, listed_in <chr>, description <chr>
dim(netflix)
## [1] 8807   12
names(netflix)
##  [1] "show_id"      "type"         "title"        "director"     "cast"        
##  [6] "country"      "date_added"   "release_year" "rating"       "duration"    
## [11] "listed_in"    "description"
str(netflix)
## spc_tbl_ [8,807 × 12] (S3: spec_tbl_df/tbl_df/tbl/data.frame)
##  $ show_id     : chr [1:8807] "s1" "s2" "s3" "s4" ...
##  $ type        : chr [1:8807] "Movie" "TV Show" "TV Show" "TV Show" ...
##  $ title       : chr [1:8807] "Dick Johnson Is Dead" "Blood & Water" "Ganglands" "Jailbirds New Orleans" ...
##  $ director    : chr [1:8807] "Kirsten Johnson" NA "Julien Leclercq" NA ...
##  $ cast        : chr [1:8807] NA "Ama Qamata, Khosi Ngema, Gail Mabalane, Thabang Molaba, Dillon Windvogel, Natasha Thahane, Arno Greeff, Xolile "| __truncated__ "Sami Bouajila, Tracy Gotoas, Samuel Jouy, Nabiha Akkari, Sofia Lesaffre, Salim Kechiouche, Noureddine Farihi, G"| __truncated__ NA ...
##  $ country     : chr [1:8807] "United States" "South Africa" NA NA ...
##  $ date_added  : chr [1:8807] "September 25, 2021" "September 24, 2021" "September 24, 2021" "September 24, 2021" ...
##  $ release_year: num [1:8807] 2020 2021 2021 2021 2021 ...
##  $ rating      : chr [1:8807] "PG-13" "TV-MA" "TV-MA" "TV-MA" ...
##  $ duration    : chr [1:8807] "90 min" "2 Seasons" "1 Season" "1 Season" ...
##  $ listed_in   : chr [1:8807] "Documentaries" "International TV Shows, TV Dramas, TV Mysteries" "Crime TV Shows, International TV Shows, TV Action & Adventure" "Docuseries, Reality TV" ...
##  $ description : chr [1:8807] "As her father nears the end of his life, filmmaker Kirsten Johnson stages his death in inventive and comical wa"| __truncated__ "After crossing paths at a party, a Cape Town teen sets out to prove whether a private-school swimming star is h"| __truncated__ "To protect his family from a powerful drug lord, skilled thief Mehdi and his expert team of robbers are pulled "| __truncated__ "Feuds, flirtations and toilet talk go down among the incarcerated women at the Orleans Justice Center in New Or"| __truncated__ ...
##  - attr(*, "spec")=
##   .. cols(
##   ..   show_id = col_character(),
##   ..   type = col_character(),
##   ..   title = col_character(),
##   ..   director = col_character(),
##   ..   cast = col_character(),
##   ..   country = col_character(),
##   ..   date_added = col_character(),
##   ..   release_year = col_double(),
##   ..   rating = col_character(),
##   ..   duration = col_character(),
##   ..   listed_in = col_character(),
##   ..   description = col_character()
##   .. )
##  - attr(*, "problems")=<pointer: 0x62dcba583dd0>

2.2 Tipos de variables

tabla_tipos <- data.frame(
  Variable = c(
    "show_id", "type", "title", "director", "cast", "country",
    "date_added", "release_year", "rating", "duration",
    "listed_in", "description"
  ),
  Tipo_de_variable = c(
    "Cualitativa nominal",
    "Cualitativa nominal",
    "Cualitativa nominal",
    "Cualitativa nominal",
    "Cualitativa nominal",
    "Cualitativa nominal",
    "Cualitativa temporal",
    "Cuantitativa discreta",
    "Cualitativa ordinal",
    "Cuantitativa discreta",
    "Cualitativa nominal",
    "Cualitativa nominal"
  )
)

tabla_tipos
##        Variable      Tipo_de_variable
## 1       show_id   Cualitativa nominal
## 2          type   Cualitativa nominal
## 3         title   Cualitativa nominal
## 4      director   Cualitativa nominal
## 5          cast   Cualitativa nominal
## 6       country   Cualitativa nominal
## 7    date_added  Cualitativa temporal
## 8  release_year Cuantitativa discreta
## 9        rating   Cualitativa ordinal
## 10     duration Cuantitativa discreta
## 11    listed_in   Cualitativa nominal
## 12  description   Cualitativa nominal

2.3 Datos faltantes

datos_faltantes <- data.frame(
  Variable = names(netflix),
  Datos_faltantes = colSums(is.na(netflix))
)

datos_faltantes
##                  Variable Datos_faltantes
## show_id           show_id               0
## type                 type               0
## title               title               0
## director         director            2634
## cast                 cast             825
## country           country             831
## date_added     date_added              10
## release_year release_year               0
## rating             rating               4
## duration         duration               3
## listed_in       listed_in               0
## description   description               0

2.4 Variables cuantitativas

Para analizar la duración de las películas y el número de temporadas de las series, se transformó la variable duration en dos variables numéricas.

netflix$duration_min <- ifelse(
  netflix$type == "Movie",
  as.numeric(gsub("[^0-9]", "", netflix$duration)),
  NA
)

netflix$seasons <- ifelse(
  netflix$type == "TV Show",
  as.numeric(gsub("[^0-9]", "", netflix$duration)),
  NA
)

resumen_numerico <- data.frame(
  Variable = c("release_year", "duration_min", "seasons"),
  Mínimo = c(
    min(netflix$release_year, na.rm = TRUE),
    min(netflix$duration_min, na.rm = TRUE),
    min(netflix$seasons, na.rm = TRUE)
  ),
  Q1 = c(
    quantile(netflix$release_year, 0.25, na.rm = TRUE),
    quantile(netflix$duration_min, 0.25, na.rm = TRUE),
    quantile(netflix$seasons, 0.25, na.rm = TRUE)
  ),
  Mediana = c(
    median(netflix$release_year, na.rm = TRUE),
    median(netflix$duration_min, na.rm = TRUE),
    median(netflix$seasons, na.rm = TRUE)
  ),
  Media = c(
    mean(netflix$release_year, na.rm = TRUE),
    mean(netflix$duration_min, na.rm = TRUE),
    mean(netflix$seasons, na.rm = TRUE)
  ),
  Q3 = c(
    quantile(netflix$release_year, 0.75, na.rm = TRUE),
    quantile(netflix$duration_min, 0.75, na.rm = TRUE),
    quantile(netflix$seasons, 0.75, na.rm = TRUE)
  ),
  Máximo = c(
    max(netflix$release_year, na.rm = TRUE),
    max(netflix$duration_min, na.rm = TRUE),
    max(netflix$seasons, na.rm = TRUE)
  ),
  `Desv. Est.` = c(
    sd(netflix$release_year, na.rm = TRUE),
    sd(netflix$duration_min, na.rm = TRUE),
    sd(netflix$seasons, na.rm = TRUE)
  )
)

resumen_numerico
##       Variable Mínimo   Q1 Mediana       Media   Q3 Máximo Desv..Est.
## 1 release_year   1925 2013    2017 2014.180198 2019   2021   8.819312
## 2 duration_min      3   87      98   99.577187  114    312  28.290593
## 3      seasons      1    1       1    1.764948    2     17   1.582752

2.5 Variables cualitativas

tabla_type <- data.frame(
  Categoría = names(table(netflix$type)),
  Frecuencia = as.vector(table(netflix$type)),
  Porcentaje = round(
    as.vector(prop.table(table(netflix$type))) * 100, 2
  )
)

tabla_type
##   Categoría Frecuencia Porcentaje
## 1     Movie       6131      69.62
## 2   TV Show       2676      30.38
rating_limpio <- netflix$rating[
  !netflix$rating %in% c("66 min", "74 min", "84 min")
]

tabla_rating <- data.frame(
  Categoría = names(table(rating_limpio)),
  Frecuencia = as.vector(table(rating_limpio)),
  Porcentaje = round(
    as.vector(prop.table(table(rating_limpio))) * 100, 2
  )
)

tabla_rating
##    Categoría Frecuencia Porcentaje
## 1          G         41       0.47
## 2      NC-17          3       0.03
## 3         NR         80       0.91
## 4         PG        287       3.26
## 5      PG-13        490       5.57
## 6          R        799       9.08
## 7      TV-14       2160      24.55
## 8       TV-G        220       2.50
## 9      TV-MA       3207      36.44
## 10     TV-PG        863       9.81
## 11      TV-Y        307       3.49
## 12     TV-Y7        334       3.80
## 13  TV-Y7-FV          6       0.07
## 14        UR          3       0.03

2.6 Gráficos

Año de lanzamiento

hist(
  netflix$release_year,
  main = "Distribución del año de lanzamiento",
  xlab = "Año de lanzamiento",
  ylab = "Frecuencia"
)

Duración de las películas

hist(
  netflix$duration_min,
  main = "Distribución de la duración de las películas",
  xlab = "Duración (minutos)",
  ylab = "Frecuencia"
)

Número de temporadas

hist(
  netflix$seasons,
  main = "Distribución del número de temporadas",
  xlab = "Número de temporadas",
  ylab = "Frecuencia"
)

Tipo de contenido

barplot(
  table(netflix$type),
  main = "Distribución por tipo de contenido",
  xlab = "Tipo de contenido",
  ylab = "Frecuencia"
)

Clasificación

barplot(
  sort(table(rating_limpio), decreasing = TRUE),
  main = "Distribución por clasificación",
  xlab = "Clasificación",
  ylab = "Frecuencia",
  las = 2
)

3. Intervalos de confianza

3.1 Intervalo de confianza para la media poblacional

Se estima la duración promedio de las películas disponibles en la base de datos.

ic_media <- t.test(
  netflix$duration_min,
  conf.level = 0.95
)

ic_media
## 
##  One Sample t-test
## 
## data:  netflix$duration_min
## t = 275.54, df = 6127, p-value < 2.2e-16
## alternative hypothesis: true mean is not equal to 0
## 95 percent confidence interval:
##   98.86872 100.28565
## sample estimates:
## mean of x 
##  99.57719

El intervalo de confianza obtenido es de 98,87 a 100,29 minutos, con una media muestral de 99,58 minutos.

Interpretación: Con un nivel de confianza del 95%, se estima que la duración promedio de las películas se encuentra entre 98,87 y 100,29 minutos.

3.2 Intervalo de confianza para una proporción poblacional

Aquí vamos a calcular el intervalo para la proporción de títulos que corresponden a películas.

Para estimar la proporción de películas dentro de los títulos de Netflix, se utiliza un nivel de confianza del 95%.

x <- sum(netflix$type == "Movie")
n <- sum(!is.na(netflix$type))

ic_proporcion <- prop.test(
  x = x,
  n = n,
  conf.level = 0.95
)

ic_proporcion
## 
##  1-sample proportions test with continuity correction
## 
## data:  x out of n, null probability 0.5
## X-squared = 1354.6, df = 1, p-value < 2.2e-16
## alternative hypothesis: true p is not equal to 0.5
## 95 percent confidence interval:
##  0.6864043 0.7057252
## sample estimates:
##         p 
## 0.6961508

La muestra contiene 6131 películas de un total de 8807 títulos, lo que corresponde a una proporción muestral de aproximadamente 69,62%.

El intervalo de confianza del 95% para la proporción poblacional se encuentra entre 68,64% y 70,57%.

Interpretación: Con un nivel de confianza del 95%, se estima que la proporción poblacional de títulos de Netflix que corresponden a películas se encuentra entre 68,64% y 70,57%.

3.3 Intervalo de confianza para la diferencia de dos medias

Para comparar la duración promedio de las películas con clasificación R y PG-13, se construye un intervalo de confianza del 95%.

peliculas_R <- netflix$duration_min[netflix$rating == "R"]
peliculas_PG13 <- netflix$duration_min[netflix$rating == "PG-13"]

ic_diferencia_medias <- t.test(
  peliculas_R,
  peliculas_PG13,
  conf.level = 0.95
)

ic_diferencia_medias
## 
##  Welch Two Sample t-test
## 
## data:  peliculas_R and peliculas_PG13
## t = -1.4856, df = 998.65, p-value = 0.1377
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
##  -3.7375854  0.5167624
## sample estimates:
## mean of x mean of y 
##  106.7202  108.3306

La duración promedio de las películas con clasificación R fue de 106,72 minutos, mientras que la duración promedio de las películas con clasificación PG-13 fue de 108,33 minutos.

El intervalo de confianza del 95% para la diferencia entre las medias se encuentra entre -3,74 y 0,52 minutos.

Interpretación: Con un nivel de confianza del 95%, la diferencia entre las duraciones promedio de las películas con clasificación R y PG-13 se encuentra entre -3,74 y 0,52 minutos. Como el intervalo incluye el valor 0, los datos no permiten establecer una diferencia estadísticamente significativa entre las dos medias.

3.4 Intervalo de confianza para la diferencia de dos proporciones

Para comparar dos proporciones poblacionales, se analiza la proporción de títulos clasificados como TV-MA y TV-14.

x1 <- sum(netflix$rating == "TV-MA", na.rm = TRUE)
x2 <- sum(netflix$rating == "TV-14", na.rm = TRUE)

n1 <- sum(!is.na(netflix$rating))
n2 <- n1

ic_diferencia_proporciones <- prop.test(
  x = c(x1, x2),
  n = c(n1, n2),
  conf.level = 0.95
)

ic_diferencia_proporciones
## 
##  2-sample test for equality of proportions with continuity correction
## 
## data:  c(x1, x2) out of c(n1, n2)
## X-squared = 293.26, df = 1, p-value < 2.2e-16
## alternative hypothesis: two.sided
## 95 percent confidence interval:
##  0.1053375 0.1325360
## sample estimates:
##    prop 1    prop 2 
## 0.3643076 0.2453709

La proporción de títulos con clasificación TV-MA fue de 36,43%, mientras que la proporción de títulos con clasificación TV-14 fue de 24,54%.

El intervalo de confianza del 95% para la diferencia entre ambas proporciones se encuentra entre 10,53% y 13,25%.

Interpretación: Con un nivel de confianza del 95%, la diferencia entre las proporciones de títulos clasificados como TV-MA y TV-14 se encuentra entre 10,53 y 13,25 puntos porcentuales. Como el intervalo no incluye el valor 0, existe evidencia de una diferencia entre ambas proporciones.

4. Conclusiones

El análisis exploratorio permitió identificar que las películas representan la mayor parte del catálogo analizado, con 69,62% de los títulos, mientras que los programas de televisión representan el 30,38%. Esto muestra que, dentro de los datos estudiados, Netflix tiene una mayor presencia de películas que de series.

En cuanto a la duración de las películas, el intervalo de confianza indica que la duración promedio se encuentra entre 98,87 y 100,29 minutos, con un nivel de confianza del 95%. En el contexto del catálogo analizado, esto significa que una película típica de Netflix tiene una duración cercana a los 100 minutos.

Para la proporción de películas, el intervalo de confianza se ubicó entre 68,64% y 70,57%. Esto indica que, considerando la población representada por los datos analizados, aproximadamente siete de cada diez títulos corresponden a películas.

Al comparar las películas con clasificación R y PG-13, el intervalo para la diferencia de medias fue de -3,74 a 0,52 minutos. Como el intervalo incluye el valor 0, los datos analizados no permiten establecer una diferencia estadísticamente significativa entre la duración promedio de las películas con estas dos clasificaciones. En términos del catálogo, las películas R y PG-13 presentan duraciones promedio bastante similares.

Finalmente, la diferencia entre las proporciones de títulos clasificados como TV-MA y TV-14 presentó un intervalo de confianza entre 10,53 y 13,25 puntos porcentuales. Al no incluir el valor 0, los resultados proporcionan evidencia de una diferencia entre ambas proporciones. En el catálogo analizado, los títulos clasificados como TV-MA representan una proporción mayor que los clasificados como TV-14, con una diferencia estimada de alrededor de 10 a 13 puntos porcentuales.