
Ссылка на .ipynb блокнот (не только код) -https://drive.google.com/file/d/1uPuyp4m-Qo2EOHji0QuKJ87sz0Qt676s/view?usp=drive_link
Ссылка на датасет -https://drive.google.com/file/d/1e3KxgXSssmksOQ9cMsqEXnFaf_dJtNea/view?usp=sharing
Мной был выбран датасет с сайта kaggle https://www.kaggle.com/datasets/ritiksharma07/imdb-top-1000-movies-dataset под названием IMDB Top 1000 Movies Dataset
Данный датасет содержит в себе информацию про 1000 фильмов с наибольшей оценкой на сайте IMDb, интерес для визуального анализа он представляет наличием точных числовых или жестко определенных категориальных переменных (как возрастной рейтинг фильма или точная дата его выхода). Помимо этого изначально некоторые стобцы датасета приведены более к человекочитаемому виду, нежели к удобному для машинного анализа:
«duration"(длительность кинокартины по времени) в формате «{число_часов}h {число_минут}m»
«numberof_ratings"(количство оценивших фильм) в формате миллионов или тысяч с буквенным обозначением «M» или «k» сответственно
Данный факт делает датасет интереснее для данной учебной задачи, так как нужно выполнить дополнительные преобразования перед непосредственной визуализацией данных
Также сам датасет основан на пользовательских оценках, так что изучая его в теории можно выделить какие-то закономерности влияющие на впечатление зрителя от фильма.
Код загрузки и обработки датасета
import pandas as pd import matplotlib.pyplot as plt import seaborn as sns
file_path = 'imdb_kaggle.csv' data = pd.read_csv (file_path)
def convert_duration (duration): parts = duration.split (' ') if len (parts) == 2: hours = int (parts[0].replace ('h', '')) minutes = int (parts[1].replace ('m', '')) return hours * 60 + minutes elif 'h' in duration: hours = int (duration.replace ('h', '')) return hours * 60 else: return int (duration.replace ('m', ''))
data['duration'] = data['duration'].apply (convert_duration)
data['numberof_ratings'] = data['numberof_ratings'].str.replace ('[()]', '', regex=True) data['numberof_ratings'] = [int (number[: -1]) if number[-1] == 'K' else (int (float (number[: -1]) * 1000)) for number in data['numberof_ratings']]
data['rating'] = data['rating'].astype (float)
data = data.dropna (subset=['rating', 'numberof_ratings', 'Metascore', 'duration'])
Для оригинальной стилизации графика я использовал стиль dark-palette
Также для bar и scatter графиков я использую палитру градиента 'magma', а для остальных графиков цвет 'purple', подходящий под данный градиент
Особых источников для вдохновения не было, просто близкая к оттенкам фиолетового палитра и реверсированный фон сетки, подходящий под палитру
Графики выполнены в отношении 12:6
Код для создания основы стиля графиков: plt.style.use («seaborn-v0_8-dark-palette») palette = 'magma' color = 'purple'
График зависимости среднего рейтинга фильмов от года выпуска
Был выбран обычный линейный график, так как мы смотрим на динамику изменения переменной с большим числом возможных значений года выпуска фильма
По данному графику, например, можно сказать, что в средней части отрезка 1960-1980 средний рейтинг выше, чем в такой же части отрезка 2000-2020, из-за чего можно выдвинуть гипотизу вида: «Старые фильмы люди оцениваю лучше, чем новые»
Код: plt.figure (figsize=(12, 6)) average_rating_by_year = data.groupby ('year')['rating'].mean ().reset_index () sns.lineplot (data=average_rating_by_year, x='year', y='rating', marker='o', linewidth=2.5, color = color) plt.title ('Average IMDb Rating by Year', fontsize=16) plt.xlabel ('Year', fontsize=14) plt.ylabel ('Average Rating', fontsize=14) plt.xticks (fontsize=12) plt.yticks (fontsize=12) plt.show ()
График распределения количества фильмов по продолжительности (30 столбцов)
Вид графика — гистограмма, так как достаточно большой разброс значений, и нам не нужно отличать друг от друга фильмы у которых разница длительности слишком малая
Код: plt.figure (figsize=(12, 6)) sns.histplot (data['duration'], bins=30, kde=True, color = color) plt.title ('Distribution of Movie Durations', fontsize=16) plt.xlabel ('Duration (minutes)', fontsize=14) plt.ylabel ('Frequency', fontsize=14) plt.xticks (fontsize=12) plt.yticks (fontsize=12) plt.show ()
График средней оценки фильма по возрастному ограничению
Вид графика столбчатый, выбран именно такой, так как у нас есть определенные категории, которые мы хотим сравнить между собой.
На данном графике видно, что оценки в среднем действительно меняются от одного ограничения к другому, особенно интересны в этом плане фильмы с американской (PG, PG-13, R) системой ограничений, где у PG явный разрыв с PG-13 и R, доходящий до 0.2 баллов
Код: plt.figure (figsize=(12, 6)) average_rating_by_age_limit = data.groupby ('age_limit')['rating'].mean ().reset_index () sns.barplot (data=average_rating_by_age_limit, x='age_limit', y='rating', hue = 'age_limit', palette=palette) plt.title ('Average IMDb Rating by Age Limit', fontsize=16) plt.xlabel ('Age Limit', fontsize=14) plt.ylabel ('Average Rating', fontsize=14) plt.xticks (fontsize=12) plt.yticks (fontsize=12) plt.ylim (7.5, 8.5) plt.show ()
Зависимость рейтинга и количества оценок на сайте IMDb
Для графика выбран формат точечного графика, так как нам важно примерное значение для каждого фильма (чтобы видеть крайние значения, которые могут быть одиночными)
На данном графике можно увидеть, что примерно с 1 миллиона оценок начинает расти минимальная оценка фильма, то есть образуется некоторый кластер фильмов, которые почти всем нравятся и который многие оценили
Код:
plt.figure (figsize=(12, 6)) sns.scatterplot (data=data, x='numberof_ratings', y='rating', hue='rating', palette=palette, alpha=0.6, edgecolor='w', s=100) plt.title ('Number of Ratings vs. IMDb Rating', fontsize=16) plt.xlabel ('Number of Ratings (in thousands)', fontsize=14) plt.ylabel ('IMDb Rating', fontsize=14) plt.xscale ('log') plt.legend (title='IMDb Rating', bbox_to_anchor=(1.05, 1), loc='upper left') plt.show ()
Зависимость рейтинга на IMDb и оценке на Metascore
Для графика выбран формат точечного графика, так как нам важно примерное значение для каждого фильма (чтобы видеть крайние значения, которые могут быть одиночными)
На данном графике аналогично прошлому графику можно увидеть повышение минимальной оценки на Metascore при повышении рейтинга на IMDb, но стоит отметить, что в остальном рейтинги IMDb и Metascore не сильно коррелируют (коэф корреляции 0.24, добавлен на график в нижнем левом углу)
Код: plt.figure (figsize=(12, 6)) sns.scatterplot (data=data, x='rating', y='Metascore', alpha=0.6, hue='rating', palette=palette, edgecolor='w', s=100) plt.title ('IMDb Rating vs. Metascore', fontsize=16) plt.xlabel ('IMDb Rating', fontsize=14) plt.ylabel ('Metascore', fontsize=14) plt.xticks (fontsize=12) plt.yticks (fontsize=12)
correlation = data['rating'].corr (data['Metascore']) plt.text (8.9, 30, f’Correlation: {correlation:.2f}', fontsize=12, color='black', bbox=dict (facecolor='white', edgecolor='black', boxstyle='round, pad=0.5'))
plt.show ()