Следующая тема: ПД. Изменение типов данных

Вернуться к разделу: "Предобработка данных"

Вернуться в оглавление: Я.Практикум

 
1.Введение
 

Идеальных данных не бывает: обычно их ещё нужно подготовить к анализу. Мы расскажем, как бороться с пропусками в данных и прочими артефактами.

Чему вы научитесь

  • Различать категориальные и количественные данные
  • Выявлять пропуски — случайные и неслучайные
  • Заменять пропуски на значения:
    • расчётные,
    • дефолтные,
    • характерные.

Сколько времени это займет

9 уроков с теорией и заданиями по 15–25 минут

Постановка задачи

Вы оцените эффективность источников трафика Яндекс.Маркета, определите самый выгодный канал привлечения новых пользователей и составите рекомендации для менеджмента. Этот большой путь начинается с маленького шага — работы с пропусками в данных.

2.Конверсия и повторные покупатели

В бизнесе чем больше потенциальных покупателей, тем лучше. Интернет-проекты привлекают посетителей через различные каналы: рекламу в поисковых системах и соцсетях, email-рассылки. Такие каналы называются источники трафика. Это места, из которых пользователи переходят на сайт.

Привлечение пользователей стоит денег. Например, стоимость контекстной рекламы — коммерческих сообщений по теме поискового запроса — складывается из рекламного бюджета и оплаты труда специалистов, подготавливающих объявления. Почтовую рассылку создают маркетологи и дизайнеры, а их усилия тоже не бесплатны.

Обычно компании инвестируют в разные источники трафика, и руководители хотят знать, какой из них выгоднее. Аналитикам поручают посчитать соответствующие метрики — показатели, отражающие эффективность действий в бизнесе. Источники трафика обычно сравнивают по конверсии. В широком смысле конверсия — это отношение целевого показателя к общему. Конверсия сайта показывает, какую долю от всех посетителей составляют целевые — те, кто что-нибудь купил или оставил заявку, то есть совершил целевые действия.

Вместо посетителей для нахождения конверсии можно считать действия — делить целевые действия на все. Например, число покупок на общее количество визитов. Если зафиксировано 1000 посещений, или визитов, и в 50 из них была совершена покупка, конверсия составит 50 / 1000 * 100% = 5%.

Picha

Если знать, сколько визитов дал определённый источник трафика, можно посчитать конверсию именно для него: поделить на число таких визитов количество совершенных во время них покупок. Проанализируйте таблицу. Какой источник трафика эффективнее с точки зрения конверсии — контекстная реклама или рассылки?

Источник трафика Количество визитов Количество покупок
Контекстная реклама 2500 100
Рассылки 1000 50

Конверсия контекстной рекламы составила 100 / 2500 * 100% = 4%. А конверсия рассылок равна 50 / 1000 * 100% = 5%. Значит, выигрывают рассылки: если конверсия не изменится, то 2500 пользователей, перешедших на сайт из писем, совершат больше покупок, чем 2500 кликнувших на контекстную рекламу.

Ещё одна важная метрика — доля повторных покупателей. Если из 100 совершивших покупку 10 вернулись и снова что-нибудь купили, эта доля составит 10 / 100 * 100% = 10%.

Задача №1

Рассчитайте конверсию визитов в покупки из рассылок и контекстной рекламы, сохраните значения в переменных email_conversion и context_conversion соответственно.

Результат выведите на экран так:

Конверсия рассылок: ...%

Конверсия контекстной рекламы: ...%

Процент отобразите в виде целого числа — с точностью ноль знаков после запятой.

email_visits = 1000 # количество визитов из рассылок
context_visits = 2500 # количество визитов из контекстной рекламы
email_purchases = 50 # количество покупок из рассылок
context_purchases = 100 # количество покупок из контекстной рекламы

email_conversion = email_purchases/email_visits # поделите email_purchases на email_visits
context_conversion = context_purchases/context_visits# напишите ваш код здесь
# выведите значение конверсий рассылок
print('Конверсия рассылок: {:.0%}'.format(email_conversion))
# выведите на экран значения конверсий контекстной рекламы
print('Конверсия контекстной рекламы: {:.0%}'.format(context_conversion))

Задача №2

Продолжим автоматизировать труд маркетологов: научим Python сравнивать источники трафика и выбирать лучший. Если конверсия рассылок email_conversion больше конверсии контекстной рекламы context_conversion, выведите на экран: 'Вывод: рассылки эффективнее'. Если наоборот, то: 'Вывод: контекстная реклама эффективнее'. Не удаляйте из вывода результат предыдущей задачи.

email_visits = 1000 # количество визитов из рассылок
context_visits = 2500 # количество визитов из контекстной рекламы
email_purchases = 50 # количество покупок из рассылок
context_purchases = 100 # количество покупок из контекстной рекламы

email_conversion = email_purchases / email_visits
context_conversion = context_purchases / context_visits 
print('Конверсия рассылок: {:.0%}'.format(email_conversion))
print('Конверсия контекстной рекламы: {:.0%}'.format(context_conversion))

# напишите условную конструкцию здесь
if email_conversion > context_conversion:
    print ('Вывод: рассылки эффективнее')
else:
    print ('Вывод: контекстная реклама эффективнее')

Задача №3

Добавьте случай, когда конверсии равны. При равенстве конверсий выводите: 'Конверсии равны, пора смотреть другие метрики'.

email_visits = 1000 # количество визитов из рассылок
context_visits = 2500 # количество визитов из контекстной рекламы
email_purchases = 50 # количество покупок из рассылок
context_purchases = 100 # количество покупок из контекстной рекламы

email_conversion = email_purchases / email_visits
context_conversion = context_purchases / context_visits 
print('Конверсия рассылок: {:.0%}'.format(email_conversion))
print('Конверсия контекстной рекламы: {:.0%}'.format(context_conversion))

# напишите условную конструкцию здесь
if email_conversion > context_conversion:
    print ('Вывод: рассылки эффективнее')
elif email_conversion == context_conversion:
    print ('Конверсии равны, пора смотреть другие метрики')
else:
    print ('Вывод: контекстная реклама эффективнее')

Задача №4

Измените значения переменных email_visitscontext_visitsemail_purchasescontext_purchases так, чтобы получить вывод, что контекстная реклама эффективнее или что конверсии рассылок и контекстной рекламы равны.

email_visits = 1000 # количество визитов из рассылок
context_visits = 1000 # количество визитов из контекстной рекламы
email_purchases = 50 # количество покупок из рассылок
context_purchases = 50 # количество покупок из контекстной рекламы

email_conversion = email_purchases / email_visits
context_conversion = context_purchases / context_visits 
print('Конверсия рассылок: {:.0%}'.format(email_conversion))
print('Конверсия контекстной рекламы: {:.0%}'.format(context_conversion))

# напишите условную конструкцию здесь
if email_conversion > context_conversion:
    print ('Вывод: рассылки эффективнее')
elif email_conversion == context_conversion:
    print ('Конверсии равны, пора смотреть другие метрики')
else:
    print ('Вывод: контекстная реклама эффективнее')

Задача №5

Вы уже умеете находить конверсию. Рассчитайте другую важную для бизнеса метрику — долю повторных покупателей.

В переменной total посчитайте общее количество покупателей: сложите число пользователей, совершивших одну покупку, с числом тех, кто совершил две и более. Выведите результат в виде: 'Общее количество покупателей: ...'

first_purchase = 885 # количество пользователей, совершивших 1 покупку
repeated_purchase = 136 # количество пользователей, совершивших 2 и более покупок
total = first_purchase + repeated_purchase# общее количество покупателей
print ('Общее количество покупателей:', total)

Задача №6

Посчитайте долю повторных покупок как отношение repeated_purchase к total. Ответ положите в переменную repeated_purchase_part. Результат выведите на экран так: 'Доля повторных покупок равна ...%'. Процент отобразите в виде целого числа — с точностью ноль знаков после запятой.

first_purchase = 885
repeated_purchase = 136
total = first_purchase + repeated_purchase
repeated_purchase_part = repeated_purchase/total# поделите количество пользователей, совершивших 2 и более покупок, на общее количество покупателей
print ('Доля повторных покупок равна {:.0%}'.format(repeated_purchase_part))

Задача №7

Вам прислали таблицу со статистикой первичных и повторных покупок по источникам трафика. Прочитайте содержимое файла returned.csv и сохраните его в датафрейме purchases. Посчитайте общее число покупок для каждого источника трафика. Результат запишите в столбец 'total'. Выведите весь датафрейм на экран.

Путь к файлу: /datasets/returned.csv

import pandas as pd
purchases = pd.read_csv('/datasets/returned.csv')
purchases['total'] = purchases['first'] + purchases['repeated']
print (purchases)

Задача №8

Для каждого источника трафика посчитайте долю повторных покупок — отношение количества повторных ко всем покупкам. Выведите весь датафрейм на экран.

import pandas as pd
purchases = pd.read_csv('/datasets/returned.csv')
purchases['total'] = purchases['first'] + purchases['repeated']
purchases['repeated_share'] = purchases['repeated'] / purchases['total'] # отношение повторных покупок ко всем покупкам 
print (purchases)

Задача №9

Постройте рейтинг источников трафика по доле повторных покупок. Отсортируйте датафрейм purchases по убыванию значений столбца 'repeated_share'. Выражение напишите в скобках функции print(), чтобы вывести результат на экран.

import pandas as pd
purchases = pd.read_csv('/datasets/returned.csv')
purchases['total'] = purchases['first'] + purchases['repeated']
purchases['repeated_share'] = purchases['repeated'] / purchases['total']
print (purchases.sort_values(by=['repeated_share'], ascending=False))

3.User ID и куки

Когда пользователь заходит на веб-страницу, ни одно его действие не остаётся незамеченным.

Счётчик — несколько строчек в коде сайта — отслеживает просмотр внутренних страниц и покупки, а ещё собирает общие сведения. В том числе источник трафика.

Данные счётчика называют «сырыми»: они не наглядны и не подходят для быстрого анализа. Системы веб-аналитики, например Яндекс Метрика, превращают их в отчёты об аудитории, посещаемости и источниках трафика. С отчётами работать удобно: можно комбинировать разные метрики и визуализировать их.

pic

Чтобы различать посетителей сайта и запоминать их поведение, система веб-аналитики присваивает каждому свой номер, или уникальный идентификатор — user ID.

pic2

Куки

Когда пользователь заходит на сайт повторно, система «узнаёт» его и учитывает по user ID, присвоенному в первое посещение. Это происходит благодаря кукам — так называют короткие текстовые файлы, которые сайт передаёт браузеру, а браузер их сохраняет. Без кук аналитик не мог бы выполнить почти ни одну задачу. В том числе рассчитать долю повторных покупателей. pic3 Куки содержат не только user ID пользователя, но и другую информацию. Например, языковые предпочтения, логин и пароль, посещённые разделы. Это улучшает опыт взаимодействия с сайтами: стриминговые платформы предлагают возобновить просмотр фильма с того момента, где вы остановились в прошлый раз, онлайн-переводчик запоминает целевой язык перевода, а соцсети не требуют заново логиниться при каждом посещении.

Сайты обязаны уведомлять посетителей о том, что используют куки. В России — на основании закона 152-ФЗ «О персональных данных», а в Евросоюзе — Общего регламента по защите данных (General Data Protection Regulation). Эти законы призваны защитить личную информацию пользователей. Компаниям, которые не соблюдают предписаний, грозит штраф: до 300 тыс. рублей в России и до 20 млн евро в странах Евросоюза.

У каждого браузера свои куки, поэтому когда пользователь открывает сайт в разных браузерах или на разных устройствах, ему присваивают несколько user ID. Чтобы вычислить такого посетителя и отслеживать его как уникального, нужна дополнительная характеристика. Например, email. (Идентификаторы будут различаться, но адрес электронной почты совпадёт). Вернёмся к задаче и посмотрим, откуда пользователи переходят на сайт и многие ли оставляют свой email.

Задача №1

Взгляните на присланную разработчиками таблицу. Она называется logs, так как в ней отражены логи — данные о посещениях сайта.

В таблице четыре столбца: user_id — идентификатор пользователя; email — электронный адрес подписчика рассылки; source — источник трафика; purchase — факт покупки: со значением 1, если покупка была, 0 — её не было.

Каждая строчка в таблице соответствует визиту на сайт. User ID, источник трафика и факт покупки можно получить из Яндекс Метрики, а электронные адреса — из базы тех, кто подписался на email-рассылку. Когда к набору полученных определённым образом данных добавляют информацию из другого источника, это называется обогащение данных. Прочтите содержимое файла logs.csv и сохраните его в датафрейме logs. Ознакомьтесь с данными, вызвав метод head(). Путь к файлу: /datasets/logs.csv

import pandas as pd
logs = pd.read_csv('/datasets/logs.csv')
print(logs.head())
Задача №2
Оцените объём данных в таблице logs.
import pandas as pd

logs = pd.read_csv('/datasets/logs.csv')
logs.info()
Задача №3

Посчитайте количество уникальных email и уникальных User ID в таблице logs. Выведите результат на экран в таком виде:

Уникальных email: ...

Уникальных User ID: ...

import pandas as pd

logs = pd.read_csv('/datasets/logs.csv')
# напишите код для подсчёта уникальных email здесь
unique_emails = logs['email'].unique()
print ('Уникальных email:',len(unique_emails))
# напишите код для подсчёта уникальных User ID здесь
unique_user_id = logs['user_id'].unique()
print ('Уникальных User ID:',len(unique_user_id))
Задача №4
Методом unique() определите, какие уникальные источники трафика есть в таблице. Результат выведите на экран.
import pandas as pd

logs = pd.read_csv('/datasets/logs.csv')
print (logs['source'].unique())

4.Вы обнаружили NaN и None

В таблице из предыдущего урока вместо источников трафика встречаются значения None, а вместо зашифрованных электронных адресов — NaN. Такие значения указывают, что данных нет.

NaN замещает отсутствующее в ячейке число и принадлежит к типу float, поэтому с ним можно проводить математические операции.

None относят к нечисловому типу NoneType, и математические операции с ним неосуществимы.

Обнаружив строки с None и NaN, не поддавайтесь искушению немедленно их удалить. Иногда пропущенные значения можно взять у разработчиков, ответственных за выгрузку данных. Кроме того, с разными типами пропущенных значений борются по-своему — этому вам и предстоит научиться.

Вызвав к столбцу source метод value_counts(), который возвращает уникальные значения и количество их упоминаний, определим, сколько раз источник трафика был пропущен.

import pandas as pd
logs = pd.read_csv('logs.csv')
print(logs['source'].value_counts())
>>>
other      133834
context     52032
email       12279
None         1674
undef         181
Name: source, dtype: int64

Источник трафика пропущен в 1674 случаях. Это менее 1% от всех значений датафрейма logs, в котором 200 000 строк. Меньше процента — это немного, и в большинстве задач удаление такой доли строк не повлияет на результаты. Но что, если все пропуски сделаны на месте значений 'email'? Тогда, удалив строки с None, мы лишим себя почти 1/8 данных: 1674 / (12279 + 1674) ≈ 12%. Это повлияет на метрики email-рассылок и выводы исследования. pic1 Методом isna() найдём все строки с пропусками в столбце email и просмотрим первые пять.

print(logs[logs['email'].isna()].head())

      user_id   source email  purchase
0  7141786820    other   NaN         0
2  1914055396  context   NaN         0
3  4099355752    other   NaN         0
4  6032477554  context   NaN         1
5  5872473344    other   NaN         0

Этот код похож на фильтр. Выражение logs['email'].isna() проверяет все строки в столбце email и оставляет только те, в которых есть NaN. Метод head() выводит на экран первые пять строк. Чтобы сосчитать строки без email-адресов, вызовем функцию len().

print(len(logs[logs['email'].isna()]))

186047

В 186 047 строках из 200 000 электронный адрес пропущен. Вполне объяснимо: пользователи регистрируются на сайте неохотно.

Тем не менее, пропуски нельзя оставлять без внимания: группировка данных с NaN может привести к некорректным результатам анализа. Удостоверимся на примере присуждения кубка в школе волшебников Хогвартс.

Ученики в течение года зарабатывают очки для своих факультетов: Гриффиндора, Слизерина, Пуффендуя и Когтеврана. Кубок школы предназначен факультету, набравшему наибольшее количество баллов. Цена ошибки велика.

Изучим таблицу с распределением баллов по факультетам.

Задача №1

Восстановите справедливость: верните Рону его факультет, заменив значение NaN на 'Гриффиндор' методом fillna(). Выведите на экран таблицу hogwarts_points.

import pandas as pd

hogwarts_points = pd.read_csv('/datasets/hogwarts_points.csv')
hogwarts_points = hogwarts_points.fillna('Гриффиндор')
print (hogwarts_points)

Задача №2

Измените код, чтобы результат приобрёл такой вид:

Сумма баллов учеников: # сумма значений столбца 'points'
Сумма баллов факультетов: # сумма баллов при группировке по факультетам
Кубок получает # название факультета

import pandas as pd

hogwarts_points = pd.read_csv('/datasets/hogwarts_points.csv')
hogwarts_points['faculty_name'] = hogwarts_points['faculty_name'].fillna(value='Гриффиндор')
print('Сумма баллов учеников:', hogwarts_points['points'].sum())# сумма значений столбца 'points'
print('Сумма баллов факультетов:', hogwarts_points.groupby('faculty_name')['points'].sum().sum() )
# сгруппируйте по столбцу 'faculty_name'
# сложите значения столбца 'points' этой группировки методом sum()
# и примените метод sum() к результату
print ('Кубок получает', hogwarts_points.groupby('faculty_name')['points'].sum().idxmax())

Задача №3

Применим полученные в Хогвартсе знания к реальной задаче. Возьмём источники трафика Яндекс.Маркета и рассчитаем конверсию. Найдите количество визитов из каждого источника трафика. Для этого сгруппируйте данные из столбца с идентификаторами пользователей по столбцу с источниками. Результат сохраните в переменной visits и выведите на экран.

import pandas as pd

logs = pd.read_csv('/datasets/logs.csv')
#общее количество визитов из каждого источника
visits = logs.groupby('source')['user_id'].count()
print (visits)

Задача №4

Посчитайте количество совершённых покупок для каждого источника трафика. Результат сохраните в переменной purchase и выведите на экран.

import pandas as pd

logs = pd.read_csv('/datasets/logs.csv')
# количество покупок для каждого источника
purchase = logs.groupby('source')['purchase'].sum()
print (purchase)

Задача №5

Посчитайте конверсию по каждому источнику трафика, результат сохраните в переменной conversion и выведите на экран.

import pandas as pd
logs = pd.read_csv('/datasets/logs.csv')
visits = logs.groupby('source')['user_id'].count() # количество визитов
purchase = logs.groupby('source')['purchase'].sum() # количество покупок
conversion = purchase / visits # поделите количество покупок на количество визитов
print (conversion)

5.Категориальные и количественные переменные

Способ работы с пропущенными значениями зависит от их типа. В датафрейме pandas могут содержаться категориальные или количественные данные:

  • Категориальная переменная принимает одно значение из ограниченного набора.
  • Количественная — любое числовое значение в диапазоне.

Вызывая такси в приложении, вы встречаете оба типа.

Категориальная переменная в Яндекс.Такси — это тариф: «Эконом», «Комфорт», «Комфорт+», «Бизнес», «Премиум», «Ультима», «Бизнес XL», «Минивэн» или «Детский». Количество тарифов ограничено, клиенты выбирают один из них. Категориальная переменная может принимать и числовые значения: если вместо «Эконома» будет стоять цифра 1, а вместо «Комфорта» — 2, переменная всё равно останется категориальной.

А стоимость поездки будет количественной переменной. На определённом расстоянии она может принимать любое значение в диапазоне, допустим, от 200 до 600 рублей. Цена зависит от спроса, категории и наличия машины.

Важное свойство количественных переменных — возможность сравнения. Поездка за 420 рублей на 120 рублей дороже поездки за 300 рублей. Категориальные переменные так не сравнить: если каждому тарифу присвоить номер от 1 до 9, нельзя сказать, что «Комфорт» больше «Эконома» на единицу.

Заметим, что категориальные и количественные переменные — это термины из статистики, а не из программирования. Такие переменные не привязаны к конкретному типу значений в Python или другом языке. Например, значения типа int могут быть и у количественных переменных, и у категориальных. Объясним на примере датафрейма, который хранит информацию об аккаунтах в социальной сети.

account_name is_active user_category average_session_duration
Mr. Pink True 1 510,5
Mr. Orange True 3 235,1
Mr. Blonde False 1 322,3
Mr. Blue True 5 412,7

Датафрейм включает столбцы:

account_name — логин пользователя; is_active — значения, которые показывают, ушёл ли пользователь из социальной сети; user_category — номер группы пользователя, который определяется поведением в социальной сети и интересами; average_session_duration — средняя длительность сессии пользователя в секундах.

Значения, которые входят в столбец is_active, относятся к логическим или булевым. Логические значения — тип не из статистики, а из Python. Такие значения указывают на истинность или ложность какого-либо события и в Python обозначаются типом bool.

В столбце is_active может быть только два значения: True и False. С точки зрения статистики, значения из ограниченного набора являются категориальными. Их нельзя измерить или количественно сравнить друг с другом: пользователь либо ушёл из социальной сети, либо остался. В этом случае логические значения определяют две категории пользователей.

Столбец user_category хранит целые числа типа int, но, с точки зрения статистики, эти значения не будут количественными. Числа в этом столбце обозначают категории, и всего их пять. Значения в столбце average_session_duration выражены типом float и, с точки зрения статистики, являются количественными. Числа в столбце обозначают среднюю продолжительность сессии пользователя, и эти показатели можно сравнивать друг с другом: значение 412.7 больше 235.1, но меньше 510.5.

Перед вами фрагмент датафрейма HR-команды небольшой компании.

Фамилия Возраст  Роль  Город проживания Команда Накопленные дни отпуска
Игнатьев  42 разработчик Москва бэкэнд-разработка 5
Макаров 30 аналитик Москва аналитика 2
Черняев   31 разработчик Екатеринбург мобильная разработка 7
Оборицкая 28 менеджер Пермь бэкэнд-разработка 0
Кац 29 аналитик Москва    

Какие из этих переменных — категориальные?

Правильный ответ Количество гостей
Правильный ответ Количество ванных комнат
Правильный ответ Количество спален
Правильный ответ Количество кроватей
Правильный ответ Стоимость

Количественные переменные можно сложить или сравнить. Категориальные — нет. Верно определить тип переменной — первое дело в борьбе с пропусками.
 

6.Индексация в атрибуте loc

Чтобы проводить глубокий анализ таблиц и заполнять пропуски, нужны условия с логическими выражениями. Разберем подробнее, как они работают в атрибуте loc.

В этом уроке вы повторите, как в атрибуте loc работает обычная индексация, и глубже изучите логическую индексацию.

Задача из жизни IT-компании. В продуктовую команду пришел новый руководитель. Первым делом он решил разобраться, кто чем занимается: создал таблицу и попросил всех её заполнить. Каждый указал свою роль в команде и отметил проекты, в которых участвует. Всего проектов три — разработка новой функции приложения, проведение эксперимента и написание статьи в блог компании. Получилась такая таблица:

Имя Роль Новая функция Эксперимент Статья
Маша разработчик   +  
Петя аналитик + - -
Вася разработчик   + +
Катя менеджер + - +
Ваня аналитик +    
Дима менеджер +    
Настя разработчик + + -
Лена копирайтер   +  
 
Обратите внимание: некоторые члены команды отметили проекты, в которых не участвуют, минусами. Многие ячейки остались пустыми, и в таблице пропуски сохранились как NaN. От них нам предстоит избавиться.

Если вы забыли атрибут loc, повторите уроки про индексацию в DataFrame из курса «Базовый Python». Они находятся в теме, посвящённой pandas.

Задача №1
Применяя атрибут loc, извлеките из таблицы роль члена команды по имени Вася и напечатайте её значение на экране. Должна получиться строка — данные из одной ячейки.
import pandas as pd
data = pd.read_csv('/datasets/projects.csv')
print(data.loc[2,'Роль'])
Задача №2
Руководитель объявил создание новой функции приоритетной задачей и решил задействовать в ней всю команду. Пользуясь атрибутом loc, замените все значения в столбце “Новая функция” на плюсы. Потом напечатайте таблицу на экране.
import pandas as pd

data = pd.read_csv('/datasets/projects.csv')
data.loc[:,'Новая функция'] = '+'
print(data)

Отлично, теперь перейдем к подробностям логической индексации в атрибуте loc. Это нужно, чтобы выбирать строки не номерами, а условиями.

Начнём с того, что вместо числовых индексов строк в атрибут loc можно передавать списки из значений True и False. Это нужно, чтобы выбранные строки можно было задавать не номерами, а условиями. Про это расскажем позже, а пока давайте поработаем со значениями True и False напрямую.

Допустим, мы хотим извлечь из таблицы строку с информацией про Петю. Это вторая строка, но вместо использования номера, мы сделаем список, где для каждой строки укажем, хотим ли мы её выбирать (True) или нет (False):

rows = [False, True, False, False, False, False, False, False]

,pic Если передать этот список в атрибут loc, он вернет только нужную нам строку:

import pandas as pd

data = pd.read_csv('/datasets/projects.csv')

rows = [False, True, False, False, False, False, False, False]
print(data.loc[rows])

Имя      Роль Новая функция Эксперимент Статья
1  Петя  аналитик             +           -      -
Если в списке будет несколько значений `True`, то и строк в результате будет несколько. Например, если мы хотим вывести строки для всех, кто поначалу работал над новой функцией, нам нужно создать такой список:
rows = [True, True, False, True, False, False, True, False]

Плюсы в столбце «Новая функция» стоят в строках с индексами 0, 1, 3 и 6.

Поэтому в списке rows значения с индексами 0, 1, 3 и 6 равны True, а остальные — False. Подставим список в атрибут loc:

import pandas as pd
data = pd.read_csv('/datasets/projects.csv')
rows = [True, True, False, True, False, False, True, False]
print(data.loc[rows])

Имя         Роль Новая функция Эксперимент Статья
0   Маша  разработчик             +         NaN    NaN
1   Петя     аналитик             +           -      -
3   Катя     менеджер             +           -      +
6  Настя  разработчик             +           +      -
Отлично, все работает, как и было задумано. Теперь попробуйте и вы.
 
Задача №3

Извлеките из таблицы строки с информацией о разработчиках (Маша, Вася, Настя) и напечатайте их на экране. Для этого в атрибут loc передайте список значений True и False.

Чтобы мы могли точнее проверить ваше решение, сохраните список значений True и False в переменной rows.

import pandas as pd

data = pd.read_csv('/datasets/projects.csv')
rows = [True, False, True, False, False, False, True, False]
print (data.loc[rows])
Вместо вас составлять списки из True и False могут логические выражения. Например, вы отбирали строки, где в столбце «Новая функция» стоят плюсы. Это можно записать условием, что столбец «Новая функция» равен '+':
rows = data['Новая функция'] == '+'
Pandas проверит это условие для каждой ячейки столбца «Новая функция» и создаст набор значений с результатами проверки: True или False.
import pandas as pd
data = pd.read_csv('/datasets/projects.csv')
rows = data['Новая функция'] == '+'
print(rows)

0     True
1     True
2    False
3     True
4    False
5    False
6     True
7    False
Name: Новая функция, dtype: bool

Чтобы лучше разобраться с этим кодом, проясним две тонкости:

  1. Запись rows = data['Новая функция'] == '+' содержит два равенства, но это не ошибка. Python понимает, что второе равенство — двойное, то есть логический оператор. Поэтому Python сначала выполняет логический оператор, а потом присваивает результат переменной rows. Мы как будто поставили скобки вот так: rows = (data['Новая функция'] == '+'). Точно так же будут работать и другие логические операторы, например x = b > 5 или y = a != 0.
  2. Результат выполнения этого условия — уже не список list, как в прошлых примерах, а объект Series, потому что именно такой тип данных Pandas использует для хранения столбцов. Но это нам не помешает — атрибут loc понимает и то, и другое.

Прежде чем подставлять в loc эти логические выражения, потренируйтесь в их создании.

Задача №4
Напишите выражение со следующим условием для строк: роль члена команды — разработчик. Сохраните результат этого выражения в переменную rows и напечатайте её на экране.
import pandas as pd

data = pd.read_csv('/datasets/projects.csv')
rows = (data['Роль'] == 'разработчик')
print (rows)
Задача №5
Напишите логическое выражение, проверяющее, что член команды не менеджер. Сохраните результат этого выражения в переменной rows и напечатайте его на экране.
import pandas as pd
data = pd.read_csv('/datasets/projects.csv')
rows = (data['Роль'] != 'менеджер')
print (rows)

7.Логические выражения в атрибуте loc

Продолжим изучать, как работают логические выражения в атрибуте loc. В этом уроке вы научитесь соединять в loc логические выражения с индексацией и отработаете всё вместе на более сложных примерах.

В прошлом уроке вы по таблице сотрудников нашли, где в столбце «Новая функция» стоят плюсы, и уже научились задавать это условие выражением. Теперь подставим логическое выражение в атрибут loc:

import pandas as pd
data = pd.read_csv('/datasets/projects.csv')
rows = data['Новая функция'] == '+'
print(data.loc[rows])
Получили тот же результат, что и просто со списком значений True и False, ура! Попробуйте и вы.
 
Задача №1

Извлеките из таблицы и напечатайте на экране строки с информацией о работающих над статьёй. Для этого используйте атрибут loc и логическое выражение с условием на имя столбца.

Чтобы мы могли точнее проверить ваше решение, сохраните список значений True и False в переменной rows.

import pandas as pd

data = pd.read_csv('/datasets/projects.csv')
rows = data['Статья'] == '+'
print(data.loc[rows])
Условие можно сразу же подставлять в атрибут loc и не создавать дополнительную переменную:
# вариант с дополнительной переменной
rows = data['Новая функция'] == '+'
print(data.loc[rows])

# вариант без дополнительной переменной
print(data.loc[data['Новая функция'] == '+'])

Далее выбирайте любой вариант — как вам удобнее.

Условие на строки таблицы можно сочетать и с указанием столбца, который мы хотим извлечь. Получая строки, где в столбце «Новая функция» стоят плюсы, можно сразу извлечь только имена членов команды.

import pandas as pd
data = pd.read_csv('/datasets/projects.csv')
print(data.loc[data['Новая функция'] == '+', 'Имя'])

0     Маша
1     Петя
3     Катя
6    Настя
Name: Имя, dtype: object
Обратите внимание: условие мы задаём на один столбец ('Новая функция'), а информацию получаем про другой столбец ('Имя'). Рассмотрим другой пример: представьте, что вы захотели сегодня вечером оказаться на пляже. Вы пойдете в поисковик авиабилетов и попросите его вывести ответ на вопрос «в какие страны я могу полететь сегодня вечером?» Здесь «сегодня вечером» — это условие на один из столбцов в базе данных билетов. А «какая страна» — это значение другого столбца, которое вам интересно. И тот и другой столбец одинаково важны, но смешивать их нельзя. pic Когда вы выбрали из таблицы нужные строки и задали интересующий столбец, можно использовать loc для замены значений. Например, давайте поменяем роль тем членам команды, которые участвуют в эксперименте:
 
import pandas as pd
data = pd.read_csv('/datasets/projects.csv')
data.loc[data['Эксперимент'] == '+', 'Роль'] = 'экспериментатор'
print(data)
Как видите, в заданном столбце 'Роль' изменились значения. Не все, а только подходящие под условие на столбец 'Эксперимент'.
 
Задача №2
 
Извлеките из таблицы имена участников эксперимента и напечатайте их на экране. Список имён должен иметь тип Series. Передайте в атрибут loc выражение с условием на значение столбца. Отдельную переменную для списка значений True и False можно не создавать. А можете и создать — как вам больше нравится.
import pandas as pd

data = pd.read_csv('/datasets/projects.csv')
print (data.loc[data['Эксперимент'] == '+', 'Имя'])
 
Задача №3

Давайте заполним пропуски в столбце проекта с новой функцией. Для этого замените все значения, не равные плюсу, на минусы. Тогда пропуски заменятся на минусы, и сами минусы заменятся на минусы (то есть не поменяются). После замены выведите на экран всю полученную таблицу.

Отдельную переменную для списка значений True и False можно не создавать.

import pandas as pd

data = pd.read_csv('/datasets/projects.csv')
data.loc[data['Новая функция'] != '+', 'Новая функция'] = '-'
print (data)

Для каждого столбца замена производится в отдельности.

Отлично, теперь вы умеете свободно извлекать и менять значения в таблице! Давайте ещё немного расширим возможности и научимся добавлять в условия логические операторы. Они работают как логические операторы andornot в обычной булевой логике Python, но есть различия:

  1. Операторы Pandas пишут не словами, а знаками: and превращается в & (амперсанд), or превращается в | (вертикальная черта), а not превращается в ~ (тильда).
  2. Каждое отдельное сравнение необходимо окружать скобками. Например, логическое выражение в Python x > 0 and x < 10 в Pandas превратится в (x > 0) & (x < 10).

Давайте для примера найдем в таблице всех разработчиков, занимающихся новой функцией. То есть это два логических условия: «Роль» равна «разработчик» и «Новая функция» равна «+». Они соединяются оператором «и», потому что должны быть выполнены оба. Получается такой код:

import pandas as pd

data = pd.read_csv('/datasets/projects.csv')

print(data.loc[(data['Новая функция'] == '+') & (data['Роль'] == 'разработчик')])

     Имя         Роль Новая функция Эксперимент Статья
0   Маша  разработчик             +         NaN    NaN
6  Настя  разработчик             +           +      -

Получили ограниченный двумя условиями набор строк, который удовлетворяет нашему запросу.

Точно так же условиями с логическими операторами можно изменять значения. Давайте всех разработчиков, которые занимаются новой функцией, переименуем в «улучшателей». Чтобы код было легче читать, условия вынесем в отдельную переменную rows, как раньше.

import pandas as pd

data = pd.read_csv('/datasets/projects.csv')

rows = (data['Новая функция'] == '+') & (data['Роль'] == 'разработчик')
data.loc[rows, "Роль"] = "улучшатель"
print(data)

     Имя         Роль Новая функция Эксперимент Статья
0   Маша   улучшатель             +         NaN    NaN
1   Петя     аналитик             +           -      -
2   Вася  разработчик           NaN           +      +
3   Катя     менеджер             +           -      +
4   Ваня     аналитик           NaN           +    NaN
5   Дима     менеджер           NaN           +    NaN
6  Настя   улучшатель             +           +      -
7   Лена   копирайтер           NaN         NaN      +
Изменили только роли в тех строках, которые соответствуют двум условиям сразу.
 
Задача №4
Найдите всех членов команды, которые одновременно занимаются экспериментом и работают над статьей. Напечатайте на экране соответствующие строки таблицы. Для этого примените атрибут loc и выражение с условием на значение столбца.
import pandas as pd

data = pd.read_csv('/datasets/projects.csv')
rows = (data['Эксперимент'] == '+') & (data['Статья'] == '+')
print (data.loc[rows])
 
Задача №5
Снимите разработчиков с проекта «Новая функция» — только тех, кто был ранее в нём задействован. Для этого поставьте минус в соответствующих ячейках таблицы. Просто потому что можете, а не потому что это хорошая идея. Используйте для этого атрибут loc и выражение с условием на значение столбца. Выведите на экран изменённую таблицу.
import pandas as pd

data = pd.read_csv('/datasets/projects.csv')
data.loc[(data['Роль'] == 'разработчик')  & (data['Новая функция'] == '+'), 'Новая функция'] = '-'
print (data)
Напоследок о разнице между loc и его сокращенной записью. Вот эти две записи на примере поиска всех работающих над новой функцией:
# полная запись
print(data.loc[data['Новая функция'] == '+'])

# сокращённая запись
print(data[data['Новая функция'] == '+'])

Сокращённая запись вам уже встречалась, но в этом уроке мы специально про неё не говорили, чтобы вас не запутать. Её применение ограничено:

  • Если мы передаем только условие (как в примере выше), то можно использовать любую из двух записей, они идентичны. Логические операторы тоже можно использовать.
  • Если мы хотим указать и условие, и столбец, подойдет только полная запись с loc.
  • Если мы хотим изменить значения в таблице, подойдет только полная запись с loc.

8.Работа с пропусками в категориальных переменных

Вы уже познакомились с одной из стратегий работы с пропусками в категориальных переменных в задаче про Рона и Гриффиндор. Факультет Рона вы знали наверняка (или могли уточнить), и восстановить пропущенный Гриффиндор не составило труда. Однако, далеко не всегда удается уточнить пропущенные данные и заменить их вручную.

Значения None остались в источниках трафика, а значения NaN – в столбце с имейлами. Что делать с ними?

Прежде всего, нужно ответить на вопрос, существует ли закономерность в появлении пропусков. Иными словами, не случайно ли их возникновение в наборе данных.

На примере таблицы с результатами анкетирования персонажей «Игры престолов» изучите типы пропусков.

import pandas as pd

game_survey = pd.read_csv('/datasets/game_of_thrones.csv')

pic .

Пропуски бывают трёх типов:

  • Полностью случайные: если вероятность встретить пропуск не зависит ни от каких других значений. Таков пропуск пола Сансы Старк. Ответ на этот вопрос не зависит от характера самого вопроса и от других вопросов анкеты, а сам пропуск легко восстановить по имени.
  • Случайные: если вероятность пропуска зависит от других значений в наборе данных, но не от значений собственного столбца. Случайным пропуском будет пропуск рода Джона Сноу. Пропущенное значение связано с тем, что рода Сноу не существует.
  • Неслучайные: если вероятность пропуска зависит от других значений, в том числе и от значений собственного столбца. Это пропуск в политических намерениях Брана Старка: он не указал их нарочно, ведь умеет предвидеть будущее и не собирается сообщать о своих планах. Отсутствующее значение зависит как от характера вопроса, так и от особенности самого Брана Старка, то есть, значения переменной в другом столбце.

Существует несколько вариантов замены пропусков категориальных значений. Например, замена значением по умолчанию. Такой вариант хорошо подойдёт для заполнения случайных пропусков. В таблице с результатами анкетирования нельзя заполнить род Джона Сноу, но для выполнения операций отсутствующее значение мешает. Заменим его на пустую строку.

game_survey['family'] = game_survey['family'].fillna(value='')

Иногда пропуски в категориальных столбцах могут принимать не стандартное значение None без определённого типа (NoneType), а значение типа str: например, 'None''-''Null'. В таких случаях метод fillna() не подойдёт — он работает только со значениями NaN или None. Для замены строковых значений вызывают атрибут loc, он осуществляет логическую индексацию — выбор значений по заданному условию. Логическая индексация позволяет найти в столбце значения 'None' или другие значения типа str и заменить их. pic Таким способом можно заполнить полностью случайный пропуск в столбце gender.

game_survey.loc[game_survey['gender'] == 'None', 'gender'] = 'женский'

Ранее вы считали количество визитов и покупок в задаче для Яндекс.Маркета. Посмотрим на результаты:

print(logs.groupby('source')['purchase'].count())

source
None         1674
context     52032
email       12279
other      133834
undef         181
Name: purchase, dtype: int64

Число визитов из источника undef значительно меньше любого другого источника трафика. Ещё раз взглянем на количество покупок из этого источника:

purchase = logs.groupby('source')['purchase'].sum()

source
None        108
context    3029
email       913
other      8041
undef        12
Name: purchase, dtype: int64

Ранее вы находили конверсию так:

import pandas as pd

logs = pd.read_csv('/datasets/logs.csv')

visits = logs.groupby('source')['purchase'].count()
purchase = logs.groupby('source')['purchase'].sum()

conversion = purchase / visits
print(conversion)

Сперва посчитали количество строк с визитами, а затем суммировали значения в строках, чтобы найти число покупок. Для группировки столбца 'source' вызывали две функции: count() и sum().

Однако количество действий для решения задачи можно сократить.

Вызовем метод agg(), указывающий, какие именно функции применить к столбцу 'purchase'. Название столбца и сами функции запишем в особую структуру данных — словарь. Словарь состоит из ключа и значения:

{'purchase': ['count','sum']}

Здесь ключ — это название столбца, к которому нужно применить функции, а значением выступает список с названиями функций. pic Результат выполнения кода сохраним в переменной logs_grouped:

logs_grouped = logs.groupby('source').agg({'purchase': ['count', 'sum']})

purchase       
source     count   sum        
None        1674   108
context    52032  3029
email      12279   913
other     133834  8041
undef        181    12

Методом agg() посчитали все необходимые значения в одной таблице.

Названия столбцов после такого действия стали «двойными».

Чтобы обратиться к сумме покупок ['sum'] столбца ['purchase'], просто укажите их подряд:

logs_grouped['purchase']['sum']

Разберёмся с пропусками в данных Яндекс.Маркета и решим задачу.

Задача №1

В столбце email встречаются значения NaN — вместо электронных почт пользователей, не подписавшихся на рассылку магазина. Их электронный адрес вы вряд ли узнаете, и не сможете заполнить пропуски вручную. Да и самих NaN слишком много для ручной замены.

Тем не менее избавиться от значений NaN можно, если заменить их единым значением. Например, пустой строкой. Так изучать таблицу будет проще: не нужно будет различать NaN и email-адрес.

Замените пропуски пустыми строками, используя знакомый метод fillna(). После этого преобразования выведите на экран первые 5 строк датафрейма.

import pandas as pd

logs = pd.read_csv('/datasets/logs.csv')
logs['email'] = logs['email'].fillna('')
print (logs.head(5))

Задача №2

Пропуски в столбце source записаны в строковом формате — 'None' вместо None.

Выясните, случайно ли их возникновение: проверьте, имеет ли каждая строка с источником 'None' определённый email.

Для этого примените к датафрейму logs два фильтра: Источник source равен 'None'; Значение столбца email равно пустой строке ''.

Выведите датафрейм с применёнными фильтрами. Переменную с датафреймом при этом перезаписывать не нужно.

import pandas as pd

logs = pd.read_csv('/datasets/logs.csv')
logs['email'] = logs['email'].fillna(value='')
print (logs.loc[(logs['source'] == 'None')&(logs['email'] == '')])

Датафрейм пуст: у всех строк без источника есть email. Пользователи оставляют свой электронный адрес только в случае подписки на email-рассылку. Получается, подписчикам из этих строк не был присвоен их источник трафика: 'email'.

Задача №3

Замените пропуски в столбце source на значение 'email'. Проверьте результат методом value_counts().

import pandas as pd

logs = pd.read_csv('/datasets/logs.csv')
logs['email'] = logs['email'].fillna(value='')
logs.loc[logs['source'] == 'None', 'source'] = 'email'
print(logs['source'].value_counts())
other      133834
context     52032
email       13953
undef         181
Name: source, dtype: int64

Больше никаких None и NaN. Пропуски в категориальных переменных устранены.

Задача №4

Посчитайте количество визитов и покупок по источнику трафика ('source'). Вызовите метод agg. Сохраните результат в переменной logs_grouped и выведите на экран.

import pandas as pd

logs = pd.read_csv('/datasets/logs.csv')
logs['email'] = logs['email'].fillna(value='')
logs.loc[logs['source'] == 'None', 'source'] = 'email'
#запишите ваш код сюда
logs_grouped = logs.groupby('source').agg({'purchase':['count','sum']})
print (logs_grouped)
purchase
           count   sum
source
context    52032  3029
email      13953  1021
other     133834  8041
undef        181    12

Задача №5

Посчитайте конверсию визитов в покупки для каждого источника трафика (т. е. отношение столбца sum к count). Сохраните результат в новый столбец logs_grouped['conversion'] и выведите обновлённую таблицу на экран.

import pandas as pd

logs = pd.read_csv('/datasets/logs.csv')
logs['email'] = logs['email'].fillna(value='')
logs.loc[logs['source'] == 'None', 'source'] = 'email'

logs_grouped = logs.groupby('source').agg({'purchase': ['count', 'sum']})
logs_grouped['conversion'] = logs_grouped['purchase']['sum'] / logs_grouped['purchase']['count']
print (logs_grouped)

Для неопределенного источника трафика undef значение конверсии близко к источнику other. Поэтому можно объединить данные по ним обоим.

Задача №6

У 'undef' всего 12 покупок. Эта категория на порядки отличается от своих более объёмных конкурентов, и сравнивать их некорректно. Объедините её с одной из «больших» категорий в данных, похожей на 'undef' своей конверсией. Замените значение источника 'undef' на 'other' и посчитайте конверсию в покупки для каждого источника трафика после замены. Выведите logs_grouped на экран.

import pandas as pd

logs = pd.read_csv('/datasets/logs.csv')
logs['email'] = logs['email'].fillna(value='')
logs.loc[logs['source'] == 'None', 'source'] = 'email'

logs.loc[logs['source'] == 'undef', 'source'] = 'other'

logs_grouped = logs.groupby('source').agg({'purchase': ['count', 'sum']})
logs_grouped['conversion'] = logs_grouped['purchase']['sum'] / logs_grouped['purchase']['count']
print (logs_grouped)

Работа с пропусками в источниках завершена! В нашем случае email-рассылки оказались самым эффективным источником трафика.

9.Работа с пропусками в количественных переменных

Самая высокая конверсия у email-сообщений, а контекстная реклама немного подводит. Анализ на этом может быть закончен, но аналитик должен уметь решать задачи «вокруг».

Кроме источников трафика, из Яндекс.Метрики можно получить агрегированную информацию о пользователях.

import pandas as pd

metrica = pd.read_csv('/datasets/metrica_data.csv')
print(metrica.head(10))

user_id		device_type		age		time
7141786820	desktop			33.0	2127.0
5644686960	mobile			30.0	35.0
1914055396	desktop			25.0	NaN
4099355752	desktop			25.0	2123.0
6032477554	desktop			27.0	59.0
5872473344	mobile			27.0	NaN
7977025176	mobile			NaN		NaN
3512872755	desktop			40.0	65.0
1827368713	desktop			37.0	NaN
8688870165	desktop			36.0	2124.0

user_id — идентификатор пользователя device_type — тип устройства пользователя age — возраст пользователя time — время на сайте в секундах

Вроде бы всё готово к анализу данных, но снова появились пропуски. Для некоторых пользователей не указаны возраст и время, проведённое на сайте.

Время и возраст — количественные переменные. Пропуски в таких переменных заполняют характерными значениями. Это значения, характеризующие состояние выборки, — набора данных, выбранных для проведения исследования. Чтобы примерно оценить типичные значения выборки, годятся среднее арифметическое или медиана.

Среднее арифметическое — это сумма всех значений, поделённая на количество значений. pic Подсчитывается методом mean(). Напомним: его применяют ко всей таблице, к отдельному столбцу или к сгруппированным данным. Вычислим средний рост актёров, исполнявших роли учеников Хогвартса:
pic .

magician_stats = pd.DataFrame(
    {
        "student": [
            "Гарри Поттер",
            "Гермиона Гренджер",
            "Полумна Лавгуд",
            "Рон Уизли",
            "Седрик Диггори",
        ],
        "height": [173, 165, 158, 173, 185],
    }
)

# Для получения среднего значения вызовем метод mean():
print(magician_stats['height'].mean())
>>> 170.8 

Медиана — это такое число в выборке, что ровно половина элементов больше него, а другая половина — меньше. pic Чтобы посчитать медиану списка значений [3, 0, 2, 9, 4], сначала упорядочим их по возрастанию: [0, 2, 3, 4, 9]. Медиана здесь число 3: слева и справа от него одинаковое количество значений. Если значений чётное количество, то берут среднее двух значений, оказавшихся посередине. Для набора [0, 2, 3, 4, 9, 22] посередине 3 и 4. Медианой будет их среднее: 3.5.

Для нахождения медианы есть специальный метод median(). Как и mean(), его можно применять к таблице, столбцу или сгруппированным данным.

Зачем нужна медиана, если есть среднее?

Среднее значение некорректно характеризует данные, когда некоторые значения сильно выделяются среди большинства. Например, 5 сотрудников компании получают зарплату 100 000 рублей. Инвестор пригласил директора по маркетингу с зарплатой 300 000 рублей. На сколько процентов выросла средняя оплата труда в коллективе?

Зарплаты первоначального состава команды приведены в old_staff. В версии с директором по маркетингу — в new_director.

import pandas as pd

old_staff = pd.Series([100, 100, 100, 100, 100])
new_director = pd.Series([100, 100, 100, 100, 100, 300])

Вызвав метод mean(), рассчитаем среднее значение зарплаты в старом и новом коллективах:

old_staff_mean = old_staff.mean()
new_director_mean = new_director.mean()

Чтобы ответить, на сколько процентов выросла средняя зарплата в команде, поделим их друг на друга:

new_director_mean / old_staff_mean - 1  

Дробь в формуле показывает, во сколько раз средняя зарплата в новой команде больше средней зарплаты в старой. Единицу отнимаем, чтобы определить, на какую долю выросла средняя зарплата после прихода директора по маркетингу. Результат выведем как привычно, в процентах:

print(f'Зарплата выросла на {new_director_mean / old_staff_mean - 1:.0%}')

Зарплата выросла на 33%

Вот так, ловким приёмом на работу нового высокооплачиваемого сотрудника средняя зарплата всех членов команды повышается на 33%. Как в известном анекдоте: у Пети 10 яблок, а у Васи 0 — в среднем у обоих по 5 яблок. Когда в выборке присутствуют выдающиеся значения (300 против 100), лучше использовать медиану.

Применим median() к набору данных new_director

new_director_median = new_director.median()
print(new_director_median)

100.0

Значит, зарплатная медиана как была равна 100, так и останется после прихода директора по маркетингу. Это более объективная информация о зарплате сотрудников, чем среднее значение. Проанализируем данные о пользователях и поищем факторы помимо источника трафика, которые влияли на решение о покупке.

Задача №1

Прочитайте данные из файла metrica_data.csv.

Результат сохраните в переменной metrica.

Посчитайте средний возраст пользователей и сохраните его в переменной age_avg.

Выведите результат на экран.

Путь к файлу: /datasets/metrica_data.csv

import pandas as pd
metrica = pd.read_csv('/datasets/metrica_data.csv')
age_avg = metrica['age'].mean()
print (age_avg)

В случае возраста считать среднее — правильно. В таблице нет выдающихся значений, потому и среднее корректно характеризует данные.

Задача №2

Замените пропущенные значения в столбце age на средний возраст. Выведите на экран первые 10 строк набора данных.

import pandas as pd

metrica = pd.read_csv('/datasets/metrica_data.csv')
age_avg = metrica['age'].mean()
metrica['age'] = metrica['age'].fillna(age_avg)
print (metrica.head(10))

Пропуски в столбце с возрастом нам больше не помеха.

Задача №3

Найдите среднее время просмотра сайта и сохраните в переменной time_avg. Выведите результат на экран.

import pandas as pd

metrica = pd.read_csv('/datasets/metrica_data.csv')
#запишите среднее время просмотра 
time_avg = metrica['time'].mean()
print (time_avg)

Пользователи в среднем проводят около 23 минут на сайте. Это достаточно много, но как на это значение влияет разброс данных?

Задача №4

Можно заменить время на среднее значение. Однако пользователи заходят в интернет то с мобильного устройства, то с компьютера. Учтём этот факт для повышения точности заполнения пропущенных данных о времени на сайте.

Выберите строки таблицы с данными о просмотрах с компьютера, т.е. такие, где в столбце 'device_type' указано значение 'desktop'.

Сохраните результат в переменной desktop_data и выведите первые 5 строк на экран.

import pandas as pd

metrica = pd.read_csv('/datasets/metrica_data.csv')
desktop_data = metrica[metrica['device_type']=='desktop']
print (desktop_data.head(5))

      user_id device_type   age    time
0  7141786820     desktop  33.0  2127.0
2  1914055396     desktop  25.0     NaN
3  4099355752     desktop  25.0  2123.0
4  6032477554     desktop  27.0    59.0
7  3512872755     desktop  40.0    65.0

Теперь можем получить среднее значение для пользователей десктопных платформ.

Задача №5

Установите, сколько времени в среднем проводят на сайте пользователи компьютеров. Результат сохраните в переменной desktop_data_time_avg. Закомментируйте вывод предыдущего задания и выведите значение desktop_data_time_avg на экран.

import pandas as pd

metrica = pd.read_csv('/datasets/metrica_data.csv')
desktop_data = metrica[metrica['device_type']=='desktop']
desktop_data_time_avg = desktop_data['time'].mean()
#print (desktop_data.head(5))
print (desktop_data_time_avg)

1741.8747158537378 = 29 минут — это больше, чем общее среднее время. Значит, пользователям комфортнее изучать сайт с компьютера.

Задача №6

Получите таблицу с данными о просмотрах с мобильных платформ. Сохраните результат в переменной mobile_data и выведите первые 5 строк на экран.

import pandas as pd

metrica = pd.read_csv('/datasets/metrica_data.csv')
mobile_data = metrica[metrica['device_type']=='mobile']
print (mobile_data.head(5))

       user_id device_type   age  time
1   5644686960      mobile  30.0  35.0
5   5872473344      mobile  27.0   NaN
6   7977025176      mobile   NaN   NaN
10  7172802697      mobile  30.0   NaN
14  9312844109      mobile   NaN  40.0
Аналитики Яндекса в 2015 году заметили, что с мобильных устройств в интернет заходит больше пользователей, чем с настольных компьютеров. Так что сейчас вы получите очень важную величину.

Задача №7

Посчитайте среднее время пребывания на сайте пользователей мобильных платформ. Результат сохраните в переменной mobile_data_time_avg. Закомментируйте вывод предыдущего задания и выведите значение mobile_data_time_avg на экран.

import pandas as pd

metrica = pd.read_csv('/datasets/metrica_data.csv')
mobile_data = metrica[metrica['device_type']=='mobile']
mobile_data_time_avg = mobile_data['time'].mean()
#print (mobile_data.head(5))
print (mobile_data_time_avg)

41.15691239238949

Всего 41 секунда! Видимо, с мобильной версией какие-то проблемы и об этом нужно сообщить. Если ничего не предпринять, результаты вливаний в увеличение трафика разочаруют инвестора. Сколько бы высокооплачиваемых директоров по маркетингу он ни нанимал.

10.Заполнение пропусков в количественных переменных по категориям

 

Вы уже определили, что на разных видах устройств среднее время просмотра сайта значительно различается. Для смартфонов — 41 секунда, а для компьютеров — 23 минуты. В других уроках при решении задач использовалось общее среднее время. Но в этом случае лучше заполнить пропуски в столбце time средним временем отдельно для каждой категории.

Вам потребуется изобразить процесс вычислений:

  • Перебрать все уникальные категории — значения desktop и mobile в столбце device_type.
  • По отдельности найти среднее целевого столбца time для строк датафрейма с desktop в столбце device_type и для mobile. Получится два средних значения.
  • Для каждого значения категории найти в датафрейме все строки, подходящие этому значению категории. То есть все строки со значением desktop в столбце device_type и пропусками в столбце time. И все строки со значением mobile в столбце device_type и пропусками в столбце time.
  • В каждую из этих строк записать соответствующее среднее значение по категории (desktop / mobile). В коде это будет выглядеть так:
# импортируем библиотеку pandas
import pandas as pd

# создаём датафрейм metrica из CSV-файла
metrica = pd.read_csv('/datasets/metrica_data.csv')

# перебираем каждый тип девайса в наборе уникальных значений столба device_type
for d in metrica['device_type'].unique():
    # на каждом шаге цикла с помощью атрибута loc выбираем строки,
    # в которых в device_type текущий тип девайса (d) и есть пропуски в time 
    metrica.loc[(metrica['device_type'] == d) & (metrica['time'].isna()), 'time'] = \
    metrica.loc[(metrica['device_type'] == d), 'time'].mean()
    # и записываем в них среднее значение time среди строк с текущим типом девайса (d)

# проверяем, что все пропуски заполнены
print(metrica['time'].isna().sum())
Результат 0

11.Заключение

Вы оценили эффективность источников трафика Яндекс.Маркета и определили выгодный канал привлечения с точки зрения повторных покупок.

Посмотрим на финальные значения:

  • email — 7,3%
  • other — 6%
  • context — 5,8%

Контекстная реклама и другие источники трафика показали примерно одинаковый результат. Стоит порекомендовать маркетологам проверить настройки контекстной рекламы, а также исследовать другие источники трафика и их метрики.

Вы изучили данные о поведении пользователей и выяснили, что они проводят на сайте больше времени, если зашли не с мобильного устройства, а с компьютера. Обратите внимание коллег и представьте вывод в отчёте о работе.

Заберите с собой

Чтобы ничего не забыть, скачайте шпаргалку и конспект темы.

Где ещё почитать про обработку пропущенных значений

Дополнительная информация про обработку пропусков в данных

12.Проверочные задания. Работа с пропусками