Este projeto utiliza uma base de dados do Internet Movie Database (IMDb) contendo informações sobre filmes, séries, atores, diretores e avaliações da comunidade. O dataset foi obtido no Kaggle (https://www.kaggle.com/datasets/ashirwadsangwan/imdb-dataset) e totaliza mais de 5GB de dados.
A base de dados contém 12.083.771 títulos únicos no total, dos quais 1.603.100 possuem avaliações registradas pela comunidade do IMDb.
Diante dessa vasta quantidade de informações sobre a indústria cinematográfica e televisiva, este projeto se propõe a realizar uma análise exploratória profunda desses dados, buscando extrair insights relevantes sobre padrões de produção, preferências do público e fatores que influenciam o sucesso de títulos audiovisuais.
O dataset original do IMDb disponibilizado no Kaggle contém 5 tabelas:
Para este projeto, serão utilizadas apenas as 3 primeiras tabelas (title.basics, title.ratings e title.akas). As tabelas de pessoas (name.basics e title.principals) foram excluídas da análise pelos seguintes motivos:
Explosão de registros: Cada título possui múltiplos profissionais associados (atores, diretores, roteiristas, produtores). Ao realizar um JOIN dessas tabelas com a tabela principal, um único filme com 10 pessoas no elenco principal geraria 10 linhas na tabela final, multiplicando artificialmente o volume de dados.
Dificuldade em agregações: Com registros duplicados por título, cálculos como média de ratings, contagem de produções por ano ou distribuição de gêneros ficariam distorcidos, exigindo tratamentos adicionais como agrupamentos e distinct.
Complexidade desnecessária: O objetivo principal deste estudo é analisar características dos títulos (gênero, duração, avaliações, distribuição geográfica). Análises sobre o impacto de profissionais específicos, embora interessantes, fogem do escopo definido e demandariam uma estrutura de dados diferente.
Dessa forma, a tabela final consolidada terá uma linha por título, facilitando a geração de estimativas, visualizações e conclusões de forma direta.
Este projeto visa realizar uma análise exploratória profunda dos dados cinematográficos do IMDb. Devido ao grande volume de dados (mais de 12 milhões de títulos), o estudo será limitado aos conteúdos produzidos no intervalo de 2020 a 2025, permitindo um foco em produções recentes e tendências contemporâneas.
Durante o processo de preparação dos dados, as 3 tabelas selecionadas serão unificadas em uma única estrutura integrada, onde cada linha representa um título único. Essa abordagem facilita a análise e permite gerar estimativas e visualizações de forma direta, sem a complexidade adicional que surgiria ao incluir dados de múltiplos profissionais por título.
Com essa estratégia de filtragem e consolidação, os objetivos específicos da análise são:
Análise Temporal e de Tendências:
Análise de Sucesso e Avaliações:
Análise de Mercado e Distribuição:
# pacotes necessários
library(dplyr)
library(readr)
library(ggplot2)
library(tidyr)
library(stringr)
library(scales)
As 3 tabelas utilizadas neste projeto possuem a seguinte estrutura:
Contém informações básicas sobre títulos (filmes, séries, episódios):
Contém as avaliações e votos do IMDb para os títulos:
Contém títulos alternativos e traduções:
Observações:
tconst é a chave primária que permite
relacionar as 3 tabelas entre siNesta etapa, realizaremos a importação das 3 tabelas do IMDb para o
ambiente R. O código verifica se os arquivos já foram processados
anteriormente (formato .rds) para otimizar o tempo de
execução.
Definição dos caminhos dos arquivos originais (.tsv) e
processados (.rds):
| Tipo | Arquivo | Caminho |
|---|---|---|
| Original | title.basics.tsv | C:/Users/Rodrigo/Downloads/ |
| Original | title.ratings.tsv | C:/Users/Rodrigo/Downloads/ |
| Original | title.akas.tsv | C:/Users/Rodrigo/Downloads/ |
| Processado | tabela_final.rds | C:/Users/Rodrigo/Downloads/ |
Estratégia de cache: Se a tabela final
(tabela_final.rds) já existir, ela é carregada diretamente,
pulando todo o processamento.
Tabela principal contendo informações básicas sobre os títulos.
Processamento:
.tsv (ou .rds se já
existir)startYear para numéricostartYear >= 2020 e
<= 2025.rdsif (file.exists(path_final_rds)) {
cat(">>> Tabela final já existe. Pulando processamento de title.basics...\n")
} else {
if (file.exists(path_basics_rds)) {
cat("Carregando title.basics.filtrado.rds...\n")
title_basics_filtrado <- readRDS(path_basics_rds)
cat("Registros:", nrow(title_basics_filtrado), "\n")
} else {
cat("Carregando title.basics.tsv (isso pode demorar)...\n")
title_basics <- read.delim(
path_title_basics,
sep = "\t",
na.strings = "\\N",
quote = "",
stringsAsFactors = FALSE
)
cat("Total de registros:", nrow(title_basics), "\n")
title_basics$startYear <- as.numeric(title_basics$startYear)
title_basics_filtrado <- title_basics %>%
filter(!is.na(startYear) & startYear >= 2020 & startYear <= 2025)
cat("Após filtro (2020-2025):", nrow(title_basics_filtrado), "registros\n")
rm(title_basics)
gc()
saveRDS(title_basics_filtrado, file = path_basics_rds, compress = "gzip")
cat("Salvo em:", path_basics_rds, "\n")
}
}
## Carregando title.basics.tsv (isso pode demorar)...
## Total de registros: 12101466
## Após filtro (2020-2025): 2712516 registros
## Salvo em: C:/Users/Rodrigo/Downloads/title.basics.filtrado.rds
Tabela contendo as avaliações (notas e votos) dos títulos.
Processamento:
.tsv (ou .rds se já
existir)title_basics_filtrado.rdsColunas extraídas: averageRating,
numVotes
if (file.exists(path_final_rds)) {
cat(">>> Tabela final já existe. Pulando processamento de title.ratings...\n")
} else {
if (file.exists(path_ratings_rds)) {
cat("Carregando title.ratings.filtrado.rds...\n")
title_ratings_filtrado <- readRDS(path_ratings_rds)
cat("Registros:", nrow(title_ratings_filtrado), "\n")
} else {
cat("Carregando title.ratings.tsv...\n")
title_ratings <- read.delim(
path_title_ratings,
sep = "\t",
na.strings = "\\N",
quote = "",
stringsAsFactors = FALSE
)
cat("Total de registros:", nrow(title_ratings), "\n")
title_ratings_filtrado <- title_ratings %>%
filter(tconst %in% title_basics_filtrado$tconst)
cat("Após filtro (títulos de 2020-2025):", nrow(title_ratings_filtrado), "registros\n")
rm(title_ratings)
gc()
saveRDS(title_ratings_filtrado, file = path_ratings_rds, compress = "gzip")
cat("Salvo em:", path_ratings_rds, "\n")
}
}
## Carregando title.ratings.tsv...
## Total de registros: 1605930
## Após filtro (títulos de 2020-2025): 361262 registros
## Salvo em: C:/Users/Rodrigo/Downloads/title.ratings.filtrado.rds
Tabela contendo títulos alternativos e traduções em diferentes regiões/idiomas.
Processamento:
.tsv (ou .rds se já
existir)title_basics_filtrado.rdsColuna extraída: regions (todas as
regiões concatenadas, ex: "US,BR,GB,FR")
if (file.exists(path_final_rds)) {
cat(">>> Tabela final já existe. Pulando processamento de title.akas...\n")
} else {
if (file.exists(path_akas_rds)) {
cat("Carregando title.akas.filtrado.rds...\n")
title_akas_filtrado <- readRDS(path_akas_rds)
cat("Registros:", nrow(title_akas_filtrado), "\n")
} else {
cat("Carregando title.akas.tsv (isso pode demorar)...\n")
title_akas <- read.delim(
path_title_akas,
sep = "\t",
na.strings = "\\N",
quote = "",
stringsAsFactors = FALSE
)
cat("Total de registros:", nrow(title_akas), "\n")
title_akas_filtrado <- title_akas %>%
filter(titleId %in% title_basics_filtrado$tconst)
cat("Após filtro (títulos de 2020-2025):", nrow(title_akas_filtrado), "registros\n")
rm(title_akas)
gc()
saveRDS(title_akas_filtrado, file = path_akas_rds, compress = "gzip")
cat("Salvo em:", path_akas_rds, "\n")
}
}
## Carregando title.akas.tsv (isso pode demorar)...
## Total de registros: 54158849
## Após filtro (títulos de 2020-2025): 10740154 registros
## Salvo em: C:/Users/Rodrigo/Downloads/title.akas.filtrado.rds
Consolidação das 3 tabelas em uma estrutura única, onde cada linha representa um título.
Etapas:
averageRating e numVotes de
title.ratingsregions de title.akaslanguages de title.akasstartYear para releaseYearendYear (desnecessária).rdsif (file.exists(path_final_rds)) {
cat(">>> Carregando tabela final existente...\n")
title_basics_filtrado <- readRDS(path_final_rds)
cat("Tabela carregada com sucesso!\n")
} else {
cat(">>> Consolidando tabelas...\n\n")
# Adicionar ratings
cat("Adicionando ratings à tabela principal...\n")
title_basics_filtrado <- title_basics_filtrado %>%
left_join(title_ratings_filtrado %>% select(tconst, averageRating, numVotes), by = "tconst")
n_com_rating <- sum(!is.na(title_basics_filtrado$averageRating))
cat("Títulos com rating:", n_com_rating, "(", round(n_com_rating/nrow(title_basics_filtrado)*100, 1), "%)\n")
rm(title_ratings_filtrado)
gc()
# Agregar e adicionar regions
cat("\nAgregando regiões por título...\n")
regions_por_titulo <- title_akas_filtrado %>%
filter(!is.na(region) & region != "\\N" & region != "") %>%
group_by(titleId) %>%
summarise(regions = paste(unique(region), collapse = ","), .groups = "drop")
cat("Títulos com informação de região:", nrow(regions_por_titulo), "\n")
title_basics_filtrado <- title_basics_filtrado %>%
left_join(regions_por_titulo, by = c("tconst" = "titleId"))
rm(regions_por_titulo)
gc()
# Agregar e adicionar languages
cat("\nAgregando idiomas por título...\n")
languages_por_titulo <- title_akas_filtrado %>%
filter(!is.na(language) & language != "\\N" & language != "") %>%
group_by(titleId) %>%
summarise(languages = paste(unique(language), collapse = ","), .groups = "drop")
cat("Títulos com informação de idioma:", nrow(languages_por_titulo), "\n")
title_basics_filtrado <- title_basics_filtrado %>%
left_join(languages_por_titulo, by = c("tconst" = "titleId"))
rm(languages_por_titulo, title_akas_filtrado)
gc()
# Renomear startYear para releaseYear
title_basics_filtrado <- title_basics_filtrado %>%
rename(releaseYear = startYear)
cat("Coluna 'startYear' renomeada para 'releaseYear'.\n")
# Remover colunas desnecessárias
title_basics_filtrado <- title_basics_filtrado %>%
select(-endYear)
cat("Coluna 'endYear' removida.\n")
# Salvar tabela final
saveRDS(title_basics_filtrado, file = path_final_rds, compress = "gzip")
tamanho_mb <- file.size(path_final_rds) / (1024^2)
cat("\n>>> Tabela final salva em:", path_final_rds)
cat("\n>>> Tamanho:", round(tamanho_mb, 2), "MB\n")
}
## >>> Consolidando tabelas...
##
## Adicionando ratings à tabela principal...
## Títulos com rating: 361262 ( 13.3 %)
##
## Agregando regiões por título...
## Títulos com informação de região: 1656711
##
## Agregando idiomas por título...
## Títulos com informação de idioma: 1042457
## Coluna 'startYear' renomeada para 'releaseYear'.
## Coluna 'endYear' removida.
##
## >>> Tabela final salva em: C:/Users/Rodrigo/Downloads/tabela_final.rds
## >>> Tamanho: 78.38 MB
Amostra da tabela final consolidada:
cat("========== ESTRUTURA DA TABELA FINAL ==========\n")
## ========== ESTRUTURA DA TABELA FINAL ==========
cat("Dimensões:", nrow(title_basics_filtrado), "linhas x", ncol(title_basics_filtrado), "colunas\n")
## Dimensões: 2712516 linhas x 12 colunas
cat("Colunas:", paste(names(title_basics_filtrado), collapse = ", "), "\n\n")
## Colunas: tconst, titleType, primaryTitle, originalTitle, isAdult, releaseYear, runtimeMinutes, genres, averageRating, numVotes, regions, languages
n_com_rating <- sum(!is.na(title_basics_filtrado$averageRating))
n_com_regiao <- sum(!is.na(title_basics_filtrado$regions))
n_com_idioma <- sum(!is.na(title_basics_filtrado$languages))
cat("Títulos com rating:", n_com_rating, "(", round(n_com_rating/nrow(title_basics_filtrado)*100, 1), "%)\n")
## Títulos com rating: 361262 ( 13.3 %)
cat("Títulos com região:", n_com_regiao, "(", round(n_com_regiao/nrow(title_basics_filtrado)*100, 1), "%)\n")
## Títulos com região: 1656711 ( 61.1 %)
cat("Títulos com idioma:", n_com_idioma, "(", round(n_com_idioma/nrow(title_basics_filtrado)*100, 1), "%)\n\n")
## Títulos com idioma: 1042457 ( 38.4 %)
# Amostra da tabela
head(title_basics_filtrado, 15)
Nesta seção, realizamos análises exploratórias para investigar padrões e tendências nos dados do IMDb. As análises estão organizadas em abas temáticas.
Panorama completo da composição da tabela final, organizado em sub-abas por tipo de variável.
Total de registros: 2.712.516 títulos
Distribuição das variáveis categóricas: tipo de título, conteúdo adulto e ano de lançamento.
cat("📌 titleType (Tipo de Título)\n")
## 📌 titleType (Tipo de Título)
title_basics_filtrado %>%
count(titleType, sort = TRUE) %>%
mutate(percentual = paste0(round(n / total_registros * 100, 2), "%"))
cat("\n📌 isAdult (Conteúdo Adulto)\n")
##
## 📌 isAdult (Conteúdo Adulto)
title_basics_filtrado %>%
count(isAdult, sort = TRUE) %>%
mutate(
isAdult = ifelse(isAdult == 0, "Não (0)", "Sim (1)"),
percentual = paste0(round(n / total_registros * 100, 2), "%")
)
cat("\n📌 releaseYear (Ano de Lançamento)\n")
##
## 📌 releaseYear (Ano de Lançamento)
title_basics_filtrado %>%
count(releaseYear, sort = FALSE) %>%
mutate(percentual = paste0(round(n / total_registros * 100, 2), "%"))
Estatísticas das variáveis numéricas: nota média, número de votos e duração.
# Calcular estatísticas
n_com_rating <- sum(!is.na(title_basics_filtrado$averageRating))
n_com_votos <- sum(!is.na(title_basics_filtrado$numVotes))
n_com_duracao <- sum(!is.na(title_basics_filtrado$runtimeMinutes))
cat("📌 averageRating (Nota Média)\n")
## 📌 averageRating (Nota Média)
cat(" Preenchidos:", format(n_com_rating, big.mark = "."),
"(", round(n_com_rating/total_registros*100, 1), "%)\n")
## Preenchidos: 361.262 ( 13.3 %)
summary(title_basics_filtrado$averageRating[!is.na(title_basics_filtrado$averageRating)])
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 1.00 6.40 7.30 7.16 8.10 10.00
cat("\n📌 numVotes (Número de Votos)\n")
##
## 📌 numVotes (Número de Votos)
cat(" Preenchidos:", format(n_com_votos, big.mark = "."),
"(", round(n_com_votos/total_registros*100, 1), "%)\n")
## Preenchidos: 361.262 ( 13.3 %)
summary(title_basics_filtrado$numVotes[!is.na(title_basics_filtrado$numVotes)])
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 5 10 24 692 95 990248
cat("\n📌 runtimeMinutes (Duração em Minutos)\n")
##
## 📌 runtimeMinutes (Duração em Minutos)
cat(" Preenchidos:", format(n_com_duracao, big.mark = "."),
"(", round(n_com_duracao/total_registros*100, 1), "%)\n")
## Preenchidos: 820.905 ( 30.3 %)
summary(title_basics_filtrado$runtimeMinutes[!is.na(title_basics_filtrado$runtimeMinutes)])
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 1.00 15.00 30.00 44.94 60.00 43200.00
Top 10 valores das variáveis compostas (múltiplos valores separados por vírgula): gêneros, regiões e idiomas.
cat("📌 genres - Top 10 Gêneros\n")
## 📌 genres - Top 10 Gêneros
title_basics_filtrado %>%
filter(!is.na(genres) & genres != "") %>%
separate_rows(genres, sep = ",") %>%
mutate(genres = trimws(genres)) %>%
count(genres, sort = TRUE) %>%
head(10)
cat("\n📌 regions - Top 10 Regiões\n")
##
## 📌 regions - Top 10 Regiões
title_basics_filtrado %>%
filter(!is.na(regions)) %>%
separate_rows(regions, sep = ",") %>%
mutate(regions = trimws(regions)) %>%
count(regions, sort = TRUE) %>%
head(10)
cat("\n📌 languages - Top 10 Idiomas\n")
##
## 📌 languages - Top 10 Idiomas
title_basics_filtrado %>%
filter(!is.na(languages)) %>%
separate_rows(languages, sep = ",") %>%
mutate(languages = trimws(languages)) %>%
count(languages, sort = TRUE) %>%
head(10)
Objetivo: Investigar a relação entre a popularidade de um título (medida pelo número de votos) e sua qualidade percebida (nota média). A pergunta central é: títulos mais populares são necessariamente melhores avaliados?
Metodologia: Utilizamos um gráfico de dispersão (scatter plot) com escala logarítmica no eixo X para melhor visualização, já que o número de votos possui grande variação. Adicionamos uma linha de tendência (regressão) para identificar o padrão geral.
# Filtrar títulos com rating e votos válidos
dados_pop_qual <- title_basics_filtrado %>%
filter(!is.na(averageRating) & !is.na(numVotes) & numVotes > 0)
# Calcular correlação
correlacao <- cor(dados_pop_qual$numVotes, dados_pop_qual$averageRating, use = "complete.obs")
# Gráfico de dispersão: Popularidade vs Qualidade
ggplot(dados_pop_qual, aes(x = numVotes, y = averageRating)) +
geom_point(alpha = 0.3, color = "#2E86AB", size = 1) +
geom_smooth(method = "lm", color = "#E94F37", linewidth = 1.2, se = TRUE) +
scale_x_log10(labels = label_number(scale_cut = cut_short_scale())) +
labs(
title = "Popularidade vs Qualidade: Títulos Populares São Melhores?",
subtitle = paste0("Correlação de Pearson: ", round(correlacao, 3)),
x = "Número de Votos (escala log)",
y = "Nota Média (IMDb)",
caption = "Fonte: IMDb | Títulos de 2020-2025"
) +
theme_minimal(base_size = 12) +
theme(
plot.title = element_text(face = "bold", size = 14),
plot.subtitle = element_text(color = "gray40"),
panel.grid.minor = element_blank()
)
Interpretação: A correlação de Pearson obtida foi de -0.006, um valor extremamente próximo de zero. Isso indica que não existe relação linear entre popularidade (número de votos) e qualidade (nota média) nos títulos do IMDb.
Em termos práticos, isso significa que:
O sinal negativo (-0.006) é estatisticamente irrelevante dado sua proximidade com zero, não indicando uma tendência real de queda. A linha de regressão praticamente horizontal no gráfico confirma essa ausência de correlação.
Objetivo: Identificar quais gêneros cinematográficos estão em crescimento ou declínio ao longo dos anos recentes (2020-2025). Esta análise revela tendências na produção audiovisual e mudanças nas preferências do mercado.
Metodologia: Separamos os gêneros (que estão concatenados) em linhas individuais, contamos a produção por gênero e ano, e visualizamos a evolução temporal dos 8 gêneros mais populares.
# Separar gêneros em linhas individuais
generos_por_ano <- title_basics_filtrado %>%
filter(!is.na(genres) & genres != "") %>%
separate_rows(genres, sep = ",") %>%
mutate(genres = trimws(genres)) %>%
filter(genres != "")
# Identificar os 15 gêneros mais comuns no total
top_generos <- generos_por_ano %>%
count(genres, sort = TRUE) %>%
head(15) %>%
pull(genres)
# Contar produção por gênero e ano (apenas top gêneros)
evolucao_generos <- generos_por_ano %>%
filter(genres %in% top_generos) %>%
count(releaseYear, genres) %>%
mutate(genres = factor(genres, levels = top_generos))
# Gráfico de linhas: Evolução dos gêneros
ggplot(evolucao_generos, aes(x = releaseYear, y = n, color = genres, group = genres)) +
geom_line(linewidth = 1.2) +
geom_point(size = 2.5) +
scale_color_manual(values = c("#E41A1C", "#377EB8", "#4DAF4A", "#984EA3", "#FF7F00",
"#FFFF33", "#A65628", "#F781BF", "#999999", "#66C2A5",
"#FC8D62", "#8DA0CB", "#E78AC3", "#A6D854", "#FFD92F")) +
scale_x_continuous(limits = c(2020, 2025), breaks = 2020:2025) +
scale_y_continuous(labels = label_number(scale_cut = cut_short_scale())) +
labs(
title = "Evolução da Produção por Gênero (2020-2025)",
subtitle = "Top 15 gêneros mais produzidos",
x = "Ano de Lançamento",
y = "Quantidade de Títulos",
color = "Gênero",
caption = "Fonte: IMDb | Um título pode ter múltiplos gêneros"
) +
theme_minimal(base_size = 12) +
theme(
plot.title = element_text(face = "bold", size = 14),
plot.subtitle = element_text(color = "gray40"),
legend.position = "right",
panel.grid.minor = element_blank()
)
Interpretação: Gêneros com linhas ascendentes indicam crescimento na produção, enquanto linhas descendentes sugerem declínio. Observe que um título pode pertencer a múltiplos gêneros, portanto os números representam participações e não títulos únicos.
Objetivo: Comparar as avaliações médias entre filmes (movies) e séries de TV (tvSeries). Esta análise busca responder: qual formato tende a ser melhor avaliado pelo público?
Metodologia: Filtramos apenas os tipos “movie” e “tvSeries”, calculamos estatísticas descritivas e visualizamos a distribuição das notas através de boxplots e histogramas sobrepostos.
# Filtrar apenas movies e tvSeries com rating válido
filmes_series <- title_basics_filtrado %>%
filter(titleType %in% c("movie", "tvSeries") & !is.na(averageRating)) %>%
mutate(titleType = factor(titleType,
levels = c("movie", "tvSeries"),
labels = c("Filmes", "Séries de TV")))
# Estatísticas por tipo
stats_rating <- filmes_series %>%
group_by(titleType) %>%
summarise(
n = n(),
media = mean(averageRating, na.rm = TRUE),
mediana = median(averageRating, na.rm = TRUE),
desvio = sd(averageRating, na.rm = TRUE),
.groups = "drop"
)
cat("========== ESTATÍSTICAS DE RATING ==========\n")
## ========== ESTATÍSTICAS DE RATING ==========
print(stats_rating)
## # A tibble: 2 × 5
## titleType n media mediana desvio
## <fct> <int> <dbl> <dbl> <dbl>
## 1 Filmes 60374 6.35 6.5 1.60
## 2 Séries de TV 25131 6.88 7.1 1.41
# Gráfico: Distribuição de ratings (histograma + boxplot)
ggplot(filmes_series, aes(x = averageRating, fill = titleType)) +
geom_histogram(bins = 20, alpha = 0.6, position = "identity", color = "white") +
geom_boxplot(aes(y = -500), width = 300, alpha = 0.8, outlier.shape = NA) +
scale_fill_manual(values = c("Filmes" = "#3498DB", "Séries de TV" = "#E74C3C")) +
labs(
title = "Distribuição de Notas: Filmes vs Séries de TV",
subtitle = paste0("Filmes (n=", format(stats_rating$n[1], big.mark="."),
") | Séries (n=", format(stats_rating$n[2], big.mark="."), ")"),
x = "Nota Média (IMDb)",
y = "Frequência",
fill = "Tipo",
caption = "Fonte: IMDb | Títulos de 2020-2025"
) +
theme_minimal(base_size = 12) +
theme(
plot.title = element_text(face = "bold", size = 14),
plot.subtitle = element_text(color = "gray40"),
legend.position = "top",
panel.grid.minor = element_blank()
)
Interpretação: A comparação revela diferenças na forma como o público avalia filmes versus séries. Diferenças nas médias e medianas indicam preferências sistemáticas, enquanto a dispersão (desvio padrão) mostra a consistência das avaliações em cada formato.
Objetivo: Comparar a duração (em minutos) entre filmes e séries de TV. Para séries, a duração geralmente representa a duração média de um episódio.
Metodologia: Filtramos títulos com duração válida e removemos outliers extremos (títulos com mais de 300 minutos) para uma visualização mais clara. Utilizamos boxplots para comparar as distribuições.
# Filtrar movies e tvSeries com duração válida (remover outliers extremos)
filmes_series_duracao <- title_basics_filtrado %>%
filter(titleType %in% c("movie", "tvSeries") &
!is.na(runtimeMinutes) &
runtimeMinutes > 0 &
runtimeMinutes <= 300) %>%
mutate(titleType = factor(titleType,
levels = c("movie", "tvSeries"),
labels = c("Filmes", "Séries de TV")))
# Estatísticas de duração por tipo
stats_duracao <- filmes_series_duracao %>%
group_by(titleType) %>%
summarise(
n = n(),
media = mean(runtimeMinutes, na.rm = TRUE),
mediana = median(runtimeMinutes, na.rm = TRUE),
minimo = min(runtimeMinutes, na.rm = TRUE),
maximo = max(runtimeMinutes, na.rm = TRUE),
.groups = "drop"
)
cat("========== ESTATÍSTICAS DE DURAÇÃO (minutos) ==========\n")
## ========== ESTATÍSTICAS DE DURAÇÃO (minutos) ==========
print(stats_duracao)
## # A tibble: 2 × 6
## titleType n media mediana minimo maximo
## <fct> <int> <dbl> <dbl> <int> <int>
## 1 Filmes 84188 90.3 90 1 300
## 2 Séries de TV 18497 42.6 35 1 300
# Gráfico: Boxplot + Violin plot de duração
ggplot(filmes_series_duracao, aes(x = titleType, y = runtimeMinutes, fill = titleType)) +
geom_violin(alpha = 0.3, color = NA) +
geom_boxplot(width = 0.2, alpha = 0.8, outlier.alpha = 0.3) +
stat_summary(fun = mean, geom = "point", shape = 18, size = 4, color = "black") +
scale_fill_manual(values = c("Filmes" = "#3498DB", "Séries de TV" = "#E74C3C")) +
labs(
title = "Distribuição de Duração: Filmes vs Séries de TV",
subtitle = "O losango (◆) indica a média | Duração máxima limitada a 300 min",
x = "",
y = "Duração (minutos)",
caption = "Fonte: IMDb | Títulos de 2020-2025 | Para séries, representa duração do episódio"
) +
theme_minimal(base_size = 12) +
theme(
plot.title = element_text(face = "bold", size = 14),
plot.subtitle = element_text(color = "gray40"),
legend.position = "none",
panel.grid.minor = element_blank()
) +
coord_flip()
Interpretação: Filmes tipicamente têm duração maior que episódios de séries. A distribuição “violin” mostra onde se concentram a maioria dos títulos, enquanto o boxplot destaca mediana, quartis e valores atípicos.
Objetivo: Analisar como a duração média de filmes, séries e curtas evoluiu ao longo dos anos (2020-2025). Esta análise permite identificar tendências temporais na duração das produções audiovisuais.
Metodologia: Calculamos a duração média por tipo de título e ano, filtrando apenas os tipos movie, tvSeries e short. Utilizamos um gráfico de linhas para visualizar a evolução temporal.
# Filtrar tipos desejados e calcular média de duração por ano
evolucao_duracao <- title_basics_filtrado %>%
filter(titleType %in% c("movie", "tvSeries", "short") &
!is.na(runtimeMinutes) &
runtimeMinutes > 0 &
runtimeMinutes <= 300) %>%
group_by(releaseYear, titleType) %>%
summarise(
duracao_media = mean(runtimeMinutes, na.rm = TRUE),
n = n(),
.groups = "drop"
) %>%
mutate(titleType = factor(titleType,
levels = c("movie", "tvSeries", "short"),
labels = c("Filmes", "Séries de TV", "Curtas")))
# Estatísticas por tipo e ano
cat("========== DURAÇÃO MÉDIA POR TIPO E ANO ==========\n")
## ========== DURAÇÃO MÉDIA POR TIPO E ANO ==========
evolucao_duracao %>%
select(releaseYear, titleType, duracao_media, n) %>%
mutate(duracao_media = round(duracao_media, 1)) %>%
print(n = 20)
## # A tibble: 18 × 4
## releaseYear titleType duracao_media n
## <dbl> <fct> <dbl> <int>
## 1 2020 Filmes 86.9 12445
## 2 2020 Curtas 12 29323
## 3 2020 Séries de TV 39.7 3914
## 4 2021 Filmes 88.7 13781
## 5 2021 Curtas 12.7 26810
## 6 2021 Séries de TV 41.8 3848
## 7 2022 Filmes 90.6 15066
## 8 2022 Curtas 13.2 25559
## 9 2022 Séries de TV 43.4 3462
## 10 2023 Filmes 91 15338
## 11 2023 Curtas 13.2 26007
## 12 2023 Séries de TV 43.6 2966
## 13 2024 Filmes 91.5 15172
## 14 2024 Curtas 13 24863
## 15 2024 Séries de TV 43.6 2462
## 16 2025 Filmes 92.9 12386
## 17 2025 Curtas 13.2 18744
## 18 2025 Séries de TV 45.9 1845
# Gráfico de linhas: Evolução da duração média
ggplot(evolucao_duracao, aes(x = releaseYear, y = duracao_media, color = titleType, group = titleType)) +
geom_line(linewidth = 1.3) +
geom_point(size = 3) +
scale_color_manual(values = c("Filmes" = "#3498DB", "Séries de TV" = "#E74C3C", "Curtas" = "#2ECC71")) +
scale_x_continuous(limits = c(2020, 2025), breaks = 2020:2025) +
labs(
title = "Evolução da Duração Média por Tipo de Título (2020-2025)",
subtitle = "Comparação entre Filmes, Séries de TV e Curtas",
x = "Ano de Lançamento",
y = "Duração Média (minutos)",
color = "Tipo",
caption = "Fonte: IMDb | Para séries, representa duração média do episódio"
) +
theme_minimal(base_size = 12) +
theme(
plot.title = element_text(face = "bold", size = 14),
plot.subtitle = element_text(color = "gray40"),
legend.position = "top",
panel.grid.minor = element_blank()
)
Interpretação: O gráfico mostra a evolução da duração média ao longo dos anos para cada tipo de produção. Filmes tendem a ter duração maior (90-120 min), séries de TV apresentam duração intermediária (duração do episódio, ~40-60 min), e curtas têm duração reduzida (<40 min). Variações ao longo dos anos podem indicar mudanças nas preferências de consumo ou tendências de produção.
Este projeto realizou uma análise exploratória dos dados do IMDb, focando em produções audiovisuais do período de 2020 a 2025. A partir da consolidação de três tabelas (title.basics, title.ratings e title.akas), foi possível extrair insights relevantes sobre a indústria cinematográfica e televisiva recente.
1. Popularidade vs Qualidade
A análise revelou uma correlação praticamente nula (-0.006) entre o número de votos e a nota média dos títulos. Isso indica que popularidade e qualidade são dimensões independentes — títulos muito votados não são necessariamente melhores avaliados, e obras de nicho podem ter excelentes avaliações mesmo com poucos votos.
2. Tendências de Gêneros
A evolução da produção por gênero mostrou quais categorias estão em crescimento ou declínio no período analisado. Esta análise permite identificar as preferências do mercado e as tendências contemporâneas na produção audiovisual.
3. Séries vs Filmes
A comparação entre filmes e séries de TV revelou diferenças nas distribuições de avaliações e durações. Filmes apresentam duração média maior (86-93 min), enquanto episódios de séries têm duração típica de 40-46 minutos.
4. Evolução da Duração
Uma descoberta interessante foi a tendência de aumento na duração tanto de filmes quanto de séries ao longo do período:
Este padrão pode refletir mudanças no consumo via streaming, onde o público tem maior flexibilidade de tempo para consumir conteúdos mais longos.
A base de dados do IMDb mostrou-se uma fonte rica para análise exploratória da indústria audiovisual. Os padrões identificados contribuem para a compreensão das tendências recentes de produção e consumo de conteúdo. Análises futuras poderiam incorporar dados de streaming, redes sociais e bilheteria para uma visão ainda mais completa do mercado audiovisual.
Vale ressaltar que a tabela final consolidada oferece diversas possibilidades além das apresentadas neste estudo. Com as variáveis disponíveis (tipo, gênero, ano, duração, avaliações, regiões e idiomas), é possível extrair análises adicionais, cruzamentos de dados e novas visualizações conforme o interesse específico do pesquisador. Este trabalho representa apenas uma amostra do potencial analítico contido nos dados.