Анализ данных с Pandas.Python
У вас есть данные которые надо превратить в аккуратную табличку, Pandas вам поможет ) Pandas — программная библиотека на языке Python для обработки и анализа данных. Работа с данными строится поверх библиотеки NumPy, являющейся инструментом более низкого уровня. Вообщем если вы хотите ваши хаотичные данные загнать в красивую табличку, где уже намного легче обрабатывать и анализировать данные, поехали.
У нас есть набор данных, который нужно превратить в таблицу. Это делается вызовом конструктора DataFrame() Конструктор принимает два аргумента – список данных и названия столбцов, которые должны быть в таблице. Попробуем :
Вот мы получили аккуратную таблицу с 3-мя колонками и 3-мя рядами (с 0 по 2 индекс). Конечно мы руками не будем забивать все данные. Давайте загрузим из CSV файла: я подготовил небольшую базу для примера, на которой мы будем тренироваться. Качаем .
CSV (от англ. Comma-Separated Values — значения, разделённые запятыми) — текстовый формат, предназначенный для представления табличных данных. Строка таблицы соответствует строке текста, которая содержит одно или несколько полей, разделенных запятыми.
Информация о базе.
Давайте ознакомимся с данными с помощью двух методов : head() и tail() . head(по умолчанию 5) — вернет строки набора данные с начала таблички, tail() — соответственно с хвоста.
У DataFrame есть неотъемлемые свойства, значения которых можно запросить. Атрибут columns содержит информацию о названиях столбцов в наборе данных. Для просмотра типа данных каждого столбца лучше всего использовать атрибут dtypes. object соответствует типу srt. О размерах таблицы с данными сообщает её атрибут shape.
Всю информацию, которую предоставляют разные атрибуты DataFrame, можно получить вызовом одного-единственного метода info().
Работа с данными или индексация.
К каждой ячейке с данными в DataFrame можно обратиться по её индексу и названию столбца. Мы можем получать различные срезы данных в зависимости от того, какой запрос к DataFrame мы сформулируем.
Атрибут loc[строка, столбец] даёт доступ к элементу по строке и столбцу.
- Одна ячейка — .loc[7, ‘название столбца’]
- Один столбец — .loc[:, ‘название столбца’]
- Несколько столбцов — .loc[:, [‘название столбца’, ‘название столбца’]]
- Несколько столбцов подряд (срез) — .loc[:, ‘login’: ‘pass’]
- Одна строка — .loc[1]
- Все строки, начиная с заданной — .loc[1:]
- Все строки до заданной — .loc[:3]
- Несколько строк подряд (срез) — .loc[2:5]
Но это не самое интересное, мы можем использовать логическую индексацию. Давайте сделаем выборку все данных где пароль задан 12345 :
[: , ‘pass’] == ‘12345’ ] — логическое условие которое проверяется для каждого элемента столбца ‘pass’ . [ : ] — какой столбец выбираем.
Так же мы можем посчитать количество данных. В Pandas для этого есть метод count() :
Для примера посчитаем долю паролей «12345» в базе данных :
Очистка данных.
Конечно данные не идеальны. Где то пропущены значения, возможно есть дубликаты и т.д. Pandos конечно нам позволяет очистить данные от мусора.
Для начало поменяем название столбцов, воспользуемся методом set_axis() . Он принимает три аргумента:
- список с новыми названиями столбцов;
- axis — ось, которой новые названия присваиваются: ‘index’, если они даются строкам, и ‘columns’, если это список новых названий столбцов;
- inplace — принимает значения True либо False. В первом случае метод set_axis() перестраивает структуру данных так, что она замещает прежнюю в переменной с тем же именем.
Так же в данных бывает что и нет данных ) В нашей таблице есть ячейки без данных .Замены пропущенных значений в DataFrame бывают трёх видов:
- Ожидаемые: None или NaN. None (англ. none, «ничто») — это эквивалент null в других языках программирования: особое значение, указывающее, что в этой ячейке таблицы никакого значения нет. None относится к NoneType .
- Странные: плейсхолдеры (тексты-заполнители) какого-нибудь общепринятого стандарта, иногда неизвестного вам, но которого придерживаются составители. Чаще всего это n/a, na, NA (от англ. no answer, «нет ответа»), и N.N.либо NN (от лат. Nomen nescio, «не знаю имени»).
- Неожиданные: например, разработчики решили, что пустые значения в таблице будут заполняться знаками вопроса или нулями. В лучшем случае этот факт укажут в документации, в худшем – придётся просматривать данные самостоятельно. Если какой-нибудь спецсимвол или число встречаются часто, и этому нет внятного объяснения, то высока вероятность, что так передаются пропущенные значения.
Для поиска первых двух типов в Pandas есть два метода .isnull() и .isna() . Если значение элемента не существует, .isnull() и .inna() возвращает True, а иначе — False. Суммируют эти True вызовом метода sum() который в этом случае возвращает общее число элементов без определённых значений.
Как мы видим у нас есть пропущенные значения в столбце Login и Password. Давайте пропущенные значения в столбце Login заполним нулями . Для этого будем использовать метод .fillna(чем заполнить)
А строки с пропущенными данными в Password удалим методом . dropna()
Заметьте , индексирование таблицы у нас нарушилась : после 8152 идет сразу 8154 . Исправим это методом .reset_index( drop=True ) .
Теперь перейдем к дубликатам. Для поиска дубликатов есть метод . duplicated() . Он возвращает Series со значением True при наличии дубликатов, и False, когда их нет.
Для удаления дубликатов из данных используем метод .drop_duplicates()
Для просмотра всех уникальных значений в столбце используется метод . unique()
Для замены определенных значений можно воспользоваться методом replace() , где первый аргумент — текущее значение, а второй — новое, нужное.
Анализ данных.
Для анализа данных мы возьмем базу найденных экзопланет в формате CSV , качаем.
- name: название экзопланеты;
- mass: масса в массах планеты Юпитер;
- radius: радиус, пересчитанный в радиусах Земли;
- discovered: год открытия экзопланеты.
- star_mass : масса в массах Солнца.
Анализ данных начинают с разделения их на группы по какому-нибудь признаку. Эта операция называется группировка данных. Группировка оправданна, если данные чётко делятся по значимому признаку, а полученные группы близки к теме задачи.
В Рandas для группировки данных есть метод .groupby() . Он принимает как аргумент название столбца, по которому нужно группировать. В случае с делением экзопланет по годам открытия:
Применение метода .groupby() к объекту типа DataFrame приводит к созданию объекта особого типа — DataFrameGroupBy. Это сгруппированные данные. Если применить к ним какой-нибудь метод Pandas, они станут новой структурой данных типа DataFrame или Series.
В 2014 и 2016 было открыто очень много планет. Уммм
Если нужно сравнить по одному показателю, метод применяют к DataFrameGroupBy с указанием на один столбец. Например радиус :
Давайте сделаем выборку по планетам радиус которых почти равен земному и отсортируем по убыванию. Для сортировки значений в Pandas есть метод .sort_values( )
- ‘имя столбца’ — имя столбца, по которому нужно сортировать;
- ascending: по умолчанию True. Для сортировки по убыванию установите значение False.
Oписательная статистика — четыре основных метода максимум, минимум, медиана и среднее
В статистике медиана делит выборку пополам: в одной половине значения меньше медианного, в другой больше. Логично, что для определения медианы список обязательно должен быть отсортирован — либо по возрастанию, либо по убыванию.
Если вы нашли ошибку, пожалуйста, выделите фрагмент текста и нажмите Ctrl+Enter.
Источник
dsibi / Добро пожаловать в самостоятельный проект
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Вы провели исследование, которое включает важнейшие стадии анализа данных. |
Применили Python и Pandas и ещё раз отработали связку метод-стадия. |
Отработали методы предобработки, важной стадии анализа данных. |
Разобрали процесс подготовки проекта в Jupyter Notebook. Теперь вы можете показать своё исследование кому пожелаете для ознакомления, проверки и развития. |
Получили опыт PR-исследования данных бизнеса с выводами, понятными широкой аудитории. |
Теперь вы можете проводить небольшие исследования, отвечающие на простые количественные вопросы. Вы также владеете простыми методами предобработки данных. Работайте с готовыми csv-файлами, доводите их до совершенства и проводите базовый анализ. Теперь у вас есть все необходимые для этого инструменты. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Этап 1. Получение данных |
Изучим данные, предоставленные сервисом для проекта. |
Импорт библиотек |
# |
import pandas as pd |
Прочитаем файл music_project.csv и сохраним его в переменной df. |
# |
df = pd.read_csv(‘/datasets/music_project.csv’) |
Получение первых 10 строк таблицы. |
# |
df.head(10) |
userID Track artist genre City time Day |
0 FFB692EC Kamigata To Boots The Mass Missile rock Saint-Petersburg 20:28:33 Wednesday |
1 55204538 Delayed Because of Accident Andreas Rönnberg rock Moscow 14:07:09 Friday |
2 20EC38 Funiculì funiculà Mario Lanza pop Saint-Petersburg 20:58:07 Wednesday |
3 A3DD03C9 Dragons in the Sunset Fire + Ice folk Saint-Petersburg 08:37:09 Monday |
4 E2DC1FAE Soul People Space Echo dance Moscow 08:34:34 Monday |
5 842029A1 Преданная IMPERVTOR rusrap Saint-Petersburg 13:09:41 Friday |
6 4CB90AA5 True Roman Messer dance Moscow 13:00:07 Wednesday |
7 F03E1C1F Feeling This Way Polina Griffith dance Moscow 20:47:49 Wednesday |
8 8FA1D3BE И вновь продолжается бой NaN ruspop Moscow 09:17:40 Friday |
9 E772D5C0 Pessimist NaN dance Saint-Petersburg 21:20:49 Wednesday |
Общая информация о данных таблицы df. |
# |
RangeIndex: 65079 entries, 0 to 65078 |
Data columns (total 7 columns): |
userID 65079 non-null object |
Track 63848 non-null object |
artist 57876 non-null object |
genre 63881 non-null object |
City 65079 non-null object |
time 65079 non-null object |
Day 65079 non-null object |
dtypes: object(7) |
memory usage: 3.5+ MB |
Рассмотрим полученную информацию подробнее. |
Всего в таблице 7 столбцов, тип данных у каждого столбца — . |
Подробно разберём, какие в df столбцы и какую информацию они содержат: |
userID — идентификатор пользователя; |
Track — название трека; |
artist — имя исполнителя; |
genre — название жанра; |
City — город, в котором происходило прослушивание; |
time — время, в которое пользователь слушал трек; |
Day — день недели. |
Количество значений в столбцах различается. Это говорит о том, что в данных есть значения. |
Выводы |
Каждая строка таблицы содержит информацию о композициях определённого жанра в определённом исполнении, которые пользователи слушали в одном из городов в определённое время и день недели. Две проблемы, которые нужно решать: пропуски и некачественные названия столбцов. Для проверки рабочих гипотез особенно ценны столбцы time, day и City. Данные из столбца genre позволят узнать самые популярные жанры. |
Этап 2. Предобработка данных |
Исключим пропуски, переименуем столбцы, а также проверим данные на наличие дубликатов. |
Получаем перечень названий столбцов. Какая наблюдается проблема — кроме тех, что уже были названы ранее? |
# |
df.columns |
Index([‘ userID’, ‘Track’, ‘artist’, ‘genre’, ‘ City ‘, ‘time’, ‘Day’], dtype=’object’) |
В названиях столбцов есть пробелы, которые могут затруднять доступ к данным. |
Переименуем столбцы для удобства дальнейшей работы. Проверим результат. |
# |
#df.columns = [‘userID’, ‘track_name’, ‘artist_name’, ‘genre_name’, ‘city’, ‘time’, ‘weekday’] |
df.set_axis([‘user_id’, ‘track_name’, ‘artist_name’, ‘genre_name’, ‘city’, ‘time’, ‘weekday’], axis = ‘columns’, inplace = True) |
# |
list(df) |
[‘user_id’, |
‘track_name’, |
‘artist_name’, |
‘genre_name’, |
‘city’, |
‘time’, |
‘weekday’] |
Проверим данные на наличие пропусков вызовом набора методов для суммирования пропущенных значений. |
# |
df.isnull().sum() |
#df.columns[df.isnull().any()] # |
#df[df.columns[df.isnull().any()]]# |
user_id 0 |
track_name 1231 |
artist_name 7203 |
genre_name 1198 |
city 0 |
time 0 |
weekday 0 |
dtype: int64 |
Пустые значения свидетельствуют, что для некоторых треков доступна не вся информация. Причины могут быть разные: скажем, не назван конкретный исполнитель народной песни. Хуже, если проблемы с записью данных. Каждый отдельный случай необходимо разобрать и выявить причину. |
Заменяем пропущенные значения в столбцах с названием трека и исполнителя на строку ‘unknown’. После этой операции нужно убедиться, что таблица больше не содержит пропусков. |
# |
df[‘track_name’] = df[‘track_name’].fillna(‘unknown’) |
# |
df[‘artist_name’] = df[‘artist_name’].fillna(‘unknown’) |
# |
df.isnull().sum() |
user_id 0 |
track_name 0 |
artist_name 0 |
genre_name 1198 |
city 0 |
time 0 |
weekday 0 |
dtype: int64 |
Удаляем в столбце с жанрами пустые значения; убеждаемся, что их больше не осталось. |
# |
df.dropna(subset=[‘genre_name’],inplace=True) |
# |
df.isnull().sum() |
user_id 0 |
track_name 0 |
artist_name 0 |
genre_name 0 |
city 0 |
time 0 |
weekday 0 |
dtype: int64 |
Необходимо установить наличие дубликатов. Если найдутся, удаляем, и проверяем, все ли удалились. |
# |
df.duplicated().sum() |
3755 |
# |
df=df.drop_duplicates().reset_index(drop=True) |
# |
df.duplicated().sum() |
0 |
Дубликаты могли появиться вследствие сбоя в записи данных. Стоит обратить внимание и разобраться с причинами появления такого «информационного мусора». |
Сохраняем список уникальных значений столбца с жанрами в переменной genres_list. |
Объявим функцию find_genre() для поиска неявных дубликатов в столбце с жанрами. Например, когда название одного и того же жанра написано разными словами. |
# |
genres_list=df[‘genre_name’].unique() |
# |
# функция принимает как параметр строку с названием искомого жанра |
def find_genre(genre): |
# в теле объявляется переменная-счётчик, ей присваивается значение 0, |
count=0 |
# затем цикл for проходит по списку уникальных значений |
for i in genres_list: |
# если очередной элемент списка равен параметру функции, |
if i == genre: |
#if len(i) == genre: |
# то значение счётчика увеличивается на 1 |
count += 1 |
# по окончании работы цикла функция возвращает значение счётчика |
return count |
Вызов функции find_genre() для поиска различных вариантов названия жанра хип-хоп в таблице. |
Правильное название — hiphop. Поищем другие варианты: |
hip |
hop |
hip-hop |
# |
find_genre(‘hip’) |
1 |
# |
find_genre(‘hop’) |
0 |
# |
find_genre(‘hip-hop’) |
0 |
Объявим функцию find_hip_hop(), которая заменяет неправильное название этого жанра в столбце ‘genre_name’ на ‘hiphop’ и проверяет успешность выполнения замены. |
Так исправляем все варианты написания, которые выявила проверка. |
# |
# функция принимает как параметры таблицу df и неверное название |
def find_hip_hop(df,wrong): |
# к столбцу ‘genre_name’ применяется специальный метод, |
# который заменяет второй параметр на строку ‘hiphop’ |
df[‘genre_name’] = df[‘genre_name’].replace(wrong, ‘hiphop’) |
# результат работы равен подсчитанному методом count() числу значений столбца, |
# которые равны второму параметру |
total = df.loc[df.loc[:,’genre_name’] == ‘wrong’][‘genre_name’].count() |
# функция возвращает результат |
return total |
0 |
# |
find_hip_hop(df,’hip’) |
#df[‘genre_name’] = df[‘genre_name’].replace(‘hip’, ‘hiphop’) |
#total = df.loc[df.loc[:,’genre_name’] == ‘hip’][‘genre_name’].count() |
#print(total) |
0 |
Получаем общую информацию о данных. Убеждаемся, что чистка выполнена успешно. |
# |
df.info() |
print(genres_list) |
RangeIndex: 60126 entries, 0 to 60125 |
Data columns (total 7 columns): |
user_id 60126 non-null object |
track_name 60126 non-null object |
artist_name 60126 non-null object |
genre_name 60126 non-null object |
city 60126 non-null object |
time 60126 non-null object |
weekday 60126 non-null object |
dtypes: object(7) |
memory usage: 3.2+ MB |
[‘rock’ ‘pop’ ‘folk’ ‘dance’ ‘rusrap’ ‘ruspop’ ‘world’ ‘electronic’ |
‘alternative’ ‘children’ ‘rnb’ ‘hip’ ‘jazz’ ‘postrock’ ‘latin’ |
‘classical’ ‘metal’ ‘reggae’ ‘tatar’ ‘blues’ ‘instrumental’ ‘rusrock’ |
‘dnb’ ‘türk’ ‘post’ ‘country’ ‘psychedelic’ ‘conjazz’ ‘indie’ |
‘posthardcore’ ‘local’ ‘avantgarde’ ‘punk’ ‘videogame’ ‘techno’ ‘house’ |
‘christmas’ ‘melodic’ ‘caucasian’ ‘reggaeton’ ‘soundtrack’ ‘singer’ ‘ska’ |
‘shanson’ ‘ambient’ ‘film’ ‘western’ ‘rap’ ‘beats’ «hard’n’heavy» |
‘progmetal’ ‘minimal’ ‘contemporary’ ‘new’ ‘soul’ ‘holiday’ ‘german’ |
‘tropical’ ‘fairytail’ ‘spiritual’ ‘urban’ ‘gospel’ ‘nujazz’ ‘folkmetal’ |
‘trance’ ‘miscellaneous’ ‘anime’ ‘hardcore’ ‘progressive’ ‘chanson’ |
‘numetal’ ‘vocal’ ‘estrada’ ‘russian’ ‘classicmetal’ ‘dubstep’ ‘club’ |
‘deep’ ‘southern’ ‘black’ ‘folkrock’ ‘fitness’ ‘french’ ‘disco’ |
‘religious’ ‘hiphop’ ‘drum’ ‘extrememetal’ ‘türkçe’ ‘experimental’ ‘easy’ |
‘metalcore’ ‘modern’ ‘argentinetango’ ‘old’ ‘breaks’ ‘eurofolk’ |
‘stonerrock’ ‘industrial’ ‘funk’ ‘jpop’ ‘middle’ ‘variété’ ‘other’ |
‘adult’ ‘christian’ ‘gothic’ ‘international’ ‘muslim’ ‘relax’ ‘schlager’ |
‘caribbean’ ‘ukrrock’ ‘nu’ ‘breakbeat’ ‘comedy’ ‘chill’ ‘newage’ |
‘specialty’ ‘uzbek’ ‘k-pop’ ‘balkan’ ‘chinese’ ‘meditative’ ‘dub’ ‘power’ |
‘death’ ‘grime’ ‘arabesk’ ‘romance’ ‘flamenco’ ‘leftfield’ ‘european’ |
‘tech’ ‘newwave’ ‘dancehall’ ‘mpb’ ‘piano’ ‘top’ ‘bigroom’ ‘opera’ |
‘celtic’ ‘tradjazz’ ‘acoustic’ ‘epicmetal’ ‘historisch’ ‘downbeat’ |
‘downtempo’ ‘africa’ ‘audiobook’ ‘jewish’ ‘sängerportrait’ ‘deutschrock’ |
‘eastern’ ‘action’ ‘future’ ‘electropop’ ‘folklore’ ‘bollywood’ |
‘marschmusik’ ‘rnr’ ‘karaoke’ ‘indian’ ‘rancheras’ ‘электроника’ |
‘afrikaans’ ‘tango’ ‘rhythm’ ‘sound’ ‘deutschspr’ ‘trip’ ‘lovers’ |
‘choral’ ‘dancepop’ ‘podcasts’ ‘retro’ ‘smooth’ ‘mexican’ ‘brazilian’ |
‘ïîï’ ‘mood’ ‘surf’ ‘author’ ‘gangsta’ ‘triphop’ ‘inspirational’ ‘idm’ |
‘ethnic’ ‘bluegrass’ ‘broadway’ ‘animated’ ‘americana’ ‘karadeniz’ |
‘rockabilly’ ‘colombian’ ‘self’ ‘synthrock’ ‘sertanejo’ ‘japanese’ |
‘canzone’ ‘swing’ ‘lounge’ ‘sport’ ‘korean’ ‘ragga’ ‘traditional’ |
‘gitarre’ ‘frankreich’ ‘alternativepunk’ ’emo’ ‘laiko’ ‘cantopop’ |
‘glitch’ ‘documentary’ ‘rockalternative’ ‘thrash’ ‘hymn’ ‘oceania’ |
‘rockother’ ‘popeurodance’ ‘dark’ ‘vi’ ‘grunge’ ‘hardstyle’ ‘samba’ |
‘garage’ ‘soft’ ‘art’ ‘folktronica’ ‘entehno’ ‘mediterranean’ ‘chamber’ |
‘cuban’ ‘taraftar’ ‘rockindie’ ‘gypsy’ ‘hardtechno’ ‘shoegazing’ |
‘skarock’ ‘bossa’ ‘salsa’ ‘latino’ ‘worldbeat’ ‘malaysian’ ‘baile’ |
‘ghazal’ ‘loungeelectronic’ ‘arabic’ ‘popelectronic’ ‘acid’ ‘kayokyoku’ |
‘neoklassik’ ‘tribal’ ‘tanzorchester’ ‘native’ ‘independent’ ‘cantautori’ |
‘handsup’ ‘poprussian’ ‘punjabi’ ‘synthpop’ ‘rave’ ‘französisch’ |
‘quebecois’ ‘speech’ ‘soulful’ ‘teen’ ‘jam’ ‘ram’ ‘horror’ ‘scenic’ |
‘orchestral’ ‘neue’ ‘roots’ ‘slow’ ‘jungle’ ‘indipop’ ‘axé’ ‘fado’ |
‘showtunes’ ‘arena’ ‘irish’ ‘mandopop’ ‘forró’ ‘popdance’ ‘dirty’ |
‘regional’] |
Вывод |
На этапе предобработки в данных обнаружились не только пропуски и проблемы с названиями столбцов, но и всяческие виды дубликатов. Их удаление позволит провести анализ точнее. Поскольку сведения о жанрах важно сохранить для анализа, не просто удаляем все пропущенные значения, но заполним пропущенные имена исполнителей и названия треков. Имена столбцов теперь корректны и удобны для дальнейшей работы. |
Действительно ли музыку в разных городах слушают по-разному? |
Была выдвинута гипотеза, что в Москве и Санкт-Петербурге пользователи слушают музыку по-разному. Проверяем это предположение по данным о трёх днях недели — понедельнике, среде и пятнице. |
Для каждого города устанавливаем количество прослушанных в эти дни композиций с известным жанром, и сравниваем результаты. |
Группируем данные по городу и вызовом метода count() подсчитываем композиции, для которых известен жанр. |
# |
df.groupby(‘city’)[‘genre_name’].count() |
В Москве прослушиваний больше, чем в Питере, но это не значит, что Москва более активна. У Яндекс.Музыки в целом больше пользователей в Москве, поэтому величины сопоставимы. |
Сгруппируем данные по дню недели и подсчитаем прослушанные в понедельник, среду и пятницу композиции, для которых известен жанр. |
# |
df.groupby(‘weekday’)[‘genre_name’].count() |
Понедельник и пятница — время для музыки; по средам пользователи немного больше вовлечены в работу. |
Создаём функцию number_tracks(), которая принимает как параметры таблицу, день недели и название города, а возвращает количество прослушанных композиций, для которых известен жанр. Проверяем количество прослушанных композиций для каждого города и понедельника, затем среды и пятницы. |
# |
# объявляется функция с тремя параметрами: df, day, city |
def number_tracks(df, day, city): |
# в переменной track_list сохраняются те строки таблицы df, для которых |
# значение в столбце ‘weekday’ равно параметру day |
# и одновременно значение в столбце ‘city’ равно параметру city |
track_list=df[(df[‘weekday’]==day) & (df[‘city’]==city)] |
# в переменной track_list_count сохраняется число значений столбца ‘genre_name’, |
# рассчитанное методом count() для таблицы track_list |
track_list_count = track_list[‘genre_name’].count() |
# функция возвращает значение track_list_count |
return track_list_count |
# |
number_tracks(df, ‘Monday’, ‘Moscow’) |
# |
number_tracks(df, ‘Monday’, ‘Saint-Petersburg’) |
# |
number_tracks(df, ‘Wednesday’, ‘Moscow’) |
# |
number_tracks(df, ‘Wednesday’, ‘Saint-Petersburg’) |
# |
number_tracks(df, ‘Friday’, ‘Moscow’) |
# |
number_tracks(df, ‘Friday’, ‘Saint-Petersburg’) |
Сведём полученную информацию в одну таблицу, где [‘city’, ‘monday’, ‘wednesday’, ‘friday’] названия столбцов. |
# |
data = [[‘Moscow’, 15347, 10865, 15680], |
[‘Saint-Petersburg’, 5519, 6913, 5802]] |
columns = [‘city’,’monday’,’wednesday’,’friday’] |
table = pd.DataFrame(data = data, columns = columns) |
table |
Вывод |
Результаты показывают, что относительно среды музыку в Петербурге и Москве слушают «зеркально»: в Москве пики приходятся на понедельник и пятницу, а в среду время прослушивания снижается. Тогда как в Санкт-Петербурге среда — день самого большого интереса к музыке, а в понедельник и пятницу он меньше, причём почти одинаково меньше. |
Утро понедельника и вечер пятницы — разная музыка или одна и та же? |
Ищем ответ на вопрос, какие жанры преобладают в разных городах в понедельник утром и в пятницу вечером. Есть предположение, что в понедельник утром пользователи слушают больше бодрящей музыки (например, жанра поп), а вечером пятницы — больше танцевальных (например, электронику). |
Получим таблицы данных по Москве moscow_general и по Санкт-Петербургу spb_general. |
# получение таблицы moscow_general из тех строк таблицы df, |
# для которых значение в столбце ‘city’ равно ‘Moscow’ |
moscow_general=df[df[‘city’] == ‘Moscow’] |
# |
spb_general=df[df[‘city’]==’Saint-Petersburg’] |
Создаём функцию genre_weekday(), которая возвращает список жанров по запрошенному дню недели и времени суток с такого-то часа по такой-то. |
# объявление функции genre_weekday() с параметрами df, day, time1, time2 |
def genre_weekday(df, day, time1, time2): |
# в переменной genre_list сохраняются те строки df, для которых одновременно: |
# 1) значение в столбце ‘weekday’ равно параметру day, |
# 2) значение в столбце ‘time’ больше time1 и |
# 3) меньше time2. |
genre_list=df[(df[‘weekday’]==day) & (df[‘time’]>time1)& (df[‘time’] |
genre_weekday(moscow_general, ‘Monday’, ’07:00:00′, ’11:00:00′) |
# |
genre_weekday(spb_general, ‘Monday’, ’07:00:00′, ’11:00:00′) |
# |
genre_weekday(moscow_general, ‘Friday’, ’17:00:00′, ’23:00:00′) |
# |
genre_weekday(spb_general, ‘Friday’, ’17:00:00′, ’23:00:00′) |
# |
genre_weekday(spb_general, ‘Friday’, ’17:00:00′, ’23:00:00′) |
Популярные жанры в понедельник утром в Питере и Москве оказались похожи: везде, как и предполагалось, популярен поп. Несмотря на это, концовка топ-10 для двух городов различается: в Питере в топ-10 входит джаз и русский рэп, а в Москве жанр world. |
В конце недели ситуация не меняется. Поп-музыка всё так же на первом месте. Опять разница заметна только в концовке топ-10, где в Питере пятничным вечером тоже присутствует жанр world. |
Вывод |
Жанр поп безусловный лидер, а топ-5 в целом не различается в обеих столицах. При этом видно, что концовка списка более «живая»: для каждого города выделяются более характерные жанры, которые действительно меняют свои позиции в зависимости от дня недели и времени. |
Москва и Питер — две разные столицы, два разных направления в музыке. Правда? |
Гипотеза: Питер богат своей рэп-культурой, поэтому это направление там слушают чаще, а Москва — город контрастов, но основная масса пользователей слушает попсу. |
Сгруппируем таблицу moscow_general по жанру, сосчитаем численность композиций каждого жанра методом count(), отсортируем в порядке убывания и сохраним результат в таблице moscow_genres. |
Просмотрим первые 10 строк этой новой таблицы. |
# одной строкой: группировка таблицы moscow_general по столбцу ‘genre_name’, |
# подсчёт числа значений ‘genre_name’ в этой группировке методом count(), |
# сортировка Series в порядке убывания и сохранение в moscow_genres |
moscow_genres=moscow_general.groupby(‘genre_name’)[‘genre_name’].count().sort_values(ascending = False) |
# |
moscow_genres.head(10) |
Сгруппируем таблицу spb_general по жанру, сосчитаем численность композиций каждого жанра методом count(), отсортируем в порядке убывания и сохраним результат в таблице spb_genres. |
Просматриваем первые 10 строк этой таблицы. Теперь можно сравнивать два города. |
# |
spb_genres=spb_general.groupby(‘genre_name’)[‘genre_name’].count().sort_values(ascending=False) |
# |
spb_genres.head(10) |
Вывод |
В Москве, кроме абсолютно популярного жанра поп, есть направление русской популярной музыки. Значит, что интерес к этому жанру шире. А рэп, вопреки предположению, занимает в обоих городах близкие позиции. |
Этап 4. Результаты исследования |
Рабочие гипотезы: |
музыку в двух городах — Москве и Санкт-Петербурге — слушают в разном режиме; |
списки десяти самых популярных жанров утром в понедельник и вечером в пятницу имеют характерные отличия; |
население двух городов предпочитает разные музыкальные жанры. |
Общие результаты |
Москва и Петербург сходятся во вкусах: везде преобладает популярная музыка. При этом зависимости предпочтений от дня недели в каждом отдельном городе нет — люди постоянно слушают то, что им нравится. Но между городами в разрезе дней неделей наблюдается зеркальность относительно среды: Москва больше слушает в понедельник и пятницу, а Петербург наоборот — больше в среду, но меньше в понедельник и пятницу. |
В результате первая гипотеза , вторая гипотеза и третья . |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Самостоятельный проект — это практическая проверка знаний, приобретённых вами на вводном курсе. Каждый раздел посвящён отдельной стадии анализа данных с экскурсом в основы Python. Ещё эту работу можно добавить в портфолио. Вы начинаете собирать это портфолио прямо сейчас. |
Проект выполняется в пять этапов: |
Постановка задачи |
Получение данных |
Предобработка данных |
Анализ данных |
Оформление результатов |
Для каждой части описаны шаги выполнения c теоретическим приложением. В Jupyter Notebook эти шаги связаны между собой выводами и результатами. |
Вы закрепите применение операторов и методов языка Python (и его библиотеки Pandas) на разных стадиях анализа данных. Кроме того, получите первый опыт оформления в Jupyter Notebook проекта, которым можно поделиться. |
Если возникнут сложности, всегда можно воспользоваться навигацией по пройденным урокам, а также шпаргалками. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Источник