Last active
July 27, 2023 23:35
-
-
Save dsibi/3c78e6cbddf8fdde2681740124268c71 to your computer and use it in GitHub Desktop.
yandex_python_data_analyst_7_Анализ данных и оформление результатов
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,5 часа = 5 уроков от 1 до 25 минут. | |
Постановка задачи | |
Завершаем анализ данных Яндекс.Музыки, выполняем поставленную менеджером задачу и сдаём отчёт. |
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
Идею объединения сервисов Музыка и Радио тестировали на небольшой группе пользователей. Результаты сведены в csv-файл, который вам предстоит изучить. Итог анализа таких данных — это метрики: величины, значения которых отражают пользовательские впечатления. Одна из важнейших — happiness. Здесь это среднее время, которое пользователь слушает музыку в течение выбранного периода времени (в нашей задаче — за сутки). Чем дольше пользователь слушает музыку, тем он довольнее. Ваша задача: найти значение happiness и посмотреть, как оно поменялось с прошлого эксперимента. | |
В анализе данных важно наглядное представление результатов, чтобы их мог оценить заказчик. Это бизнес, где на кону громадный трафик, серверные мощности, личное время многотысячной аудитории. И одновременно это исследование. Как в настоящей экспериментальной науке, ответ непредсказуем. Его точность зависит от умелого владения статистическими методами и от качества исходных данных. Перед тем, как начинать считать, проверьте, грамотно ли ваши данные подготовлены. | |
Ознакомление с данными: в предыдущих сериях. | |
Перед тем, как браться за статистику, нужно: | |
1. Прочесть исходный файл и превратить его в структуру данных | |
К заданию прилагается файл в формате csv, где все значения разделены запятыми. Это наши исходные данные. Чтобы применить к ним все возможности языка Python и библиотеки Pandas, надо импортировать эту библиотеку и сохранить её в переменной. По сокращённому названию панельных данных (panel data), с которых начиналась Pandas, эту переменную принято называть pd: | |
import pandas as pd | |
Для чтения csv-файла в библиотеке Pandas есть готовая функция — метод read_csv(). Как и все методы, он вызывается записью через точку после имени своего объекта. В скобках указывается аргумент (параметр) метода. У read_csv() это имя файла с данными. Прочтение превращает файл в структуру данных DataFrame. Имя переменной, в которой эта структура данных сохраняется, чаще всего df либо отражает тематику данных: | |
df = pd.read_csv('music_log.csv') | |
2. Посмотреть на данные | |
Вывести на экран таблицу и оценить данные: | |
print(df) | |
Как правило, таблица очень велика. Практичнее запросить определённое количество первых строк, методом head(): | |
print(df.head(15)) # выведет первые 15 строк таблицы | |
3. Оценить качество предподготовки | |
Нужно убедиться в том, что данные прошли предподготовку. По крайней мере, не должно быть пропусков и повторов. Пропущенные и неопределённые значения выявляет метод isna(), а суммарное количество таких значений — метод sum(). Обратите внимание: мы записали вызов обоих методов в одну строку, разделив их точкой. Python сначала вызовет метод isna(), а затем результаты его работы передаст методу sum(). | |
print(df.isna().sum()) | |
Повторяющиеся строки — дубликаты — выявляются методом duplicated() и подсчитываются тем же sum(): | |
print(df.duplicated().sum()) | |
Если возвращаются нули, всё хорошо — данные пригодны для исследования. | |
TASK_1_4 | |
Прочитайте данные из файла music_log_upd.csv и выведите первые 10 строк. | |
music_log_upd.csv — обновлённый файл с данными, которые прошли предобработку в предыдущей теме. | |
SOLUTION | |
import pandas as pd | |
df = pd.read_csv('music_log_upd.csv') | |
print(df.head(10)) | |
TASK_2_4 | |
Получите список названий столбцов, запросив атрибут columns. Результат выведите на экран. | |
SOLUTION | |
import pandas as pd | |
df = pd.read_csv('music_log_upd.csv') | |
print(df.columns) | |
TASK_3_4 | |
Посчитайте количество пустых значений в наборе данных, сохраните результат в переменной na_number. Выведите её значение на экран. | |
SOLUTION | |
import pandas as pd | |
df = pd.read_csv('music_log_upd.csv') | |
na_number=(df.isna().sum()) | |
print(na_number) | |
TASK_4_4 | |
Посчитайте количество дубликатов в наборе данных, сохраните результат в переменной duplicated_number. Выведите её значение на экран. | |
SOLUTION | |
import pandas as pd | |
df = pd.read_csv('music_log_upd.csv') | |
duplicated_number=df.duplicated().sum() | |
print(duplicated_number) |
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
Слово «анализ» означает разбор, рассмотрение с разных сторон. Анализ данных начинают с разделения их на группы по какому-нибудь признаку. Эта операция называется группировка данных. Она помогает изучить материал более подробно, чтобы затем перейти к поиску взаимосвязей между отдельными группами. | |
Группировка оправданна, если данные чётко делятся по значимому признаку, а полученные группы близки к теме задачи. Например, когда есть данные обо всех покупках в супермаркете, можно смело заниматься группировкой. Так можно установить время наплыва покупателей и решить проблему пиковых нагрузок. Или посчитать средний чек — обычно для магазинов это ключевая метрика. | |
Стадии группировки хорошо укладываются в словесную формулу split-apply-combine: | |
разделить, split — разбиение на группы по определённому критерию; | |
применить, apply — применение какого-либо метода к каждой группе в отдельности, например, подсчёт численности группы методом count() или суммирование вызовом sum(); | |
объединить, combine — сведение результатов в новую структуру данных, в зависимости от условий разделения и выполнения метода это бывает DataFrame и Series. | |
В библиотеке Pandas есть отличные инструменты группировки. Рассмотрим обращение с ними на примере анализа данных о планетах за пределами Солнечной системы, или экзопланетах. Орбитальные обсерватории засекли уже тысячи таких небесных тел. Их выявляют на снимках космических телескопов наши коллеги, аналитики данных. Поищем среди экзопланет похожие на Землю. Возможно, это наши будущие колонии, или там уже обитают разумные существа, с которыми однажды предстоит установить контакт. | |
DataFrame с данными по нескольким тысячам экзопланет сохранён в переменной exoplanet. Посмотрим на первые 30 строк таблицы: | |
print(exoplanet.head(30)) | |
NAME MASS RADIUS DISCOVERED | |
0 1RXS 1609 b 14 19.04 2008 | |
1 2M 0122-24 b 20 11.2 2013 | |
2 2M 0219-39 b 13.9 16.128 2015 | |
3 2M 0746+20 b 12.21 10.864 2010 | |
4 2M 2140+16 b 20 10.304 2010 | |
5 2M 2206-20 b 30 14.56 2010 | |
6 51 Eri b 9.1 12.432 2015 | |
7 51 Peg b 0.47 21.28 1995 | |
8 55 Cnc e 0.02703 1.94544 2004 | |
9 BD+20 594 b 0.0513 2.2288 2016 | |
10 BD-10 3166 b 0.46 11.536 2000 | |
11 CT Cha b 17 24.64 2008 | |
12 CVSO 30 b 6.2 21.392 2012 | |
13 CoRoT-1 b 1.03 16.688 2007 | |
14 CoRoT-10 b 2.75 10.864 2010 | |
15 CoRoT-11 b 2.33 16.016 2010 | |
16 CoRoT-12 b 0.917 16.128 2010 | |
17 CoRoT-13 b 1.308 9.912 2010 | |
18 CoRoT-14 b 7.6 12.208 2010 | |
19 CoRoT-15 b 63.4 12.544 2010 | |
20 CoRoT-16 b 0.535 13.104 2010 | |
21 CoRoT-17 b 2.43 11.424 2010 | |
22 CoRoT-18 b 3.47 14.672 2011 | |
23 CoRoT-19 b 1.11 14.448 2011 | |
24 CoRoT-2 b 3.31 16.408 2007 | |
25 CoRoT-20 b 4.24 9.408 2011 | |
26 CoRoT-21 b 2.26 14.56 2011 | |
27 CoRoT-22 b 0.06 4.87648 2011 | |
28 CoRoT-23 b 2.8 12.096 2011 | |
29 CoRoT-24 b 0.018 3.696 2011 | |
Документация | |
Столбцы: | |
name: название экзопланеты; | |
mass: масса в массах планеты Юпитер; | |
radius: радиус, пересчитанный в радиусах Земли; | |
discovered: год открытия экзопланеты. | |
Источник: каталог экзопланет на портале exoplanet.eu | |
На картинке изображен принцип split-apply-combine для таблицы с экзопланетами. Посмотрим, как вообще идут дела с поиском экзопланет. Сначала данные делят по группам, где каждая группа — это год. Потом метод count() подсчитывает численность каждой группы. В итоге получаем новую структуру данных с группами, где каждая содержит год и число открытых за этот год экзопланет. | |
image | |
В Рandas для группировки данных есть метод groupby(). Он принимает как аргумент название столбца, по которому нужно группировать. В случае с делением экзопланет по годам открытия: | |
print(exoplanet.groupby('discovered')) | |
<pandas.core.groupby.DataFrameGroupBy object at 0x7fc1e1ca3400> | |
Применение метода groupby() к объекту типа DataFrame приводит к созданию объекта особого типа — DataFrameGroupBy. Это сгруппированные данные. Если применить к ним какой-нибудь метод Pandas, они станут новой структурой данных типа DataFrame или Series. | |
Подсчитаем сгруппированные по годам экзопланеты методом count(): | |
print(exoplanet.groupby('discovered').count()) | |
DISCOVERED NAME MASS RADIUS | |
1995 1 1 1 | |
1996 1 1 1 | |
1999 2 2 2 | |
2000 5 5 5 | |
2001 1 1 1 | |
2002 4 4 4 | |
2004 10 10 10 | |
2005 9 9 9 | |
2006 11 11 11 | |
2007 23 23 23 | |
2008 23 23 23 | |
2009 12 12 12 | |
2010 59 59 59 | |
2011 87 87 87 | |
2012 93 93 93 | |
2013 98 98 98 | |
2014 73 73 73 | |
2015 56 56 56 | |
2016 84 84 84 | |
2017 54 54 54 | |
2018 101 101 101 | |
2019 2 2 2 | |
Результат выполнения кода exoplanet.groupby('discovered').count() — это уже новая структура данных, типа DataFrame. И с первого взгляда на этот DataFrame заметна тенденция: количество открытых экзопланет почти ежегодно растёт. | |
Если нужно сравнить наблюдения по одному показателю, метод применяют к DataFrameGroupBy с указанием на один столбец. Нас в первую очередь интересует радиус экзопланет: мы ищем другую Землю. Давайте получим таблицу с единственным столбцом 'radius': | |
exo_number = exoplanet.groupby('discovered')['radius'].count() | |
print(exo_number) | |
DISCOVERED | |
1995 1 | |
1996 1 | |
1999 2 | |
2000 5 | |
2001 1 | |
2002 4 | |
2004 10 | |
2005 9 | |
2006 11 | |
2007 23 | |
2008 23 | |
2009 12 | |
2010 59 | |
2011 87 | |
2012 93 | |
2013 98 | |
2014 73 | |
2015 56 | |
2016 84 | |
2017 54 | |
2018 101 | |
2019 2 | |
Name: radius, dtype: int64 | |
Получили Series, где по годам открытия расписано количество экзопланет, для которых удалось установить радиус. | |
Посмотрим, как меняется средний радиус открытых экзопланет год от года. Для этого надо сложить радиусы планет, открытых за определённый год, и поделить на их количество (которое мы уже нашли). | |
Сумма радиусов считается методом sum(): | |
exo_radius_sum = exoplanet.groupby('discovered')['radius'].sum() | |
print(exo_radius_sum) | |
DISCOVERED | |
1995 21.280000 | |
1996 11.872000 | |
1999 26.992000 | |
2000 57.198400 | |
2001 10.315200 | |
2002 47.152000 | |
2004 110.988640 | |
2005 111.059200 | |
2006 246.568000 | |
2007 325.908800 | |
2008 350.884800 | |
2009 130.959289 | |
2010 723.900182 | |
2011 917.345484 | |
2012 707.924857 | |
2013 705.458700 | |
2014 554.762932 | |
2015 563.962784 | |
2016 971.348000 | |
2017 504.473312 | |
2018 994.195820 | |
2019 14.324800 | |
Name: radius, dtype: float64 | |
Очень кстати, что объекты Series можно делить друг на друга. Это позволит нам разделить перечень сумм радиусов на перечень количеств экзопланет без перебора в цикле: | |
exo_radius_mean = exo_radius_sum/exo_number | |
print(exo_radius_mean) | |
DISCOVERED | |
1995 21.280000 | |
1996 11.872000 | |
1999 13.496000 | |
2000 11.439680 | |
2001 10.315200 | |
2002 11.788000 | |
2004 11.098864 | |
2005 12.339911 | |
2006 22.415273 | |
2007 14.169948 | |
2008 15.255861 | |
2009 10.913274 | |
2010 12.269495 | |
2011 10.544201 | |
2012 7.612095 | |
2013 7.198558 | |
2014 7.599492 | |
2015 10.070764 | |
2016 11.563667 | |
2017 9.342098 | |
2018 9.843523 | |
2019 7.162400 | |
Name: radius, dtype: float64 | |
Точность наших приборов растёт, и новые экзопланеты по размерам всё ближе к Земле. За 24 года средний радиус обнаруженных планет снизился втрое. | |
Тем же методом groupby(), которым мы ищем новую Землю, можно поискать и необыкновенного человека в данных Яндекс.Музыки. Тем более, что без этого не выполнить поставленной менеджером задачи. | |
Прежде, чем рассчитывать метрику happiness, нужно изучить пользователей, чьё «счастье» мы собираемся оценить. Какие они, эти люди, которые слушают действительно много музыки? Есть ли у них особые предпочтения, или они потребляют всё подряд? | |
TASK_1_3 | |
Меломаны у нас есть. Сейчас узнаем идентификатор user_id одного из них. Для этого сгруппируем данные по каждому пользователю, чтобы собрать жанры прослушанных им композиций. | |
Сгруппируйте DataFrame по столбцу user_id, сохраните полученный результат в переменной genre_grouping. | |
Посчитайте количество жанров, которые выбрали пользователи, методом count(), указав, что выбираем один столбец genre_name. Сохраните результат в переменной genre_counting и выведите первые 30 строк этой таблицы. | |
SOLUTION | |
import pandas as pd | |
df = pd.read_csv('music_log_upd.csv') | |
genre_grouping=df.groupby("user_id") | |
genre_counting=genre_grouping['genre_name'].count() | |
print(genre_counting.head(30)) | |
TASK_2_3 | |
Быть может, те, кто за день слушает больше 50 песен, имеют более широкие предпочтения. Чтобы найти такого, изготовим универсальный инструмент. | |
Напишите функцию user_genres, которая принимает некую группировку как свой аргумент group. Функция должна перебирать группы, входящие в эту группировку. | |
В каждой группе два элемента — имя группы с индексом 0 и список значений с индексом 1. | |
Обнаружив такую группу, в которой список (элемент с индексом 1) содержит более 50 значений, функция возвращает имя группы (значение элемента с индексом 0). | |
SOLUTION | |
import pandas as pd | |
df = pd.read_csv('music_log_upd.csv') | |
def user_genres(group): | |
for col in group: | |
if len(col[1]) > 50:# назначьте условие: если длина столбца col с индексом 1 больше 50, тогда | |
user = col[0]# в переменной user сохраняется элемент col[0] | |
return user | |
TASK_3_3 | |
Вызовите функцию user_genres, как аргумент передайте ей genre_grouping. Результат – user_id неведомого нам любителя музыки – сохраните в переменной search_id и выведите значение на экран. | |
SOLUTION | |
import pandas as pd | |
df = pd.read_csv('music_log_upd.csv') | |
genre_grouping = df.groupby('user_id')['genre_name'] | |
#print(genre_grouping.head(30)) | |
def user_genres(group): | |
for col in group: | |
if len(col[1]) > 50: | |
user = col[0] | |
return user | |
search_id=user_genres(genre_grouping) | |
print(search_id) |
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
Поиск необычного в группе — что среди планет, что среди меломанов — это прежде всего поиск чемпионов: объектов с выдающимися показателями по разным статьям. Как всю таблицу, так и отдельные группы изучают, сортируя строки по какому-либо столбцу. В Pandas для этой операции есть метод sort_values(). У него два аргумента: | |
• by = 'имя столбца' — имя столбца, по которому нужно сортировать; | |
• ascending: по умолчанию True. Для сортировки по убыванию установите значение False. | |
image | |
Этот аргумент уже знаком вам по аналогичному методу sort() в языке Python. | |
Среди экзопланет интересны близкие по размерам к Земле. Есть ли такие? Отсортируем список по радиусу в порядке возрастания. Тогда в голове таблицы окажутся самые малые, на которых гравитация не прижмёт нас к полу. | |
print(exoplanet.sort_values(by = 'radius').head(30)) | |
NAME MASS RADIUS DISCOVERED | |
469 Kepler-37 b 0.00875 0.3192 2013 | |
359 Kepler-102 b 0.0013 0.4704 2014 | |
541 Kepler-62 c 0.0126 0.5376 2013 | |
490 Kepler-42 d 0.003 0.5712 2012 | |
390 Kepler-138 b 0.00021 0.5824 2014 | |
360 Kepler-102 c 0.009 0.5824 2013 | |
489 Kepler-42 c 0.006 0.728 2012 | |
470 Kepler-37 c 0.031463 0.749399 2013 | |
552 Kepler-70 b 0.014 0.7616 2011 | |
625 TRAPPIST-1 d 0.0013 0.77168 2016 | |
488 Kepler-42 b 0.009 0.784 2012 | |
481 Kepler-408 b 0.02 0.8176 2013 | |
367 Kepler-106 b 0.00047 0.8176 2014 | |
389 Kepler-131 c 0.026 0.84 2014 | |
346 KIC 12557548 b 6.3e-05 0.849319 2012 | |
479 Kepler-406 c 0.00853 0.8512 2014 | |
417 Kepler-20 e 0.0097 0.86464 2011 | |
553 Kepler-70 c 0.0021 0.8736 2011 | |
363 Kepler-102 f 0.002 0.8848 2013 | |
288 K2-137 b 0.7 0.8848 2017 | |
626 TRAPPIST-1 e 0.002 0.91728 2017 | |
550 Kepler-68 c 0.00686 0.92624 2013 | |
369 Kepler-106 d 0.025 0.952 2014 | |
64 EPIC 248545986 c 0.0028 0.9968 2018 | |
418 Kepler-20 f 0.045 1.00218 2011 | |
627 TRAPPIST-1 f 0.0021 1.04418 2017 | |
624 TRAPPIST-1 c 0.00434 1.05515 2016 | |
350 KOI-2700 b 0.00271 1.05952 2013 | |
623 TRAPPIST-1 b 0.0027 1.08517 2016 | |
534 Kepler-59 b 2.05 1.0976 2012 | |
Оказывается, некоторые из уже открытых экзопланет по размерам близки не то что к Земле, но уже и к Луне! Получим список экзопланет с радиусом меньше земного. Смотрите, как логический оператор (здесь это <) задействуется в отборе элементов столбца. Дальше нам этот приём не раз понадобится. | |
print(exoplanet[exoplanet['radius'] < 1]) | |
NAME MASS RADIUS DISCOVERED | |
64 EPIC 248545986 c 0.0028 0.9968 2018 | |
288 K2-137 b 0.7 0.8848 2017 | |
346 KIC 12557548 b 6.3e-05 0.849319 2012 | |
359 Kepler-102 b 0.0013 0.4704 2014 | |
360 Kepler-102 c 0.009 0.5824 2013 | |
363 Kepler-102 f 0.002 0.8848 2013 | |
367 Kepler-106 b 0.00047 0.8176 2014 | |
369 Kepler-106 d 0.025 0.952 2014 | |
389 Kepler-131 c 0.026 0.84 2014 | |
390 Kepler-138 b 0.00021 0.5824 2014 | |
417 Kepler-20 e 0.0097 0.86464 2011 | |
469 Kepler-37 b 0.00875 0.3192 2013 | |
470 Kepler-37 c 0.031463 0.749399 2013 | |
479 Kepler-406 c 0.00853 0.8512 2014 | |
481 Kepler-408 b 0.02 0.8176 2013 | |
488 Kepler-42 b 0.009 0.784 2012 | |
489 Kepler-42 c 0.006 0.728 2012 | |
490 Kepler-42 d 0.003 0.5712 2012 | |
541 Kepler-62 c 0.0126 0.5376 2013 | |
550 Kepler-68 c 0.00686 0.92624 2013 | |
552 Kepler-70 b 0.014 0.7616 2011 | |
553 Kepler-70 c 0.0021 0.8736 2011 | |
625 TRAPPIST-1 d 0.0013 0.77168 2016 | |
626 TRAPPIST-1 e 0.002 0.91728 2017 | |
Но и этот список такой длинный, что изучать его лучше по частям. Экзопланеты, близкие по размерам к Земле, за последнее десятилетие открывали нередко. Можно изучать список открытых за каждый год. Например, для 2014 года (вновь обратите внимание на работу логического оператора, теперь это ==): | |
print(exoplanet[exoplanet['discovered'] == 2014]) | |
NAME MASS RADIUS DISCOVERED | |
83 GU Psc b 11.00000 15.120000 2014 | |
127 HAT-P-49 b 1.73000 15.825600 2014 | |
133 HAT-P-54 b 0.76000 10.572800 2014 | |
150 HATS-15 b 2.17000 12.376000 2014 | |
175 HATS-4 b 1.32300 11.424000 2014 | |
183 HATS-5 b 0.23700 10.214400 2014 | |
194 HATS-6 b 0.31900 11.177600 2014 | |
213 HD 114613 b 0.35700 13.238400 2014 | |
274 HIP 116454 b 0.03720 2.531200 2014 | |
347 KOI-188 b 0.25000 10.953600 2014 | |
348 KOI-192 b 0.29000 13.776000 2014 | |
349 KOI-195 b 0.34000 12.208000 2014 | |
352 KOI-830 b 1.27000 12.096000 2014 | |
356 Kepler-100 b 0.02310 1.303680 2014 | |
357 Kepler-100 c 0.00270 2.218720 2014 | |
358 Kepler-100 d 0.00940 1.513120 2014 | |
359 Kepler-102 b 0.00130 0.470400 2014 | |
361 Kepler-102 d 0.00820 1.164800 2014 | |
364 Kepler-103 b 0.03100 3.473120 2014 | |
365 Kepler-103 c 0.11400 5.314400 2014 | |
366 Kepler-105 c 0.01400 1.310400 2014 | |
367 Kepler-106 b 0.00047 0.817600 2014 | |
368 Kepler-106 c 0.03285 2.497600 2014 | |
369 Kepler-106 d 0.02500 0.952000 2014 | |
370 Kepler-106 e 0.03514 2.553600 2014 | |
371 Kepler-109 b 0.00410 2.336320 2014 | |
372 Kepler-109 c 0.00698 2.632000 2014 | |
379 Kepler-113 b 0.03680 1.814400 2014 | |
380 Kepler-113 c 0.02700 2.172800 2014 | |
388 Kepler-131 b 0.05075 2.408000 2014 | |
... ... ... ... ... | |
480 Kepler-407 b 0.01000 1.163680 2014 | |
484 Kepler-412 b 0.93900 14.840000 2014 | |
486 Kepler-418 b 1.10000 13.440000 2014 | |
491 Kepler-420 A b 1.45000 10.528000 2014 | |
492 Kepler-422 b 0.43000 12.880000 2014 | |
493 Kepler-423 b 0.59500 13.350400 2014 | |
494 Kepler-424 b 1.03000 9.968000 2014 | |
496 Kepler-432 b 5.41000 16.240000 2014 | |
510 Kepler-453 (AB) b 0.03000 6.160000 2014 | |
515 Kepler-48 d 0.02500 2.038400 2014 | |
522 Kepler-51 d 0.02390 9.688000 2014 | |
583 Kepler-93 b 0.01260 1.481812 2014 | |
584 Kepler-94 b 0.03411 3.505600 2014 | |
585 Kepler-95 b 0.04100 3.416000 2014 | |
586 Kepler-96 b 0.02700 2.665600 2014 | |
641 WASP-103 b 1.49000 17.113600 2014 | |
642 WASP-104 b 1.27200 12.734400 2014 | |
644 WASP-106 b 1.92500 12.152000 2014 | |
646 WASP-108 b 1.16700 13.608000 2014 | |
647 WASP-109 b 0.91000 16.161600 2014 | |
648 WASP-110 b 0.51500 13.865600 2014 | |
649 WASP-111 b 1.85000 16.150400 2014 | |
650 WASP-112 b 0.88000 13.339200 2014 | |
653 WASP-117 b 0.27550 11.435200 2014 | |
768 WASP-74 b 0.97000 17.472000 2014 | |
778 WASP-83 b 0.30000 11.648000 2014 | |
780 WASP-85 A b 1.26500 13.888000 2014 | |
782 WASP-87 A b 2.21000 15.512000 2014 | |
784 WASP-89 b 5.90000 11.648000 2014 | |
789 WASP-94 A b 0.45200 19.264000 2014 | |
А чтобы не тратить время на лишнее, поставим оба условия сразу. Для этого в Pandas есть логический оператор &, подобный оператору and языка Python. Напомним, его смысл на русском языке можно передать словами «и ещё»: | |
# экзопланеты меньше Земли __ и ещё __ открытые в 2014 году | |
exo_small_14 = exoplanet[ (exoplanet['radius']<1) & (exoplanet['discovered']==2014)] | |
print(exo_small_14) | |
NAME MASS RADIUS DISCOVERED | |
359 Kepler-102 b 0.00130 0.4704 2014 | |
367 Kepler-106 b 0.00047 0.8176 2014 | |
369 Kepler-106 d 0.02500 0.9520 2014 | |
389 Kepler-131 c 0.02600 0.8400 2014 | |
390 Kepler-138 b 0.00021 0.5824 2014 | |
479 Kepler-406 c 0.00853 0.8512 2014 | |
Отсортируем результат в порядке убывания радиуса. | |
print(exo_small_14.sort_values(by = 'radius', ascending = False)) | |
NAME MASS RADIUS DISCOVERED | |
369 Kepler-106 d 0.025 0.952 2014 | |
479 Kepler-406 c 0.00853 0.8512 2014 | |
389 Kepler-131 c 0.026 0.84 2014 | |
367 Kepler-106 b 0.00047 0.8176 2014 | |
390 Kepler-138 b 0.00021 0.5824 2014 | |
359 Kepler-102 b 0.0013 0.4704 2014 | |
Самая крупная планета, Kepler 106 d – почти как Земля, вращается вокруг звезды Kepler 106 в созвездии Лебедя. Эта звезда очень похожа на наше Солнце. Правда, до неё 1435 световых лет — далековато. Но, возможно, учёные что-нибудь придумают. А мы пока применим эту технологию к нашему бизнесу, в «приземлённой» задаче. | |
TASK_1_5 | |
Космический телескоп Kepler открыл похожую на Землю планету у похожей на Солнце звезды. А вы в данных Яндекс.Музыки обнаружили меломана с уникальными данными. Он за день послушал больше 50 композиций. | |
Получите таблицу с прослушанными им треками. | |
Для этого запросите из структуры данных df строки, отвечающие сразу двум условиям: | |
1) значение в столбце 'user_id' должно быть равно значению переменной search_id; | |
2) время прослушивания, т.е. значение в столбце 'total_play_seconds', не должно равняться 0. | |
Сохраните результат в переменной music_user. | |
SOLUTION | |
import pandas as pd | |
df = pd.read_csv('music_log_upd.csv') | |
genre_grouping = df.groupby('user_id')['genre_name'] | |
def user_genres(group): | |
for col in group: | |
if len(col[1]) > 50: | |
user = col[0] | |
return user | |
search_id = user_genres(genre_grouping) | |
music_user=df[(df['user_id']==search_id)&(df["total_play_seconds"]!=0)] | |
print(music_user) | |
TASK_2_5 | |
Теперь узнаем, сколько времени он слушал музыку каждого жанра. | |
Сгруппируйте данные таблицы music_user по столбцу 'genre_name' и получите сумму значений столбца 'total_play_seconds'. Сохраните результат в переменной sum_music_user и выведите её значение на экран. | |
SOLUTION | |
import pandas as pd | |
df = pd.read_csv('music_log_upd.csv') | |
genre_grouping = df.groupby('user_id')['genre_name'] | |
def user_genres(group): | |
for col in group: | |
if len(col[1]) > 50: | |
user = col[0] | |
return user | |
search_id = user_genres(genre_grouping) | |
music_user=df[(df['user_id']==search_id)&(df["total_play_seconds"]!=0)] | |
#print(music_user) | |
sum_music_user=music_user.groupby("genre_name")['total_play_seconds'].sum() | |
print(sum_music_user) | |
TASK_3_5 | |
Кажется, предпочтения нашего меломана начинают проявляться. Но, возможно, длительность композиций от жанра к жанру сильно различается. Важно знать, сколько треков каждого жанра он включил. | |
Сгруппируйте данные по столбцу genre_name и посчитайте, сколько значений в столбце genre_name. Сохраните результат в переменной count_music_user и выведите её значение на экран. | |
Чтобы команда «распечатать сумму» из прошлой задачи не мешала рассматривать новое решение, закомментируйте её. | |
SOLUTION | |
import pandas as pd | |
df = pd.read_csv('music_log_upd.csv') | |
genre_grouping = df.groupby('user_id')['genre_name'] | |
def user_genres(group): | |
for col in group: | |
if len(col[1]) > 50: | |
user = col[0] | |
return user | |
search_id = user_genres(genre_grouping) | |
music_user=df[(df['user_id']==search_id)&(df["total_play_seconds"]!=0)] | |
#print(music_user) | |
sum_music_user=music_user.groupby("genre_name")['total_play_seconds'].sum() | |
#print(sum_music_user) | |
count_music_user=music_user.groupby("genre_name")['genre_name'].count() | |
print(count_music_user) | |
TASK_4_5 | |
Чтобы предпочтения были видны сразу, нужно крупнейшие значения расположить наверху. Отсортируйте данные в группировке sum_music_user по убыванию. Внимание: когда применяете метод sort_values() к Series с единственным столбцом, аргумент by указывать не нужно, только порядок сортировки. | |
Сохраните результат в переменной final_sum и выведите её значение на экран. | |
Команду «распечатать сумму» из прошлой задачи закомментируйте. | |
SOLUTION | |
import pandas as pd | |
df = pd.read_csv('music_log_upd.csv') | |
genre_grouping = df.groupby('user_id')['genre_name'] | |
def user_genres(group): | |
for col in group: | |
if len(col[1]) > 50: | |
user = col[0] | |
return user | |
search_id = user_genres(genre_grouping) | |
music_user=df[(df['user_id']==search_id)&(df["total_play_seconds"]!=0)] | |
#print(music_user) | |
sum_music_user=music_user.groupby("genre_name")['total_play_seconds'].sum() | |
#print(sum_music_user) | |
count_music_user=music_user.groupby("genre_name")['genre_name'].count() | |
#print(count_music_user) | |
final_sum=sum_music_user.sort_values(ascending=False) | |
print(final_sum) | |
TASK_5_5 | |
Теперь то же самое надо сделать с числом прослушанных меломаном композиций. Отсортируйте данные группировки count_music_user по убыванию. Сохраните результат в переменной final_count, значение которой выведите на экран. | |
Команду «распечатать» из прошлой задачи закомментируйте. | |
SOLUTION | |
import pandas as pd | |
df = pd.read_csv('music_log_upd.csv') | |
genre_grouping = df.groupby('user_id')['genre_name'] | |
def user_genres(group): | |
for col in group: | |
if len(col[1]) > 50: | |
user = col[0] | |
return user | |
search_id = user_genres(genre_grouping) | |
music_user=df[(df['user_id']==search_id)&(df["total_play_seconds"]!=0)] | |
#print(music_user) | |
sum_music_user=music_user.groupby("genre_name")['total_play_seconds'].sum() | |
#print(sum_music_user) | |
count_music_user=music_user.groupby("genre_name")['genre_name'].count() | |
#print(count_music_user) | |
final_sum=sum_music_user.sort_values(ascending=False) | |
#print(final_sum) | |
final_count=count_music_user.sort_values(ascending=False) | |
print(final_count) |
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
Меломан оказался таким же последовательным поклонником определённых жанров, как и те, кому хватает пяти композиций в день (исследования на остальных меломанах это подтверждают). Значит, по своим вкусам и поведению наша аудитория однородна, оценивать её «счастье» можно показателями «середнячков». Чтобы представить себе среднестатистического пользователя, понадобится описательная статистика. | |
Из её показателей для количественного описания данных в нашей простой задаче нужны четыре меры — максимум, минимум, медиана и среднее. | |
Наибольшее и наименьшее обычно вычисляют только по одному признаку. Например, можно получить минимальное и максимальное значение количества прослушанных секунд композиции (столбец 'total_play_seconds'). Для поиска максимума вызывают метод max(): | |
print(df['total_play_seconds'].max()) | |
4707.422018 | |
Самый длинный трек звучал почти полтора часа. Интересно, какую композицию слушали так долго. | |
Запросим из df строку с максимальным значением, прибегнув к логической индексации с условием df['total_play_seconds'] == df['total_play_seconds'].max(): | |
print(df[df['total_play_seconds'] == df['total_play_seconds'].max()]) | |
USER_ID TOTAL_PLAY_SECONDS ARTIST_NAME GENRE_NAME TRACK_NAME | |
22181 87B5F115 4707.42 Mishary Rashid Al-Afassy world Alaraf | |
Минимальное значение — самый короткий трек — ищут методом min(). Понятно, что в Яндекс.Музыке показателей меньше нуля не бывает: если пользователь пролистнул трек, значение 'total_play_seconds' равно 0. Нам интересно установить композиции, которые слушали хоть и недолго, но не пропустили сразу. | |
Вот как мы создаём выборку без пропущенных треков и находим в ней минимальное значение: | |
df_min = df[df['total_play_seconds'] != 0] | |
print(df_min['total_play_seconds'].min()) | |
0.000794 | |
Получим названия композиции, которую пропустили быстрее всего. Как и при поиске максимума, воспользуемся условием и логической индексацией: | |
print(df_min[df_min['total_play_seconds'] == df_min['total_play_seconds'].min()]) | |
USER_ID TOTAL_PLAY_SECONDS ARTIST_NAME GENRE_NAME TRACK_NAME | |
12431 984326C8 0.000794 Madera & Jenny T feat. Jenny T dance Just Don't Say Goodbye | |
36140 2815A725 0.000794 Chicco pop Modjadji | |
50506 C371F506 0.000794 Людмила Лопато romances Три года ты мне снилась | |
Результат вывода — три трека, которые соответствуют минимальному значению. | |
На основе полученных данных можно сделать вывод, что время прослушивания треков находится в диапазоне от 0.000794 до 4707.422018 секунд, не включая пропущенные. | |
Это знание пригодится, чтобы разобраться с медианой и средним арифметическим. | |
Среднее и медиана оценивают значения в центре выборки. Если тех, кто слушает долго, столько же, сколько тех, кто слушает мало — среднее подойдет. Но когда есть оторванные от основной массы лидеры, слушающие музыку по 8 часов, их результаты сильно смещают значение среднего вверх. Вот почему оценивать предпочтения широкого круга потребителей лучше медианой. | |
image | |
В геометрии медиана делит фигуру на две равные по площади. В статистике она делит выборку пополам: в одной половине значения меньше медианного, в другой больше. Логично, что для определения медианы список обязательно должен быть отсортирован — либо по возрастанию, либо по убыванию. | |
Когда количество значений нечётное, медиана будет равна тому значению, которое оказалось ровно посередине отсортированного набора. Если же количество данных чётное, то медиана рассчитывается как среднее арифметическое двух соседних чисел в середине набора. | |
Для примера возьмем 5 последних строк в таблице. Обратимся к столбцу 'total_play_seconds' и отсортируем его: | |
df_stat_1 = df.tail() | |
print(df_stat_1['total_play_seconds'].sort_values()) | |
61211 11.529112 | |
61209 26.127000 | |
61207 109.000000 | |
61208 220.551837 | |
61210 292.455000 | |
Name: total_play_seconds, dtype: float64 | |
Значение в середине равно 109 — это и будет медиана. | |
Возьмём 4 последних строки в таблице, обратимся к столбцу 'total_play_seconds': | |
df_stat = df.tail(4) | |
print(df_stat['total_play_seconds'].sort_values()) | |
61211 11.529112 | |
61209 26.127000 | |
61208 220.551837 | |
61210 292.455000 | |
Name: total_play_seconds, dtype: float64 | |
Возьмём два значения в середине — 26.127 и 220.551837. Посчитаем среднее: | |
(26.127 + 220.551837) / 2 | |
123.3394185 | |
В Pandas есть метод median(), который считает медиану. По аналогии с min() и max() его можно применять ко всей таблице, к отдельному столбцу или к сгруппированным данным. | |
Сравним результаты с теми, которые мы получили вручную: | |
print(df_stat['total_play_seconds'].median()) | |
124.3138585 | |
Теперь применим медиану ко всем значениям времени прослушивания в нашей таблице, исключив нулевые: | |
df_drop_null = df[df['total_play_seconds'] != 0] | |
print(df_drop_null['total_play_seconds'].median()) | |
37.0 | |
Чтобы убедиться, что лидеры действительно смещают средний показатель вверх, найдём среднее арифметическое всех этих значений методом mean(): | |
print(df_drop_null['total_play_seconds'].mean()) | |
109.81197057131848 | |
Убедились? А теперь — за дело! | |
TASK_1_7 | |
Получите таблицу с композициями самого популярного жанра — pop, исключив пропущенные треки. Сохраните результат в переменной pop_music. | |
SOLUTION | |
import pandas as pd | |
df = pd.read_csv('music_log_upd.csv') | |
pop_music=df[(df['genre_name']=='pop')&(df['total_play_seconds']!=0)] | |
TASK_2_7 | |
Найдите максимальное время прослушивания песни в жанре pop. Сохраните результат в переменной pop_music_max_total_play и выведите её значение на экран. | |
SOLUTION | |
import pandas as pd | |
df = pd.read_csv('music_log_upd.csv') | |
pop_music=df[(df['genre_name']=='pop')&(df['total_play_seconds']!=0)] | |
pop_music_max_total_play=pop_music['total_play_seconds'].max() | |
print(pop_music_max_total_play) | |
TASK_3_7 | |
Получите строку таблицы pop_music c информацией о самой длинной по времени прослушивания песне жанра 'pop' и сохраните её в переменной pop_music_max_info. Выведите эту строку на экран. Закомментируйте вывод результата предыдущей задачи. | |
SOLUTION | |
import pandas as pd | |
df = pd.read_csv('music_log_upd.csv') | |
pop_music=df[(df['genre_name']=='pop')&(df['total_play_seconds']!=0)] | |
pop_music_max_total_play=pop_music['total_play_seconds'].max() | |
#print(pop_music_max_total_play) | |
pop_music_max_info=pop_music[pop_music['total_play_seconds']==pop_music['total_play_seconds'].max()] | |
print(pop_music_max_info) | |
TASK_4_7 | |
Найдите минимальное ненулевое время прослушивания композиции в жанре pop. Сохраните его в переменной pop_music_min_total_play, значение выведите на экран. Вывод результата предыдущей задачи закомментируйте. | |
SOLUTION | |
import pandas as pd | |
df = pd.read_csv('music_log_upd.csv') | |
pop_music=df[(df['genre_name']=='pop')&(df['total_play_seconds']!=0)] | |
pop_music_max_total_play=pop_music['total_play_seconds'].max() | |
#print(pop_music_max_total_play) | |
pop_music_max_info=pop_music[pop_music['total_play_seconds']==pop_music['total_play_seconds'].max()] | |
#print(pop_music_max_info) | |
pop_music_min_total_play=pop_music['total_play_seconds'].min() | |
print(pop_music_min_total_play) | |
TASK_5_7 | |
Выведите на экран информацию о композиции жанра pop, которую запустили, но быстрее всех остальных выключили. Результат сохраните в переменную pop_music_min_info и выведите на экран. | |
Вывод результата предыдущей задачи закомментируйте. | |
SOLUTION | |
import pandas as pd | |
df = pd.read_csv('music_log_upd.csv') | |
pop_music=df[(df['genre_name']=='pop')&(df['total_play_seconds']!=0)] | |
pop_music_max_total_play=pop_music['total_play_seconds'].max() | |
#print(pop_music_max_total_play) | |
pop_music_max_info=pop_music[pop_music['total_play_seconds']==pop_music['total_play_seconds'].max()] | |
#print(pop_music_max_info) | |
pop_music_min_total_play=pop_music['total_play_seconds'].min() | |
#print(pop_music_min_total_play) | |
pop_music_min_info=pop_music[pop_music['total_play_seconds']==pop_music['total_play_seconds'].min()] | |
print(pop_music_min_info) | |
TASK_6_7 | |
Рассчитайте медиану времени прослушивания произведений жанра pop. Сохраните результат в переменной pop_music_median и выведите на экран. | |
Вывод результата предыдущей задачи закомментируйте. | |
SOLUTION | |
import pandas as pd | |
df = pd.read_csv('music_log_upd.csv') | |
pop_music=df[(df['genre_name']=='pop')&(df['total_play_seconds']!=0)] | |
pop_music_max_total_play=pop_music['total_play_seconds'].max() | |
#print(pop_music_max_total_play) | |
pop_music_max_info=pop_music[pop_music['total_play_seconds']==pop_music['total_play_seconds'].max()] | |
#print(pop_music_max_info) | |
pop_music_min_total_play=pop_music['total_play_seconds'].min() | |
#print(pop_music_min_total_play) | |
pop_music_min_info=pop_music[pop_music['total_play_seconds']==pop_music['total_play_seconds'].min()] | |
#print(pop_music_min_info) | |
pop_music_median=pop_music['total_play_seconds'].median() | |
print(pop_music_median) | |
TASK_7_7 | |
Рассчитайте среднее арифметическое времени прослушивания произведений жанра pop. Сохраните результат в переменной pop_music_mean и выведите на экран. | |
Вывод результата предыдущей задачи закомментируйте. | |
SOLUTION | |
import pandas as pd | |
df = pd.read_csv('music_log_upd.csv') | |
pop_music = df[(df['genre_name'] == 'pop')&(df['total_play_seconds'] != 0)] | |
pop_music_max_total_play = pop_music['total_play_seconds'].max() | |
#print(pop_music_max_total_play) | |
pop_music_max_info = pop_music.loc[pop_music['total_play_seconds'] == pop_music['total_play_seconds'].max()] | |
#print(pop_music_max_info) | |
pop_music_min_total_play = pop_music['total_play_seconds'].min() | |
#print(pop_music_min_total_play) | |
pop_music_min_info = pop_music.loc[pop_music['total_play_seconds'] == pop_music['total_play_seconds'].min()] | |
#print(pop_music_min_info) | |
pop_music_median = pop_music['total_play_seconds'].median() | |
#print(pop_music_median) | |
pop_music_mean=pop_music['total_play_seconds'].mean() | |
print(pop_music_mean) |
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
От жанра к жанру картина тоже не меняется. Есть любители, готовые слушать «поп» тысячами секунд, есть те, кто половину композиций пролистывает в самом начале. Зато другую половину, судя по медиане, слушают почти до конца. Так что же с задачей, которую поставил менеджер? Вы к ней готовы: у вас есть инструменты группировки и сортировки данных, а также для расчёта статистики. С этим уже можно приносить пользу в бизнесе. | |
До начала эксперимента метрика happiness в Яндекс.Музыке была равна 57.456 секунд. Если время прослушивания выросло, значит, Радио хорошо повлияло на сервис, и такие данные могут обосновать окончательное решение. Если же метрика уменьшилась или не изменилась в условиях, где другие факторы сказаться не могли – тогда это нововведение не повлияло на аудиторию либо повлияло отрицательно. Тоже результат: стоит разобраться, почему. | |
Команда каждого продукта сама решает, как считать «уровень счастья». Для Яндекс.Музыки это медианное время прослушивания по пользователям. | |
Необходимо посчитать метрику happiness и подготовить отчётную таблицу, где будут собраны все данные, отвечающие на поставленный вопрос. | |
Метрика happiness рассчитывается так: | |
Считаем, как долго каждый пользователь слушал музыку. Для этого сгруппируем DataFrame по пользователю. | |
Для примера возьмём последние 5 строк таблицы. | |
df.tail() | |
Сгруппируем по пользователю: | |
df.tail().groupby('user_id') | |
Посчитаем общее время прослушивания музыки: | |
df.tail().groupby('user_id').sum() | |
Находим медианное значение для суммы прослушиваний по пользователю. | |
print(df.tail().groupby('user_id').sum().median()) | |
167.334833 | |
Аналитик то и дело показывает свою работу нетехническим специалистам: проджектам, маркетологам, топ-менеджерам. Они могут не владеть терминологией. Поэтому ваш отчёт, не теряя в содержательности, должен быть доступен широкой аудитории без подробных комментариев. | |
В дальнейших курсах программы «Аналитик данных» вы узнаете, как наполнять отчёты графиками и другими средствами визуализации. Здесь же задача такова, что хватит и наглядной таблицы с ключевыми показателями сервиса. Однако её детализация и нотация, т.е. устройство и словесное содержание, тоже должны выглядеть дружественными к пользователю. Даже в таком нехитром деле есть правила, которые стоит соблюдать. | |
Показывая, как меняется какой-нибудь параметр во времени, поместите его значения в строке, а столбцами задавайте временные промежутки. | |
image | |
Если нужно показать разнородные признаки для конкурирующих категорий (например, для жанров), то каждой категории отведите отдельную строку, а значения признаков размещайте по столбцам. | |
image | |
Не старайтесь обязательно собрать все данные в одну таблицу: лучше несколько таблиц, чтобы каждая отражала одну важную идею. | |
Отлично работает детализация от большего к меньшему. К общей сводной таблице прилагайте более подробные. Например, сначала обзорная таблица по всему сервису, затем более детальные: сводки по группам пользователей, по городам и т.п. | |
image | |
Проявите заботу о коллегах — старайтесь оформлять результаты наглядно и понятно. | |
TASK_1_4 | |
Рассчитайте метрику happiness после проведения эксперимента для всего набора данных. Действуйте по инструкции из урока. Сохраните полученный результат в переменной current_happiness и выведите на экран. | |
SOLUTION | |
import pandas as pd | |
df = pd.read_csv('music_log_upd.csv') | |
current_happiness=df.groupby('user_id').sum().median() | |
print(current_happiness) | |
TASK_2_4 | |
Внесите результат своей работы в существующую таблицу и вручную рассчитайте разность двух значений метрики happiness. | |
Названия столбцов: | |
metrics — метрика | |
before_test — до эксперимента | |
after_test — после эксперимента | |
absolute_difference — абсолютная разница | |
Значение метрики happiness после эксперимента: 62.344431 | |
SOLUTION | |
import pandas as pd | |
exp = [['happiness', 0, 0, 0]] | |
columns = ['metrics','before_test','after_test','absolute_difference'] | |
exp = [['happiness', 57.456 , 62.344431, 62.344431-57.456]] | |
metrics = pd.DataFrame(data=exp,columns=columns) | |
print(metrics) | |
TASK_3_4 | |
Вы много исследовали жанры рок и поп, давайте сведём в одну таблицу всю информацию о них. Недостаёт данных по року. Получите выборку прослушанных композиций в жанре рок, сохраните в переменной genre_rock. Получите максимальное и минимальное значения времени прослушивания, сохраните соответственно в переменных genre_rock_max и genre_rock_min, выведите на экран со строками: | |
'Максимальное время прослушивания в жанре рок равно:' | |
'Минимальное время прослушивания в жанре рок равно:' | |
SOLUTION | |
import pandas as pd | |
df = pd.read_csv('music_log_upd.csv') | |
# <введите здесь решение для поиска недостающих данных> | |
genre_rock=df[(df['genre_name']=='rock')&(df['total_play_seconds']!=0)] | |
# максимальное время прослушивания в жанре рок | |
genre_rock_max=genre_rock['total_play_seconds'].max() | |
# минимальное время прослушивания в жанре рок | |
genre_rock_min=genre_rock['total_play_seconds'].min() | |
print('Максимальное время прослушивания в жанре рок равно:',genre_rock_max) | |
print('Минимальное время прослушивания в жанре рок равно:', genre_rock_min) | |
TASK_4_4 | |
Соберите результаты исследования в таблицу research_genres_result, которую нужно создать конструктором DataFrame(). Его аргумент data — список с данными, аргумент columns — список названий столбцов. Выведите полученную таблицу на экран. | |
SOLUTION | |
import pandas as pd | |
data = [['pop', 8663, 34.6, 1158.03, 0.000794], | |
['rock', 6828, 33.3, 1699.14882, 0.014183]] | |
columns = ['genre_name','total_track','skip_track','max_total_time','min_total_time'] | |
research_genres_result=pd.DataFrame(data=data,columns=columns) | |
print(research_genres_result) |
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
Мы нашли ответ на интересующий нас вопрос. Фундамент владения библиотекой Pandas заложен и пригодится вам на всех стадиях анализа данных. Для предобработки вы умеете пользоваться методами избавления от пропусков и дубликатов, а для анализа — методами группировки и сортировки. | |
image | |
Теперь слово тому, чью задачу мы решали последние три урока: Привет! Это снова менеджер Яндекс.Музыки. | |
image | |
Было непросто, но вы справились с неподготовленными данными и собрали полезную статистику. Вы прошли все стадии анализа — от постановки задачи до оформления результатов. Формат подачи результатов подходящий: сразу видны важнейшие цифры. | |
Как видите, метрика happiness выросла. Стало быть, внедрение Радио — действительно хорошая идея. | |
Но у меня есть еще одна хорошая идея и обещаю вам, что вскоре мы её обсудим. До свидания! | |
Забери с собой | |
Чтобы ничего не забыть, скачайте шпаргалку |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
В блоке 3 Группировка данных у вас верный код с точки зрения выполнения, но тренажер яндекс.практимума будет выдавать ошибку:
"Текущий тип переменной - DataFrameGroupBy а ожидался - SeriesGroupBy..."
и не пропустит задание. Код нужно немного подправить: