Сейчас мы, наконец, попробуем получить данные, которые понадобятся непосредственно для выполнения задачи, поставленной менеджером Яндекс.Музыки. Для этого надо уметь запрашивать информацию из определённых ячеек таблицы. К каждой ячейке с данными в DataFrame можно обратиться по её индексу и названию столбца. Мы можем получать различные срезы данных в зависимости от того, какой запрос к DataFrame мы сформулируем. Этот процесс называется индексация. Для DataFrame она проводится разными способами. Атрибут loc[строка, столбец] даёт доступ к элементу по строке и столбцу. image ВИД РЕАЛИЗАЦИЯ Одна ячейка .loc[7, 'genre'] Один столбец .loc[:, 'genre'] Несколько столбцов .loc[:, ['genre', 'Artist']] Несколько столбцов подряд (срез) .loc[:, 'user_id': 'genre'] Одна строка .loc[1] Все строки, начиная с заданной .loc[1:] Все строки до заданной .loc[:3] Несколько строк подряд (срез) .loc[2:5] image image Также вы могли заметить, что запрос к атрибуту loc[] использует квадратные скобки, это напоминает списки в Python. Индексация здесь очень похожа на индексацию списков. Вспомните, как вы играли в «Морской бой» на уроках. Для победы недостаточно просто стрелять куда попало — нужно обдумывать ситуацию на поле противника, чтобы бить в цель как можно точнее. Посмотрите на поле для игры, оно подобно DataFrame: есть столбцы с буквенными обозначениями и ось индексов. Обратите внимание на разницу в индексах — в DataFrame они от 0 до 9. image import pandas as pd data = [[0,0,0,0,0,0,0,0,0,0], [0,'-','-','-',0,0,0,0,0,0], [0,'-','X','-',0,0,'X','X','X','X'], [0,'-','X','-',0,0,0,0,0,0], [0,'-','-','-',0,0,0,0,0,0], [0,0,'-',0,0,0,0,0,'X',0], [0,'-','X','X',0,0,0,0,0,0], [0,0,'-','-',0,0,0,0,0,0], [0,0,0,0,'-','X',0,0,0,0], [0,0,0,0,0,0,0,0,0,0]] columns = ['А','Б','В','Г','Д','Е','Ж','З','И','К'] battle = pd.DataFrame(data = data, columns = columns) print(battle) А Б В Г Д Е Ж З И К 0 0 0 0 0 0 0 0 0 0 0 1 0 - - - 0 0 0 0 0 0 2 0 - X - 0 0 X X X X 3 0 - X - 0 0 0 0 0 0 4 0 - - - 0 0 0 0 0 0 5 0 0 - 0 0 0 0 0 X 0 6 0 - X X 0 0 0 0 0 0 7 0 0 - - 0 0 0 0 0 0 8 0 0 0 0 - X 0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 Ячейки DataFrame со значением 0 обозначают пустую клетку. Информация в ячейке меняется на X, если игрок выстрелил и попал в корабль противника, а если не попал, то меняется на прочерк. Давайте исследуем текущую ситуацию на поле. Просмотрим столбец 'В' и убедимся, что там уже началась атака на корабль: print(battle.loc[:,'В']) 0 0 1 - 2 X 3 X 4 - 5 - 6 X 7 - 8 0 9 0 Name: В, dtype: object Действительно, атака уже началась в 6-ой строке, но корабль ещё не убит, а выстрелы в ячейки сверху и снизу кончились промахом. Просмотрим 6-ую строку и узнаем расположение корабля. print(battle.loc[6]) А 0 Б - В X Г X Д 0 Е 0 Ж 0 З 0 И 0 К 0 Name: 6, dtype: object Корабль ориентирован по горизонтали, по нему произведено два удачных выстрела, которые пришлись на столбцы В и Г. Нужно оценить ситуацию вокруг корабля. Для этого просмотрим строки с 5 по 7. print(battle.loc[5:7]) А Б В Г Д Е Ж З И К 5 0 0 - 0 0 0 0 0 X 0 6 0 - X X 0 0 0 0 0 0 7 0 0 - - 0 0 0 0 0 0 Очевидно, что следующий выстрел нужно сделать по координате 6Д. Ура, корабль убит! Теперь мы хотим найти второй трёхпалубный корабль. Оценим, где вероятнее всего он может располагаться. Для этого просмотрим две половины игрового поля. Срез из столбцов от А до Д даст возможность вывести левую часть таблицы: print(battle.loc[:,'А':'Д']) А Б В Г Д 0 0 0 0 0 0 1 0 - - - 0 2 0 - X - 0 3 0 - X - 0 4 0 - - - 0 5 0 0 - 0 0 6 0 - X X 0 7 0 0 - - 0 8 0 0 0 0 - 9 0 0 0 0 0 Такая же операция для столбцов от Е до К покажет правую часть таблицы: print(battle.loc[:,'Е':'К']) Е Ж З И К 0 0 0 0 0 0 1 0 0 0 0 0 2 0 X X X X 3 0 0 0 0 0 4 0 0 0 0 0 5 0 0 0 X 0 6 0 0 0 0 0 7 0 0 0 0 0 8 X 0 0 0 0 9 0 0 0 0 0 Важное замечание: когда мы используем срезы в списках, то конец среза не включается в результат. А вот атрибут .loc[] тем и выделяется, что включает и начало, и конец среза. Например, есть список исполнителей: artist = ['Marina Rei', 'Stive Morgan','Rixton','Henry Hall & His Gleneagles Hotel Band', 'Andrew Paul Woodworth', 'Pillar Point','Steve Campbell','David Civera','Lumipa Beats', 'Henning Wehland'] Элементы с 2 по 4 получают запросом: print(artist[2:5]) ['Rixton', 'Henry Hall & His Gleneagles Hotel Band', 'Andrew Paul Woodworth'] Последним в запросе указан индекс 5 — именно для того, чтобы в срез попал элемент с индексом 4. Запрос на получение со 2 по 4 строки в таблице будет выглядеть вот так: print(df.loc[2:4]) USER_ID TOTAL PLAY ARTIST GENRE TRACK 2 FB1E568E 282.981000 Stive Morgan ambient Love Planet 3 EF15C7BA 8.966000 NaN dance Loving Every Minute 4 82F52E69 193.776327 Rixton pop Me And My Broken Heart Итак, вы видели, как запрашивать один столбец, одну строку, диапазон столбцов и диапазон строк. Это самые ходовые запросы, которые вам предстоит делать как аналитику данных. На практике чаще применяют сокращённую форму записи для индексации. Но возможности у неё ограничены. Имейте в виду, что она не всегда возвращает те же результаты, что атрибут .loc[] в его полном варианте. ВИД РЕАЛИЗАЦИЯ СОКРАЩЁННАЯ ЗАПИСЬ Одна ячейка .loc[7, 'genre'] - Один столбец .loc[:, 'genre'] df['genre'] Несколько столбцов .loc[:, ['genre', 'Artist']] df [['genre', 'Artist']] Несколько столбцов подряд (срез) .loc[:, 'user_id': 'genre'] - Одна строка .loc[1] - Все строки, начиная с заданной .loc[1:] df[1:] Все строки до заданной .loc[:3] включая 3 df[:3] не включая 3 Несколько строк подряд (срез) .loc[2:5]включая 5 df[2:5] не включая 5 Неприятельский трёхпалубный корабль, скорее всего, на правой половине поля. Это можно предположить, оглядев по очереди оба среза. Аналитики называют такой метод изучения «посмотреть на данные глазами». На глаз хорошо выбирать направление дальнейших поисков, но так не получишь точных цифр, которые можно включить в отчёт. Надо уметь подсчитать количество определённых значений, например, точных попаданий. В Pandas для этого есть метод count(). Его вызывают и приказывают сосчитать, например, количество ячеек столбца В, где были попадания. Удачный выстрел — это значение "X" в ячейке. Для столбца В таблицы battle такие ячейки отвечают логическому условию battle.loc[:,'В'] == 'X'. Поскольку в указании, какие именно значения считать, нужен логический оператор, такой доступ к значению ячейки называют логическая индексация. image print(battle.loc[battle.loc[:,'В'] == 'X']['В'].count()) # используем метод .count() для подсчёта записей, удовлетворяющих условию в столбце В 3 ВИД РЕАЛИЗАЦИЯ СОКРАЩЁННАЯ ЗАПИСЬ Все строки, удовлетворяющие условию battle.loc[battle.loc[:,'В'] == 'X'] battle[battle['В'] == 'X'] Столбец, удовлетворяющий условию battle.loc[battle.loc[:,'В'] == 'X']['В'] battle[battle['В'] == 'X']['В'] Применение метода battle.loc[battle.loc[:,'В'] == 'X']['В'].count() battle[battle['В'] == 'X']['В'].count() Конечно, писать вызов метода count() для подсчёта попаданий в «морском бою» то же, что стрелять из пушки по воробьям. Но в анализе таблиц на много тысяч строк счётный метод — мощное орудие. Попробуйте в задаче с данными Яндекс.Музыки определить, какой жанр оказался популярнее у пользователей: поп или рок? TASK_1_4 Получите таблицу, состоящую из столбцов genre и Artist. Сохраните её в переменной genre_fight. SOLUTION import pandas as pd df = pd.read_csv('music_log.csv') genre_fight=df.loc[:,['genre', 'Artist']] TASK_2_4 Посчитайте число прослушанных треков в жанре поп. Для этого лучше всего использовать логическое условие genre_fight['genre'] == 'pop'. Сохраните результат в переменной genre_pop. Напечатайте ответ на экране в таком виде: Число прослушанных треков в жанре поп равно ... SOLUTION import pandas as pd df = pd.read_csv('music_log.csv') genre_fight=df.loc[:,['genre', 'Artist']] genre_pop=genre_fight.loc[genre_fight.loc[:,'genre'] == 'pop']['genre'].count() print('Число прослушанных треков в жанре поп равно', genre_pop) TASK_3_4 Теперь посчитайте число прослушанных треков в жанре рок. Допишите в код подсчёт, похожий на предыдущий, только с логическим условием df['genre'] == 'rock'. Сохраните результат в переменной genre_rock. Напечатайте ответ на экране в таком виде: Число прослушанных треков в жанре поп равно ... Число прослушанных треков в жанре рок равно ... SOLUTION import pandas as pd df = pd.read_csv('music_log.csv') genre_fight=df.loc[:,['genre', 'Artist']] genre_pop=genre_fight.loc[genre_fight.loc[:,'genre'] == 'pop']['genre'].count() genre_rock=genre_fight.loc[genre_fight.loc[:,'genre'] == 'rock']['genre'].count() print('Число прослушанных треков в жанре поп равно', genre_pop) print('Число прослушанных треков в жанре рок равно', genre_rock) TASK_4_4 Напишите условную конструкцию, которая сравнивает полученные значения и выводит информацию о победителе в этом бою! Если победил жанр рок, то выведите сообщение "Рок победил!", а если победил жанр поп - сообщение "Попса forever!" Не удаляйте вывод числа прослушанных треков в жанрах поп и рок. SOLUTION import pandas as pd df = pd.read_csv('music_log.csv') genre_fight=df.loc[:,['genre', 'Artist']] genre_pop=genre_fight.loc[genre_fight.loc[:,'genre'] == 'pop']['genre'].count() genre_rock=genre_fight.loc[genre_fight.loc[:,'genre'] == 'rock']['genre'].count() print('Число прослушанных треков в жанре поп равно', genre_pop) print('Число прослушанных треков в жанре рок равно', genre_rock) if genre_pop>genre_rock: print('Попса forever!') else: print('Рок победил!')