Инструменты Python для анализа данных на примере данных стриминг-сервиса
В данной статье будет рассказано о некоторых методах библиотек Python, с помощью которых можно производить анализ данных, писать аналитические запросы к набору данных, визуализировать необходимую информацию в виде графиков и гистограмм.
Для примеров использования методов библиотек Python взят готовый датасет с информацией о пользователях онлайн-кинотеатра, о фильмах и их рейтинге. Будут использованы три библиотеки: Pandas, Numpy для аналитических запросов и Seaborn для визуализации.
1. Обработка данных
1.1 Импортирование файлов
Чтобы пользоваться инструментами библиотек, их необходимо импортировать, для этого используется команда import:
import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
Для начала импортируем три дата сета с информацией о фильмах, их рейтинге, и пользователях стриминг-сервиса с помощью команды pd.read_csv и преобразуем их в DataFrame:
movies_data = pd.read_csv('Dataset_Movie.csv')
ratings = pd.read_csv('Rating.csv')
users = pd.read_csv('users.csv')
1.2 Проверка DataFrame на наличие пустых значений:
Будет полезно проверить DataFrame на наличие пустых значений для корректного вывода информации. Часто используется метод .isnull ().sum ().
Метод isnull () возвращает DataFrame той же формы, но с булевыми значениями True или False. Поскольку True интерпретируется как 1, а False как 0, сумма по столбцу будет равна количеству пропущенных значений в этом столбце.
print(ratings.isnull().sum())
output:
User_ID 0
Rating 0
Movie_ID 0
1.3 Заполнение пустых значений
Если бы в данных DataFrame присутствовали пустые значения, то преобразовать их можно было бы следующими способами:
ratings['Rating'] = ratings['Rating'].fillna(ratings['Rating'].mean())
users['Age'] = users['Age'].fillna(users['Age'].median())
Был применен метод .fillna (), который заполняет пустые значения в колонке 'Rating' значением в скобках. В данном случае пустые значения были заполнены средним значением в колонке 'Rating' с помощью метода .mean ().
Для колонки 'Age' пустые значения были заполнены медианным значением при помощи метода .median ()
1.4 Объединение таблиц
Иногда для удобства выполнения запросов или визуализации требуется объединить данные в один DataFrame.
Это можно сделать при помощи метода pd.merge (), затем вывеcти первые пять строк получившегося DataFrame при помощи метода .head (), если, например, требуется проверить корректность получившегося результата:
merged_df = pd.merge(movies_data, ratings, on = 'Movie_ID')
rating_user = pd.merge(users, merged_df, on = 'User_ID')
print(rating_user.head())
2. Аналитические запросы
2.1 Самый популярный жанр
Найти самый популярный жанр фильмов среди пользователей можно следующим способом:
rating_user = rating_user.assign(Genres=rating_user['Favorite_Genre'].str.split('|')).explode('Favorite_Genre')
most_popular_genre = rating_user['Favorite_Genre'].value_counts().idxmax()
print(f'Самый популярный жанр среди пользователей:\n{most_popular_genre}')
Cначала необходимо разделить информацию в колонке 'Favorite_Genre', так как может быть указан не один жанр. Затем с помощью метода .value_counts () производится подсчет количества каждого жанра, и выводится встречающийся чаще всего при помощи .idmax ()
2.2 Самый любимый жанр для определенных возрастных групп
Допустим, нам требуется разделить всех пользователей по возрасту и понять, какие фильмы нравятся больше всего каждой возрастной группе:
rating_user['Age_Group'] = pd.cut(rating_user['Age'],
bins = [18,30,45,60,90],
labels= ['18-30', '30-45', '45-60', '60-90'])
Можно создать дополнительную колонку 'Age_Group', используя метод pd.cut (), чтобы отнести каждого пользователя к определенной возрастной группе. Указываются в виде списков границы каждой группы (bins) и наименования группы (labels).
Затем, применяя метод pd.pivot_table, создается сводная таблица: по оси абсцисс значения из колонки 'Favorite_Genre', по оси ординат — из 'Age_Group'. Далее в поле значений сводной таблицы находится средний рейтинг по каждому жанру в определенной возрастной группе с округлением до двух знаков после запятой.
popular_genre = pivot.idxmax(axis=0)
popular_genre_df = popular_genre.reset_index()
popular_genre_df.columns = ['Age_Group', 'Most_Popular_Genre']
print(f'Самый популярный жанр для каждой возрастной группы:\n{popular_genre_df}')
output:
Самый популярный жанр для каждой возрастной группы:
Age_Group Most_Popular_Genre
0 18–30 Action
1 30–45 Drama
2 45–60 Romance
3 60–90 Horror
Применив данные из сводной таблицы, был создан новый DataFrame popular_genre_df с колонками 'Age_Group' и 'Most_Popular_Genre'. Было найдено максимальное значение в каждой колонке сводной таблицы с помощью метода .idmax (axis = 0) (axis = 0 указывает, что поиск производится по столбцам).
2.3 Средний рейтинг фильмов за каждое десятилетие
Можно посмотреть, как люди оценивали фильмы за некоторые временные промежутки. Для начала создадим список из необходимых нам десятилетий:
bins1=[1960, 1970, 1980, 1990, 2000]
Аналогично созданию столбца 'Age_Group', создадим колонку 'Decade':
rating_user['Decade'] = pd.cut(
rating_user['Year'],
bins=bins1,
right=False,
labels=[f'{bins1[i]}' for i in range(len(bins1) - 1)])
Сгруппируем значения по столбцу 'Decade', значения возьмем как средний рейтинг:
avg_rating_by_year = round(rating_user.groupby('Decade', observed =
True)['Rating'].mean(),2)
print(f'Средний рейтинг фильмов за каждое десятилетие:\n{avg_rating_by_year}')
output:
Decade
1960 3.74
1970 3.76
1980 3.62
1990 3.61
Как итог: в семидесятые выпускались фильмы с самым высоким средним рейтингом.
2.4 Страна с наибольшим количеством пользователей
Также, с помощью библиотек python есть возможность найти страну, пользователей стриминга в которой, наибольшее количество.
country_most_users = rating_user['Country'].value_counts().idxmax()
print(f'Страна с наибольшим кол-вом пользователей:\n{country_most_users}')
output:
Страна с наибольшим кол-вом пользователей:
Germany
Методом value_counts ().idmax () подсчитывается количество значений и затем выделяется наиболее часто встречающееся. Таким образом, Германия является страной с наибольшим количеством пользователей.
2.5 Самый популярный жанр в каждой стране
Посмотрим, фильмы какого жанра предпочитают пользователи в каждой стране:
top_genre_by_country = rating_user.groupby('Country')
['Favorite_Genre'].apply(lambda x: x.mode()[0])
print(f'Самый популярный жанр в каждой стране:\n
{top_genre_by_country}')
output:
Самый популярный жанр в каждой стране:
Country
Australia Romance
Brazil Romance
Canada Documentary
France Drama
Germany Drama
India Horror
Japan Documentary
Mexico Romance
UK Documentary
USA Romance
Name: Favorite_Genre, dtype: object
В данном случае используется лямбда-функция (lambda), которая берет значения в колонке 'Favorite_Genre' и находит самый частый элемент с помощью метода .mode (). Метод .mode () возвращает список всех значений, встречающихся чаще всего.
Так как нужен только один результат, мы берем первый элемент списка с помощью [0].
2.6 Отбор фильмов с рейтингом больше 4.5
top_movies = rating_user[rating_user['Rating'] > 4.5][['Movie_ID', 'Rating']]
В данном отборе была применена булевая индексация и маскировка: был создан DataFrame c булевыми значениями, где значение True обозначает выполнение условия ['Rating'] > 4.5.
После фильтрации оставлены колонки 'Movie_ID' и 'Rating' для наглядности.
2.7 Количество просмотренных часов для каждого типа подписки
watch_hours = rating_user.groupby('Subscription_Type', observed=True)
['Watch_Time_Hours'].sum()
print(f'Количество просмотренный часов для каждого типа подписки:\n{watch_hours}')
output:
Количество просмотренный часов для каждого типа подписки:
Subscription_Type
Basic 28594802.53
Premium 26518708.16
Standard 27210667.60
Name: Watch_Time_Hours, dtype: float64
Опять же, применяем метод .groupby () для группировки данных по колонке 'Subscription_Type', а для значений выносим сумму по часам просмотренного контента. Получается, что пользователи с видом подписки 'Basic' смотрят фильмы и сериалы больше остальных пользователей.
3. Визуализация
3.1 Гистограмма распределения возраста пользователей
sns.histplot(rating_user['Age'], bins = 10, kde = True, color='pink')
plt.title('Распределение возраста пользователей')
plt.show()
C помощью метода sns.hisplot () была построена гистограмма распределения возраста пользователей.
![Alt Распределение возраста пользователей (/Users/grigorovakarina/Documents/GitHub/Project1/Figure_1.png)
3.2 Кривая плотности рейтинга
Для наглядности можно визуализировать кривую плотности рейтинга:
sns.kdeplot(rating_user['Rating'], color='blue', fill=True)
plt.title('Кривая плотности рейтинга')
plt.show()

Следовательно, можно увидеть, что пользователи больше склонны ставить фильмам оценку '4'.
3.3 Распределение типов подписок по разным возрастным группам
Сгруппируем данные по возрастной группе и типу подписки:
subscription_counts = rating_user.groupby(['Age_Group',
'Subscription_Type'], observed=True).size().reset_index(name='Count')
print(subscription_counts)
output:
Age_Group Subscription_Type Count
0 18–30 Basic 8753
1 18–30 Premium 9662
2 18–30 Standard 8254
3 30–45 Basic 14185
4 30–45 Premium 11211
5 30–45 Standard 11167
6 45–60 Basic 11977
7 45–60 Premium 12598
8 45–60 Standard 12310
9 60–90 Basic 17929
10 60–90 Premium 14991
11 60–90 Standard 16373
Была произведена группировка по двум колонкам: 'Age_Group' и 'Subscription_Type'. Метод .size () подсчитывает количество записей в каждой группе. То есть, для каждой уникальной пары значений 'Age_Group' и 'Subscription_Type' будет определено число подписчиков. Метод .reset_index () преобразует результат группировки обратно в DataFrame. Параметр name='Count' присваивает имя новому столбцу, содержащему количество подписчиков для каждой комбинации 'Age_Group' и 'Subscription_Type'.
Построение гистограммы barplot:
sns.barplot (x='Age_Group', y='Count', hue='Subscription_Type',
data=subscription_counts, palette='viridis')
plt.title ('Распределение типов подписок по возрастным группам')
plt.xlabel ('Возрастная группа')
plt.ylabel ('Количество подписок')
plt.legend (title='Тип подписки')
plt.show ()

По оси абсцисс выводится возрастная группа, по оси ординат количество подписчиков. Из данной гистаграммы видно, что пользователи от 18 до 30 лет чаще выбирают подписку Premium, а пользователи более старшего возраста предпочитают подписку Basic.
По итогам всего вышесказанного можно понять, как с помощью языка python и его библиотек визуализировать информацию, получить необходимые данные, провести аналитику по различным критериям и категориям для различных нужд.