Este trabajo corresponde al proyecto final de la clase de Métodos Cuantitativos. El objetivo es aplicar, sobre datos reales de entretenimiento, las técnicas vistas en el curso para describir patrones, contrastar hipótesis y comunicar resultados de forma clara. Se analizan dos tipos de contenido: series (rendimiento en Netflix en 2023) y películas (calificaciones y metadatos asociados a IMDb), con el fin de comparar qué factores se relacionan con el éxito en cada plataforma o catálogo.
A lo largo del curso utilizamos, entre otras, las siguientes herramientas estadísticas: análisis de covarianza y correlación, distribuciones de probabilidad (modelo normal como referencia), pruebas de hipótesis, la prueba \(\chi^2\) de independencia, la prueba t de Student para comparar medias, el análisis de varianza (ANOVA) de un factor y la regresión lineal simple. Cada sección del informe enlaza una de estas herramientas con una gráfica, su interpretación y una conclusión breve.
| Parte | Fuente de datos | Enfoque del análisis |
|---|---|---|
| I — Netflix | Fuentes/total_netflix_2023 new.csv |
Horas vistas, valoraciones, calificación y disponibilidad global |
| II — Películas (IMDb) | Fuentes/movies.json |
Calificación IMDb, año de estreno, género y tendencias temporales |
ruta_netflix <- "Fuentes/total_netflix_2023 new.csv"
netflix <- read.csv(ruta_netflix, stringsAsFactors = FALSE)
netflix <- netflix %>%
mutate(
Hours.Viewed = as.numeric(gsub("[^0-9.]", "", Hours.Viewed)),
Number.of.Ratings = as.numeric(gsub("[^0-9.]", "", Number.of.Ratings)),
Rating = as.numeric(Rating),
log_Hours = log10(Hours.Viewed),
Available.Globally. = factor(Available.Globally., levels = c("No", "Yes")),
GenreSimple = case_when(
grepl("Comedy", Genre) ~ "Comedy",
grepl("Drama", Genre) ~ "Drama",
grepl("Action", Genre) ~ "Action",
TRUE ~ "Otro"
),
GenreSimple = factor(GenreSimple)
) %>%
filter(
!is.na(Hours.Viewed),
!is.na(Rating),
!is.na(Number.of.Ratings),
Hours.Viewed > 0,
Number.of.Ratings >= 0
)
n_netflix <- nrow(netflix)
Tras la limpieza hay 14,633 series. Aproximadamente 29% está disponible globalmente. Para horas vistas usamos \(\log_{10}\); la justificación aparece al cierre de esta parte.
En series de Netflix preguntamos si horas vistas, número de valoraciones y calificación (0–10) varían juntas. La correlación de Pearson resume esa relación lineal; para horas aplicamos \(\log_{10}\) por el sesgo de la escala original.
vars_cov <- netflix %>%
select(log_Hours, Number.of.Ratings, Rating) %>%
rename(
`log10(Horas vistas)` = log_Hours,
`N. valoraciones` = Number.of.Ratings,
Calificacion = Rating
)
cor_mat <- cor(vars_cov, use = "complete.obs")
tabla_proyecto(
as.data.frame(round(cor_mat, 3)),
caption = "Netflix — Matriz de correlación",
align = "c",
digits = 3
)
| log10(Horas vistas) | N. valoraciones | Calificacion | |
|---|---|---|---|
| log10(Horas vistas) | 1.000 | -0.003 | -0.008 |
| N. valoraciones | -0.003 | 1.000 | 0.117 |
| Calificacion | -0.008 | 0.117 | 1.000 |
cor_largo <- as.data.frame(as.table(cor_mat))
names(cor_largo) <- c("Var1", "Var2", "r")
ggplot(cor_largo, aes(Var1, Var2, fill = r)) +
geom_tile(color = "white", linewidth = 0.8) +
geom_text(aes(label = sprintf("%.2f", r)), color = "white", fontface = "bold", size = 5) +
scale_fill_gradientn(colours = paleta_cor, limits = c(-1, 1), name = "Correlación") +
labs(
title = titulo_grafica("Análisis de covarianza"),
subtitle = "Correlación entre log10(horas), valoraciones y calificación",
x = NULL, y = NULL
) +
tema_proyecto +
theme(axis.text.x = element_text(angle = 25, hjust = 1, face = "bold"))
Netflix: matriz de correlación.
La correlación más fuerte aparece entre
N. valoraciones y Calificacion (0.117).
Entre log-horas y calificación la relación es débil (-0.008):
más reproducción no garantiza mejor nota en esta
muestra.
Describimos la distribución de calificaciones de series y la comparamos con una curva normal teórica (media y desviación muestrales) como referencia visual.
mu_n <- mean(netflix$Rating)
sd_n <- sd(netflix$Rating)
tabla_proyecto(
data.frame(
Estadistico = c("Media", "Desv. est.", "Mínimo", "Máximo"),
Valor = c(mu_n, sd_n, min(netflix$Rating), max(netflix$Rating))
),
digits = 3,
caption = "Netflix — Resumen de calificaciones",
align = c("l", "r")
)
| Estadistico | Valor |
|---|---|
| Media | 6.624 |
| Desv. est. | 1.256 |
| Mínimo | 1.400 |
| Máximo | 10.000 |
x_seq <- seq(min(netflix$Rating), max(netflix$Rating), length.out = 200)
curva_norm <- data.frame(Rating = x_seq, densidad = dnorm(x_seq, mu_n, sd_n))
ggplot(netflix, aes(x = Rating, fill = GenreSimple)) +
geom_histogram(aes(y = after_stat(density)), bins = 25, alpha = 0.75, color = "white", position = "identity") +
geom_line(data = curva_norm, aes(x = Rating, y = densidad), inherit.aes = FALSE, color = col_linea, linewidth = 1.4) +
scale_fill_manual(values = col_genero, name = "Género") +
labs(
title = titulo_grafica("Distribución de probabilidades"),
subtitle = "Histograma por género con curva normal teórica superpuesta",
x = "Calificación (0–10)", y = "Densidad"
) +
tema_proyecto +
theme(legend.position = "bottom")
Netflix: distribución de calificaciones.
Las calificaciones se concentran cerca de 6.62 (DE = 1.26). La mayoría de series reciben notas medias-altas; la campana roja es referencia, no prueba formal de normalidad.
Contrastamos \(\log_{10}\)(horas vistas) entre series no disponibles globalmente frente a sí disponibles, con prueba t de Welch (\(H_0\): medias iguales).
t_prueba <- t.test(log_Hours ~ Available.Globally., data = netflix, var.equal = FALSE)
tabla_proyecto(
data.frame(
Estadistico = c("t", "gl", "valor-p", "Media log10 (No)", "Media log10 (Yes)"),
Valor = c(
round(t_prueba$statistic, 4),
round(t_prueba$parameter, 2),
format.pval(t_prueba$p.value, digits = 4),
round(t_prueba$estimate[1], 3),
round(t_prueba$estimate[2], 3)
)
),
caption = "Netflix — Prueba t de Student",
align = c("l", "r")
)
| Estadistico | Valor | |
|---|---|---|
| t | t | -12.5488 |
| df | gl | 7683.76 |
| valor-p | < 2.2e-16 | |
| mean in group No | Media log10 (No) | 6.381 |
| mean in group Yes | Media log10 (Yes) | 6.553 |
ggplot(netflix, aes(x = Available.Globally., y = log_Hours, fill = Available.Globally.)) +
geom_boxplot(alpha = 0.75, width = 0.55, color = color_vino, outlier.color = "#FFD166") +
geom_jitter(aes(color = Available.Globally.), width = 0.15, alpha = 0.25, size = 0.6) +
stat_summary(fun = mean, geom = "point", shape = 18, size = 3.5, color = col_punto) +
scale_fill_manual(values = col_global, guide = "none") +
scale_color_manual(values = col_global, guide = "none") +
labs(
title = titulo_grafica("Prueba t de Student"),
subtitle = "Boxplots lado a lado; rombo negro = media muestral",
x = "Disponible globalmente",
y = expression(log[10](Horas~vistas))
) +
annotate("text", x = 1.5, y = max(netflix$log_Hours) * 0.98, color = color_vino,
label = paste0("valor-p = ", format.pval(t_prueba$p.value, digits = 3))) +
tema_proyecto
Netflix: boxplots lado a lado (log10 horas).
Con valor-p = <2e-16, rechazamos \(H_0\). Las series globales tienen media log-horas 6.553 vs 6.381 en las no globales: la disponibilidad global se asocia con mayor audiencia.
Evaluamos si disponibilidad global y género simplificado son independientes mediante \(\chi^2\) de Pearson.
tab_chi <- table(netflix$Available.Globally., netflix$GenreSimple)
dimnames(tab_chi) <- list(Disponibilidad = c("No", "Yes"), Genero = levels(netflix$GenreSimple))
tabla_chi_df <- data.frame(
Disponibilidad = rownames(tab_chi),
as.data.frame.matrix(tab_chi),
check.names = FALSE
)
names(tabla_chi_df)[-1] <- colnames(tab_chi)
tabla_proyecto(
tabla_chi_df,
caption = "Netflix — Tabla de contingencia",
align = c("l", rep("r", ncol(tab_chi)))
)
| Disponibilidad | Action | Comedy | Drama | Otro | |
|---|---|---|---|---|---|
| No | No | 853 | 3493 | 2618 | 3420 |
| Yes | Yes | 342 | 1442 | 1104 | 1361 |
chi_resultado <- chisq.test(tab_chi)
tabla_proyecto(
data.frame(
`Chi-cuadrado` = round(chi_resultado$statistic, 3),
gl = chi_resultado$parameter,
`valor-p` = format.pval(chi_resultado$p.value, digits = 4),
check.names = FALSE
),
caption = "Netflix — Resultado Chi-cuadrado",
align = c("l", "r", "r", "r")
)
| Chi-cuadrado | gl | valor-p | |
|---|---|---|---|
| X-squared | 1.64 | 3 | 0.6504 |
\(\chi^2\) = 1.64, valor-p = 0.65. No rechazamos independencia: el género simplificado no parece asociarse con la disponibilidad global en este catálogo.
Modelamos calificación ~ \(\log_{10}\)(horas vistas) para ver si más audiencia implica mejor nota promedio.
mod_n <- lm(Rating ~ log_Hours, data = netflix)
coef_n <- as.data.frame(summary(mod_n)$coefficients)
coef_n$Termino <- rownames(coef_n)
rownames(coef_n) <- NULL
tabla_proyecto(
coef_n[, c("Termino", "Estimate", "Std. Error", "Pr(>|t|)")],
digits = 6, caption = "Netflix — Regresión simple",
align = c("l", "r", "r", "r")
)
| Termino | Estimate | Std. Error | Pr(>|t|) |
|---|---|---|---|
| (Intercept) | 6.708467 | 0.090008 | 0.000000 |
| log_Hours | -0.013170 | 0.013903 | 0.343518 |
tabla_proyecto(
data.frame(
Metrica = c("R²", "R² ajustado"),
Valor = c(summary(mod_n)$r.squared, summary(mod_n)$adj.r.squared)
),
digits = 4, caption = "Netflix — Bondad de ajuste",
align = c("l", "r")
)
| Metrica | Valor |
|---|---|
| R² | 1e-04 |
| R² ajustado | 0e+00 |
ggplot(netflix, aes(x = log_Hours, y = Rating, color = GenreSimple)) +
geom_point(alpha = 0.35, size = 1.2) +
geom_smooth(aes(group = 1), method = "lm", se = TRUE, color = col_linea, fill = col_relleno_banda, linewidth = 1.2) +
scale_color_manual(values = col_genero, name = "Género") +
labs(
title = titulo_grafica("Análisis de regresión"),
subtitle = "Modelo lineal: calificación ~ log10(horas vistas)",
x = expression(log[10](Horas~vistas)), y = "Calificación"
) +
tema_proyecto +
theme(legend.position = "bottom")
Netflix: regresión calificación ~ log10(horas).
\(R^2\) = 10^{-4} (0.01% de variación explicada). Las horas en escala log no predicen significativamente la calificación: audiencia y opinión del público miden dimensiones distintas.
Las horas vistas tienen sesgo positivo: pocos títulos concentran cifras enormes y comprimen el resto en gráficos en escala original. \(\log_{10}\) equilibra la visualización sin alterar el orden de los títulos.
tabla_proyecto(
data.frame(
Escala = c("Original", "log10"),
Media = c(mean(netflix$Hours.Viewed), mean(netflix$log_Hours)),
Mediana = c(median(netflix$Hours.Viewed), median(netflix$log_Hours)),
Sesgo = c(sesgo(netflix$Hours.Viewed), sesgo(netflix$log_Hours))
),
digits = c(0, 0, 0, 2),
format.args = list(big.mark = ","),
caption = "Netflix — Comparación de escalas",
align = c("l", "r", "r", "r")
)
| Escala | Media | Mediana | Sesgo |
|---|---|---|---|
| Original | 10,982,615 | 2,900,000 | 11.04 |
| log10 | 6 | 6 | 0.01 |
datos_escalas <- bind_rows(
data.frame(valor = netflix$Hours.Viewed, Escala = "Original"),
data.frame(valor = netflix$log_Hours, Escala = "log10")
)
ggplot(datos_escalas, aes(x = valor, fill = Escala)) +
geom_histogram(bins = 40, alpha = 0.85, color = "white") +
facet_wrap(~Escala, scales = "free_x", ncol = 2) +
scale_fill_manual(values = c("Original" = col_terciario, "log10" = col_secundario), guide = "none") +
scale_x_continuous(labels = scales::label_number(scale_cut = scales::cut_short_scale())) +
labs(
title = titulo_grafica("Comparación de escalas en horas vistas"),
subtitle = "Escala original frente a transformación log10",
x = NULL, y = "Frecuencia"
) +
tema_proyecto
Netflix: escala original vs. log10.
El sesgo cae al pasar a log₁₀; por eso covarianza, prueba t
y regresión de series usan log_Hours.
Basado en el proyecto de web scraping y análisis IMDb
(Final Project - MCAA 2026-2 (2).R). Fuente:
Fuentes/movies.json.
ruta_imdb <- "Fuentes/movies.json"
peliculas <- as.data.frame(fromJSON(ruta_imdb))
peliculas <- peliculas %>%
mutate(
`Release Date` = as.Date(`Release Date`, format = "%b %d %Y"),
Year = as.numeric(format(`Release Date`, "%Y")),
Rating = `IMDB Rating`,
Decade = floor(Year / 10) * 10,
Worldwide.Gross = as.numeric(gsub("[^0-9.]", "", as.character(`Worldwide Gross`))),
Major.Genre = as.factor(`Major Genre`)
) %>%
filter(!is.na(Rating), !is.na(Year))
n_peliculas <- nrow(peliculas)
top15 <- peliculas %>% arrange(desc(Rating)) %>% head(15)
peliculas_genero <- peliculas %>%
filter(!is.na(Major.Genre)) %>%
add_count(Major.Genre, name = "n_genero") %>%
filter(n_genero >= 50) %>%
mutate(Major.Genre = droplevels(Major.Genre))
resumen_genero <- peliculas_genero %>%
group_by(Major.Genre) %>%
summarise(
Peliculas = n(),
Promedio = mean(Rating, na.rm = TRUE),
Mediana = median(Rating, na.rm = TRUE),
.groups = "drop"
) %>%
arrange(desc(Promedio))
generos_facet <- levels(peliculas_genero$Major.Genre)
decade_genero <- peliculas %>%
filter(Major.Genre %in% generos_facet, !is.na(Decade), Decade >= 1920) %>%
group_by(Major.Genre, Decade) %>%
summarise(
Promedio = mean(Rating, na.rm = TRUE),
Peliculas = n(),
.groups = "drop"
) %>%
filter(Peliculas >= 5)
Hay 2,988 películas con calificación y año válidos. Calificación media: 6.28 / 10.
Identificamos las 15 películas con mayor calificación IMDb del conjunto. Este gráfico de barras resume el extremo superior de la distribución y facilita comparar títulos destacados.
ggplot(top15, aes(x = reorder(Title, Rating), y = Rating, fill = Rating)) +
geom_col(show.legend = FALSE) +
scale_fill_gradient(low = "#C9A0A4", high = col_primario) +
coord_flip() +
labs(
title = titulo_grafica("Top 15 películas mejor calificadas", "IMDb"),
subtitle = "Barras ordenadas por calificación IMDb",
x = NULL, y = "Calificación IMDb"
) +
tema_proyecto
Películas (IMDb): Top 15 por calificación.
El tope del ranking supera 8.8 puntos; las mejores películas concentran calificaciones muy altas, lo que refleja la selección positiva típica de catálogos curados o muy valorados por usuarios.
El histograma muestra cómo se reparten las calificaciones IMDb en todo el catálogo. Superponemos la curva normal teórica (media y desviación muestrales) para comparar la forma empírica con el modelo gaussiano, igual que en las series de Netflix.
mu_p <- mean(peliculas$Rating)
sd_p <- sd(peliculas$Rating)
tabla_proyecto(
data.frame(
Estadistico = c("Media", "Desv. est.", "Mínimo", "Máximo"),
Valor = c(mu_p, sd_p, min(peliculas$Rating), max(peliculas$Rating))
),
digits = 3,
caption = "IMDb — Resumen de calificaciones",
align = c("l", "r")
)
| Estadistico | Valor |
|---|---|
| Media | 6.283 |
| Desv. est. | 1.252 |
| Mínimo | 1.400 |
| Máximo | 9.200 |
x_seq_p <- seq(min(peliculas$Rating), max(peliculas$Rating), length.out = 200)
curva_norm_p <- data.frame(Rating = x_seq_p, densidad = dnorm(x_seq_p, mu_p, sd_p))
ggplot(peliculas, aes(x = Rating)) +
geom_histogram(aes(y = after_stat(density)), binwidth = 0.2, fill = col_secundario, color = "white", alpha = 0.85) +
geom_line(data = curva_norm_p, aes(x = Rating, y = densidad), inherit.aes = FALSE, color = col_linea, linewidth = 1.4) +
labs(
title = titulo_grafica("Distribución de probabilidades", "IMDb"),
subtitle = "Histograma con curva normal teórica superpuesta",
x = "Calificación IMDb", y = "Densidad"
) +
tema_proyecto
Películas (IMDb): histograma de calificaciones con curva normal.
Las calificaciones se concentran cerca de 6.28 (DE = 1.25). La mayoría de películas supera 6.0 puntos; la curva normal es referencia visual, no prueba formal de normalidad.
¿La calificación IMDb depende del género principal? Agrupamos los géneros con al menos 50 películas y comparamos sus distribuciones con boxplots lado a lado. Además aplicamos ANOVA de un factor (\(H_0\): medias iguales entre géneros).
tabla_proyecto(
resumen_genero,
digits = 3,
caption = "IMDb — Calificación promedio por género (mínimo 50 películas)",
align = c("l", "r", "r", "r")
)
| Major.Genre | Peliculas | Promedio | Mediana |
|---|---|---|---|
| Drama | 738 | 6.773 | 6.90 |
| Musical | 50 | 6.448 | 6.85 |
| Thriller/Suspense | 233 | 6.361 | 6.40 |
| Adventure | 251 | 6.345 | 6.40 |
| Action | 392 | 6.115 | 6.20 |
| Romantic Comedy | 130 | 5.873 | 5.85 |
| Comedy | 635 | 5.854 | 6.00 |
| Horror | 209 | 5.676 | 5.60 |
anova_genero_p <- aov(Rating ~ Major.Genre, data = peliculas_genero)
anova_tabla_p <- as.data.frame(summary(anova_genero_p)[[1]])
anova_tabla_p$Fuente <- rownames(anova_tabla_p)
rownames(anova_tabla_p) <- NULL
tabla_proyecto(
anova_tabla_p[, c("Fuente", "Df", "Sum Sq", "Mean Sq", "F value", "Pr(>F)")],
digits = 4,
caption = "IMDb — ANOVA: calificación por género",
align = c("l", "r", "r", "r", "r", "r"),
na = ""
)
| Fuente | Df | Sum Sq | Mean Sq | F value | Pr(>F) |
|---|---|---|---|---|---|
| Major.Genre | 7 | 403.1377 | 57.5911 | 40.9151 | 0 |
| Residuals | 2630 | 3701.9285 | 1.4076 | NA | NA |
genero_orden <- resumen_genero %>% arrange(Promedio) %>% pull(Major.Genre)
ggplot(peliculas_genero, aes(x = reorder(Major.Genre, Rating, FUN = median), y = Rating, fill = Major.Genre)) +
geom_boxplot(alpha = 0.75, width = 0.65, color = col_primario, outlier.color = col_outlier) +
geom_jitter(width = 0.12, alpha = 0.15, size = 0.5, color = col_punto) +
stat_summary(fun = mean, geom = "point", shape = 18, size = 3, color = col_punto) +
scale_fill_manual(values = paleta_genero_imdb, guide = "none") +
scale_x_discrete(limits = genero_orden) +
labs(
title = titulo_grafica("Calificación por género cinematográfico", "IMDb"),
subtitle = "Géneros con ≥ 50 películas; rombo negro = media",
x = "Género principal", y = "Calificación IMDb"
) +
tema_proyecto +
theme(axis.text.x = element_text(angle = 30, hjust = 1))
Películas (IMDb): calificación por género principal.
El género con mayor promedio es Drama (6.77); el menor, Horror (5.68). ANOVA: valor-p = <2e-16 — rechazamos \(H_0\). El género sí se asocia con diferencias en calificación, aunque el gráfico muestra matices (p. ej. comedia vs. terror).
Comparamos cómo cambia la calificación promedio por década de
estreno dentro de cada género principal (con
al menos 5 películas por década). El panel de gráficas con
facet_wrap permite ver si la tendencia temporal es similar
en drama, comedia, acción y otros géneros.
ggplot(decade_genero, aes(x = Decade, y = Promedio)) +
geom_line(color = col_primario, linewidth = 1) +
geom_point(color = col_secundario, size = 2) +
facet_wrap(~Major.Genre, scales = "free_y", ncol = 3) +
labs(
title = titulo_grafica("Evolución de la calificación por década", "IMDb"),
subtitle = "Un panel por género principal (mínimo 5 películas por década)",
x = "Década de estreno", y = "Calificación promedio"
) +
tema_proyecto +
theme(strip.text = element_text(face = "bold", color = col_primario))
Películas (IMDb): evolución por década según género.
No todas las décadas ni todos los géneros evolucionan igual: algunos paneles muestran ligero ascenso o descenso según la época, mientras otros se mantienen estables. Esto indica que el año de estreno interactúa con el género; conviene interpretar la tendencia global junto con cada categoría, no solo el promedio de todo el catálogo.
¿Las películas más recientes reciben mejores o peores calificaciones? Ajustamos una regresión lineal simple (año → calificación), equivalente al análisis del script original.
mod_p <- lm(Rating ~ Year, data = peliculas)
coef_p <- as.data.frame(summary(mod_p)$coefficients)
coef_p$Termino <- rownames(coef_p)
rownames(coef_p) <- NULL
tabla_proyecto(
coef_p[, c("Termino", "Estimate", "Std. Error", "Pr(>|t|)")],
digits = 6, caption = "IMDb — Regresión calificación ~ año",
align = c("l", "r", "r", "r")
)
| Termino | Estimate | Std. Error | Pr(>|t|) |
|---|---|---|---|
| (Intercept) | 27.642287 | 3.828858 | 0 |
| Year | -0.010689 | 0.001916 | 0 |
cor_ano <- cor(peliculas$Year, peliculas$Rating, use = "complete.obs")
ggplot(peliculas, aes(x = Year, y = Rating)) +
geom_point(color = col_terciario, alpha = 0.35, size = 1) +
geom_smooth(method = "lm", se = TRUE, color = col_linea, fill = col_relleno_banda, linewidth = 1.1) +
labs(
title = titulo_grafica("Análisis de regresión", "IMDb"),
subtitle = "Modelo lineal: calificación ~ año de estreno",
x = "Año de estreno", y = "Calificación IMDb"
) +
tema_proyecto
Películas (IMDb): año de estreno vs. calificación con recta de regresión.
Correlación año–rating: -0.102; \(R^2\) = 0.0103. La pendiente es significativa pero el modelo explica poca variación: el año de estreno por sí solo no determina la calificación IMDb en este conjunto amplio.
La nube de palabras resume las palabras más frecuentes en los títulos de las películas, tras eliminar muletillas y stop words (artículos, preposiciones y términos vacíos en inglés y español) para resaltar sustantivos y nombres relevantes.
if (requireNamespace("wordcloud", quietly = TRUE) &&
requireNamespace("tm", quietly = TRUE)) {
library(wordcloud)
library(tm)
palabras_vacias <- unique(c(
stopwords("english"),
stopwords("spanish"),
"movie", "film", "story",
"part", "chapter", "vs", "ii", "iii", "iv", "v", "vi",
"the", "and", "of", "in", "to", "a", "an", "for", "on", "at", "by",
"de", "la", "el", "los", "las", "y", "en", "un", "una", "del", "al"
))
corpus_titulos <- Corpus(VectorSource(peliculas$Title))
corpus_titulos <- tm_map(corpus_titulos, content_transformer(tolower))
corpus_titulos <- tm_map(corpus_titulos, removePunctuation)
corpus_titulos <- tm_map(corpus_titulos, removeNumbers)
corpus_titulos <- tm_map(corpus_titulos, removeWords, palabras_vacias)
corpus_titulos <- tm_map(corpus_titulos, stripWhitespace)
tdm <- TermDocumentMatrix(corpus_titulos)
m <- as.matrix(tdm)
freq <- sort(rowSums(m), decreasing = TRUE)
freq <- freq[nchar(names(freq)) > 2]
par(bg = "white", fg = col_texto_eje, mar = rep(0.5, 4))
wordcloud(
words = names(freq),
freq = freq,
random.order = FALSE,
colors = c(col_primario, col_secundario, col_terciario, col_linea, "#9B5DE5", "#F77F00"),
max.words = 80,
scale = c(3, 0.5)
)
} else {
plot.new()
text(0.5, 0.5, "Instale los paquetes wordcloud y tm para ver esta figura")
}
Películas (IMDb): nube de palabras sin muletillas.
Tras quitar muletillas, emergen términos con significado narrativo o temático (nombres, lugares, conceptos) en lugar de artículos repetidos. La nube refleja la diversidad léxica del catálogo y no debe leerse como ranking de películas, sino como exploración del lenguaje usado en los títulos.
facet_wrap.Los dos catálogos difieren en tamaño y en tipos de variables disponibles. La tabla resume filas, columnas y cuántas variables son numéricas, categóricas, de fecha o lógicas.
| Catalogo | Filas | Columnas | Numéricas | Categóricas | Fechas | Lógicas |
|---|---|---|---|---|---|---|
| Netflix (archivo original) | 18332 | 9 | 0 | 9 | 0 | 0 |
| Netflix (datos analizados) | 14633 | 11 | 4 | 7 | 0 | 0 |
| IMDb (archivo original) | 3201 | 16 | 8 | 8 | 0 | 0 |
| IMDb (datos analizados) | 2988 | 21 | 12 | 8 | 1 | 0 |