Задача №1
Методом read_excel()
прочтите первый лист 'traffic_data'
Выведите на экран первые 5 строк листа методом head()
. Прочитайте названия столбцов:
subcategory_id
— идентификатор товарной подкатегории, или её зашифрованное название;source
— источник трафика. В нашем случае источников два: прямой заход на сайт в таблице обозначен какdirect
, переход из поисковых систем —organic
;visits
— количество визитов на страницу подкатегории за отчётный период.
Путь к файлу: /datasets/seo_data.xlsx
import pandas as pd
data = pd.read_excel('/datasets/seo_data.xlsx', sheet_name='traffic_data')
print(data.head(5))
subcategory_id | source | visits |
---|---|---|
0 cf2e61c7af | direct | 501165.668858 |
1 0cd903d1cc | direct | 126342.359505 |
2 ef35bc88a7 | direct | 95626.321402 |
3 6ff9f4014c | direct | 75680.653002 |
4 72bc238e4d | direct | 64435.934651 |
Первый лист с выгрузкой по посещаемости товарных подкатегорий сайта доступен для анализа в Python. Осталось проделать то же самое с другими листами.
Задача №2
Пока в первых 5 строчках таблицы виден только один источник трафика direct. Проверьте, какие источники есть в столбце source. Выведите на экран список уникальных значений этого столбца.
import pandas as pd
data = pd.read_excel('/datasets/seo_data.xlsx', sheet_name='traffic_data')
print(data['source'].unique())
['direct' 'organic']
Думали, там только 'direct'? А там вообще-то и 'organic' имеется!
Задача №3
Методом read_excel()
прочтите второй лист 'subcategory_ids'
и сохраните его в переменной subcategory_dict
. Выведите на экран его первые 5 строк методом head()
.
Обратите внимание на названия столбцов: к знакомым нам идентификаторам подкатегорий (subcategory_id
) добавились идентификаторы категорий (category_id
) и названия подкатегорий (subcategory_name
).
Всё это похоже на словарь, где идентификаторам подкатегорий из цифр и латинских букв соответствуют понятные нам названия. Поэтому датафрейм называется subcategory_dict
.
Путь к файлу: /datasets/seo_data.xlsx
import pandas as pd
subcategory_dict = pd.read_excel('/datasets/seo_data.xlsx','subcategory_ids')
print (subcategory_dict.head(5))
subcategory_id | subcategory_name | category_id |
---|---|---|
0 cf2e61c7af | Мобильные телефоны | 09f279a643 |
1 0cd903d1cc | Ноутбуки | 3509869a61 |
2 ef35bc88a7 | Телевизоры | 09f279a643 |
3 6ff9f4014c | Планшеты | 3509869a61 |
4 72bc238e4d | Наушники и Bluetooth-гарнитуры | 09f279a643 |
Второй лист доступен для анализа в Python. Теперь вы знаете не только посещаемость товарных подкатегорий, но и их реальные названия.
Задача №4
Наконец, методом read_excel()
прочтём третий лист category_ids и сохраним его в переменной category_dict. Выведите на экран первые 5 строк листа методом head().
Путь к файлу: /datasets/seo_data.xlsx
import pandas as pd
category_dict = pd.read_excel('/datasets/seo_data.xlsx','category_ids')
print (category_dict.head(5))
category_id | category_name |
---|---|
0 09f279a643 | Электроника |
1 3509869a61 | Компьютерная техника |
2 09f279a643 | Электроника |
3 3509869a61 | Компьютерная техника |
4 09f279a643 | Электроника |
Вы научились читать экселевские файлы. Самое время применить к ним доступные в Python методы анализа.
Данные загружены и выглядят корректными. Нам нужно соотношение прямого и поискового трафика для каждой категории. Оценим, как обстоят дела с поисковой оптимизацией вообще — разделим число визитов по прямым ссылкам на число заходов с поисковиков.
Сгруппируем датафрейм 'data' по источнику трафика и посчитаем сумму визитов:
import pandas as pd
data = pd.read_excel('/datasets/seo_data.xlsx', sheet_name='traffic_data')
print(data.groupby('source').sum())
source | subcategory_id |
---|---|
direct | cf2e61c7af0cd903d1ccef35bc88a76ff9f4014c72bc23... |
organic | cf2e61c7af0cd903d1ccef35bc88a76ff9f4014c72bc23... |
Вместо ожидаемого результата получили странное склеивание идентификаторов подкатегорий. А где же сумма визитов?
Разберитесь, почему сумма визитов не считается. Проверьте тип данных методом info().
import pandas as pd
data = pd.read_excel('/datasets/seo_data.xlsx', sheet_name='traffic_data')
print (data.info())
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 1930 entries, 0 to 1929
Data columns (total 3 columns):
//// | Column | Non-Null | Count | Dtype |
---|---|---|---|---|
0 | subcategory_id | 1930 | non-null | object |
1 | source | 1930 | non-null | object |
2 | visits | 1930 | non-null | object |
dtypes: object(3) | ||||
memory usage: 45.4+ KB |
NoneВот и причина ошибки! Почему-то Pandas посчитал визиты не числовыми, а строковыми значениями. Научимся исправлять это недоразумение в следующем уроке.
Задача №1
Переведите значения столбца 'id'
из строк в числа методом pd.to_numeric()
. Не используйте аргумент errors. В результате правильного выполнения задания вы получите ошибку — так и должно быть.
import pandas as pd
transactions = pd.read_excel('/datasets/ids.xlsx')
transactions['id'] = pd.to_numeric(transactions['id'])
Результат
Traceback (most recent call last):
File "main.py", line 4, in <module>
ValueError: Unable to parse string "Null" at position 48
Вот и ошибка! ValueError: Unable to parse string "Null" at position 48: на строке 48 вместо числового ID строка Null. Метод отработал по дефолту.
Задача №2
Попробуйте ещё раз перевести значения столбца 'id'
из строк в числа методом to_numeric()
, но уже со значением 'coerce'
параметра errors
. Это заменит вызывающий ошибку Null
на NaN
.
Полученную таблицу выведите на экран методом tail(): так как ошибка возникает на последней строке, 5 значений с конца будет достаточно.
import pandas as pd
transactions = pd.read_excel('/datasets/ids.xlsx')
transactions['id'] = pd.to_numeric(transactions['id'],errors='coerce')
print (transactions.tail(5))
\\ | id | category | amount |
---|---|---|---|
44 | 6.007483e+11 | A | 8958.23 |
45 | 6.007483e+11 | C | 12771.1 |
46 | 6.007483e+11 | E | 9630.56 |
47 | 6.007483e+11 | Null | Null |
48 | NaN | A | 14327.22 |
Значение на последней строке столбца c id теперь не Null, а NaN! Проверим, повлияло ли это на тип столбца.
Задача №3
Вызовите метод info() после преобразований ещё раз. Проверьте, повлияла ли работа pd.to_numeric(transactions['id'], errors='coerce')
на тип значений в столбце id.
import pandas as pd
transactions = pd.read_excel('/datasets/ids.xlsx') transactions['id'] = pd.to_numeric(transactions['id'], errors='coerce') print (transactions.info())
<class 'pandas.core.frame.DataFrame'> RangeIndex: 49 entries, 0 to 48 Data columns (total 3 columns):
\ | Column | Non-Null | Count | Dtype |
---|---|---|---|---|
0 | id | 48 non-null | float64 | |
1 | category | 49 non-null | object | |
2 | amount | 49 non-null | object |
dtypes: float64(1), object(2) memory usage: 1.3+ KB None
Теперь Pandas распознаёт столбец 'id' как числовой. Это дает возможность проделывать с идентификаторами транзакций математические операции.
Задача №4
Методом to_numeric()
превратите значения столбца amount
в числа, заменив некорректные значения на NaN. Проверьте результаты преобразований методом info()
.
import pandas as pd
transactions = pd.read_excel('/datasets/ids.xlsx')
transactions['id'] = pd.to_numeric(transactions['id'], errors='coerce')
transactions['amount'] = pd.to_numeric(transactions['amount'], errors='coerce')
print (transactions.info())
<class 'pandas.core.frame.DataFrame'> RangeIndex: 49 entries, 0 to 48 Data columns (total 3 columns):
\ | Column | Non-Null | Count | Dtype |
---|---|---|---|---|
0 | id | 48 | non-null | float64 |
1 | category | 49 | non-null | object |
2 | amount | 45 | non-null | float64 |
dtypes: float64(2), object(1) memory usage: 1.3+ KB None
И идентификаторы, и продажи теперь числового типа. Вернёмся к расчёту суммы?
Задача №5
Посчитайте общую стоимость проданных товаров — сумму значений столбца amount в датафрейме transactions. Результат выведите на экран.
import pandas as pd
transactions = pd.read_excel('/datasets/ids.xlsx')
transactions['id'] = pd.to_numeric(transactions['id'], errors='coerce')
transactions['amount'] = pd.to_numeric(transactions['amount'], errors='coerce')
print (transactions['amount'].sum())
596107.1
Оцените сумму: это не просто цифра. Мы считаем деньги, которые кто-то заработал, собрал и за что-то милое сердцу заплатил.
Задача №6
Рассчитайте сумму продаж для каждой категории и сохраните в переменной transactions_per_category
. Для этого сгруппируйте датафрейм transactions
по столбцу category
и примените метод sum()
к столбцу amount
. Выведите результат на экран.
import pandas as pd
transactions = pd.read_excel('/datasets/ids.xlsx')
transactions['id'] = pd.to_numeric(transactions['id'], errors='coerce')
transactions['amount'] = pd.to_numeric(transactions['amount'], errors='coerce')
# Рассчитайте сумму продаж для каждой категории
transactions_per_category = transactions.groupby('category')['amount'].sum()
print (transactions_per_category)
category
A 133988.50
B 168617.89
C 173332.50
D 62630.82
E 57537.39
Null 0.00
Name: amount, dtype: float64
Невероятно, но факт: посчитать сумму гораздо легче, если имеешь дело с числами.
Задача №7
Вернитесь к таблице с трафиком: вы сможете найти сумму визитов.
Раньше вместо неё получались склеенные названия категорий, а столбец visits
определялся как строковый (тип object
).
Попробуйте перевести значения столбца visits
датафрейма data
в числовой тип методом to_numeric()
. Не используйте аргумент errors
. В результате правильного выполнения задания вы должны получить ошибку — так и должно быть.
import pandas as pd
data = pd.read_excel('/datasets/seo_data.xlsx', sheet_name='traffic_data')
data['visits'] = pd.to_numeric(data['visits'])
Traceback (most recent call last):
File "main.py", line 4, in <module>
ValueError: Unable to parse string ""2369468"" at position 964
Опыт, сын ошибок трудных!
ValueError: Unable to parse string ""2369468"" at position 964:
на 964-й строке: в столбце с визитами внезапно появилось строковое значение.
Задача №8
Узнайте, что не так со строкой 964. Используйте атрибут loc для вывода этой строки на экран. Он позволяет обращаться к датафрейму по значению индекса, в нашем случае как раз по номеру строки.
import pandas as pd
data = pd.read_excel('/datasets/seo_data.xlsx', sheet_name='traffic_data')
print (data.loc[964,:])
subcategory_id total
source direct
visits "2369468"
Name: 964, dtype: object
Вот и причина ошибки. Судя по названию подкатегории 'total' (англ. total — «итог»), при выгрузке были добавлены промежуточные итоги для каждого источника. А само значение итоговой суммы зачем-то написали в кавычках.
Задача №9
Выведите на экран общее количество строк в датафрейме и строки таблицы, которые имеют значение 'total'
в столбце 'subcategory_id'
.
Изучите полученные результаты: сколько строк портят весь датасет?
Формат должен быть следующим:
Количество строк: ...
subcategory_id source visits Unnamed: 3
964 ... ... ... ...
1929 ... ... ... ...
import pandas as pd
data = pd.read_excel('/datasets/seo_data.xlsx', sheet_name='traffic_data')
print ('Количество строк:', data.shape[0])
print (data[data['subcategory_id'] == 'total'])
Количество строк: 1930
\ | subcategory_id | source | visits |
---|---|---|---|
964 | total | direct | "2369468" |
1929 | total | organic | "5687882" |
Кривых строк всего две, а портят они почти 2 тысячи.
Задача №10
Оставьте в датафрейме только строки, удовлетворяющие условию data['subcategory_id'] != 'total'
. Проверьте результат: выведите на экран датафрейм с условием data['subcategory_id'] == 'total'
.
import pandas as pd
data = pd.read_excel('/datasets/seo_data.xlsx', sheet_name='traffic_data')
data = data[data['subcategory_id'] != 'total']
print (data[data['subcategory_id'] == 'total'])
Empty DataFrame
Columns: [subcategory_id, source, visits]
Index: []
У вас отлично получается избавляться от лишнего!
Задача №11
Измените тип данных в столбце ['visits']
на integer
. Проверьте полученный результат, вызвав метод info()
.
import pandas as pd
data = pd.read_excel('/datasets/seo_data.xlsx', sheet_name='traffic_data')
data = data[(data['subcategory_id'] != 'total')]
data['visits'] = data['visits'].astype ('int')
print (data.info())
<class 'pandas.core.frame.DataFrame'> Int64Index: 1928 entries, 0 to 1928 Data columns (total 3 columns):
\ | Column | Non-Null | Count | Dtype |
---|---|---|---|---|
0 | subcategory_id | 1928 | non-null | object |
1 | source | 1928 | non-null | object |
2 | visits | 1928 | non-null | int64 |
dtypes: int64(1), object(2) memory usage: 60.2+ KB None Целочисленные значения в столбце с визитами — это просто красиво. В конце концов, нельзя же совершить половину или полтора визита!
Задача №12
Сгруппируйте данные по источникам и вычислите количество визитов для каждого источника. Выведите результат на экран.
import pandas as pd
data = pd.read_excel('/datasets/seo_data.xlsx', sheet_name='traffic_data')
data = data[(data['subcategory_id'] != 'total')]
data['visits'] = data['visits'].astype('int')
print (data.groupby('source')['visits'].sum())
source
direct 2368980
organic 5687407
Name: visits, dtype: int64
На органический трафик приходится в два раза больше визитов пользователей. А как на любимые сайты попадаете вы: из закладок или поиска?
import pandas as pd
arrivals = pd.read_excel('/datasets/arrivals.xlsx')
print(arrivals.head())
\ | date | login | target_time |
---|---|---|---|
0 | 01.04.2019Z11:03:00 | alex | 2019-04-01Z11:00:00 |
1 | 02.04.2019Z11:08:00 | alex | 2019-04-02Z11:00:00 |
2 | 03.04.2019Z11:19:00 | alex | 2019-04-03Z11:00:00 |
3 | 04.04.2019Z10:58:00 | alex | 2019-04-04Z11:00:00 |
4 | 05.04.2019Z11:07:00 | alex | 2019-04-05Z11:00:00 |
В столбце 'date'
записано фактическое время прихода сотрудника. В столбце 'target_time'
— во сколько он должен был явиться на планёрку.
Проверим методом info()
тип данных в столбце 'date'
:
arrivals.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 10 entries, 0 to 9
Data columns (total 3 columns):
date 10 non-null object
login 10 non-null object
target_time 10 non-null object
dtypes: object(3)
memory usage: 320.0+ bytes
Методом to_datetime()
превратим содержимое этого столбца в понятные для Python даты. Для этого строку форматируют, обращаясь к специальной системе обозначений, где:
- %d — день месяца (от 01 до 31)
- %m — номер месяца (от 01 до 12)
- %Y — четырёхзначный номер года (например, 2019)
- Z — стандартный разделитель даты и времени
- %H — номер часа в 24-часовом формате
- %I — номер часа в 12-часовом формате
- %M — минуты (от 00 до 59)
- %S — секунды (от 00 до 59)
Преобразуем формат даты 01.04.2019Z11:03:00 из первой строчки датафрейма:
- Сначала номер дня месяца. В соответствии с таблицей форматов заменяем его на %d: %d.04.2019Z11:03:00
- Далее точка (ее оставляем без изменений), потом номер месяца: %m: %d.%m.2019Z11:03:00
- После четырёхзначный номер года, заменяем 2019 на %Y: %d.%m.%YZ11:03:00
- Букву Z оставляем без изменений: %d.%m.%YZ11:03:00
- Номер часа в 24-часовом формате заменим на %H: %d.%m.%YZ%H:03:00
- Количество минут обозначим %M: %d.%m.%YZ%H:%M:00
- Завершим форматирование обозначением секунд %S: %d.%m.%YZ%H:%M:%S Вот такое выражение '%d.%m.%YZ%H:%M:%S' передают в аргумент format метода
to_datetime()
при переводе строковых значений столбца 'date' в формат datetime:
arrivals['date_datetime'] = pd.to_datetime(
arrivals['date'], format='%d.%m.%YZ%H:%M:%S'
)
print(arrivals.head())
\ | date | login | target_time | date_datetime |
---|---|---|---|---|
0 | 01.04.2019Z11:03:00 | alex | 2019-04-01Z11:00:00 | 2019-04-01 11:03:00 |
1 | 02.04.2019Z11:08:00 | alex | 2019-04-02Z11:00:00 | 2019-04-02 11:08:00 |
2 | 03.04.2019Z11:19:00 | alex | 2019-04-03Z11:00:00 | 2019-04-03 11:19:00 |
3 | 04.04.2019Z10:58:00 | alex | 2019-04-04Z11:00:00 | 2019-04-04 10:58:00 |
4 | 05.04.2019Z11:07:00 | alex | 2019-04-05Z11:00:00 | 2019-04-05 11:07:00 |
А у значений столбца '*target_time*'
другой способ записи даты: 2019-04-01Z11:00:00. Значит, и в аргументе format сохраним другое выражение: '%Y-%m-%dZ%H:%M:%S':
arrivals['target_datetime'] = pd.to_datetime(
arrivals['target_time'], format='%Y-%m-%dZ%H:%M:%S'
)
print(arrivals.head())
\ | date | login | target_time | date_datetime | target_datetime |
---|---|---|---|---|---|
0 | 01.04.2019Z11:03:00 | alex | 2019-04-01Z11:00:00 | 2019-04-01 11:03:00 | 2019-04-01 11:00:00 |
1 | 02.04.2019Z11:08:00 | alex | 2019-04-02Z11:00:00 | 2019-04-02 11:08:00 | 2019-04-02 11:00:00 |
Проверим, как после вызова datetime() изменился тип выгруженных дат:
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 10 entries, 0 to 9
Data columns (total 5 columns):
date 10 non-null object
login 10 non-null object
target_time 10 non-null object
date_datetime 10 non-null datetime64[ns]
target_datetime 10 non-null datetime64[ns]
dtypes: datetime64[ns](2), object(3)
memory usage: 480.0+ bytes
None
У новых столбцов тип данных datetime64. Можно добавить эти значения в исходные столбцы и работать с датами.
Среди самых разнообразных способов представления даты и времени особое место занимает формат unix time. Его идея проста — это количество секунд, прошедших с 00:00:00 1 января 1970 года. Время unix соответствует Всемирному координированному времени, или UTC.
Это интересно: почему UTC называется так?
По-английски о всемирном координированном времени сказали бы так: Coordinated Universal Time: CUT. По-французски эта же мысль будет выражена по-другому: Temps Universel Coordonné: TUC. Чтобы ни французам, ни англичанам не было обидно, выбрали нейтральный вариант: UTC.
В формате unix time дата и время хранятся в виде целого числа, увеличивающегося с каждой прошедшей секундой. Отсюда преимущества формата:
- хранение даты и времени в виде целого числа экономит место на диске;
- с датами-числами легко проводить арифметические операции;
- даты, записанные в виде целого числа, удобно принимать за единый формат.
Метод to_datetime()
работает и с форматом unix time
. Первый аргумент — это столбец со временем в формате unix time
, второй аргумент unit
со значением 's'
сообщит о том, что нужно перевести время в привычный формат с точностью до секунды.
Часто приходится исследовать статистику по месяцам: например, узнать, на сколько минут сотрудник опаздывал в среднем. Чтобы осуществить такой расчёт, нужно поместить время в класс DatetimeIndex и применить к нему атрибут month:
arrivals['month'] = pd.DatetimeIndex(arrivals['date_datetime']).month
Задача №1
Прочитайте файл с данными о позиции в поисковой выдаче за 3 месяца. Выведите первые 15 строк на экран. Путь к файлу: /datasets/position.csv
import pandas as pd
position = pd.read_csv('/datasets/position.csv')
print (position.head(15))
timestamp level page_id
0 2019-02-04T13:22:34 1 6ukoNykP
1 2019-02-06T15:30:54 1 Q62R1Ue7
2 2019-02-08T14:53:45 1 GmfSxgPs
3 2019-02-10T16:50:22 2 M56OK96C
4 2019-02-12T14:16:28 1 q2fqVqPc
5 2019-02-14T15:10:45 1 LioXfSPk
6 2019-02-16T14:52:23 3 bQXWpQ2z
7 2019-02-18T15:45:33 2 gsFVGOTy
8 2019-02-20T16:35:12 3 zVuiSTm1
9 2019-02-22T15:52:27 1 kuULtbnm
10 2019-02-24T12:39:30 2 MKDhBt9L
11 2019-02-26T12:45:10 3 FEgRztcr
12 2019-03-04T15:34:46 4 OUBWQSCl
13 2019-03-06T14:20:57 5 6YeTUHgm
14 2019-03-08T12:34:43 6 zlrBrZ0d
Со временем уровень растёт. Посмотрев неподготовленным взглядом, можно сказать, что всё меняется к лучшему. Однако напомним, что вы анализируете позиции сайта в результатах выдачи. Значит, чем они ближе к поисковой строке, тем лучше. Выходит, что позиции со временем падают!
Задача №2
Просмотрите общую информацию о данных.
import pandas as pd
position = pd.read_csv('/datasets/position.csv')
print (position.info())
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 39 entries, 0 to 38
Data columns (total 3 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 timestamp 39 non-null object
1 level 39 non-null int64
2 page_id 39 non-null object
dtypes: int64(1), object(2)
memory usage: 1.0+ KB
None
Позиции падают. Даты записаны как строки.
Кто виноват? И главное — как быть?
Задача №3
Обработайте данные о времени в столбце 'timestamp': переведите их из строкового типа в datetime64. Разделителем даты и времени назначьте заглавную латинскую T
. Выведите на экран первые 5 строк таблицы position.
import pandas as pd
position = pd.read_csv('/datasets/position.csv')
position['timestamp'] = pd.to_datetime(position['timestamp'], format='%Y-%m-%dT%H:%M:%S')
print(position.head(5))
timestamp level page_id
0 2019-02-04 13:22:34 1 6ukoNykP
1 2019-02-06 15:30:54 1 Q62R1Ue7
2 2019-02-08 14:53:45 1 GmfSxgPs
3 2019-02-10 16:50:22 2 M56OK96C
4 2019-02-12 14:16:28 1 q2fqVqPc
Вот теперь даты записаны по-человечески! Ну, или по-питоньи.
Задача №4
Проверьте изменение типа данных с object на datetime64.
import pandas as pd
position = pd.read_csv('/datasets/position.csv')
position['timestamp'] = pd.to_datetime(position['timestamp'], format='%Y-%m-%dT%H:%M:%S')
print (position.info())
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 39 entries, 0 to 38
Data columns (total 3 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 timestamp 39 non-null datetime64[ns]
1 level 39 non-null int64
2 page_id 39 non-null object
dtypes: datetime64[ns](1), int64(1), object(1)
memory usage: 1.0+ KB
None
Проверка пройдена. Даты как даты.
Задача №5
Отсортируйте таблицу position по столбцу 'level' в порядке убывания и выведите на экран. Сохранять отсортированную таблицу не нужно.
import pandas as pd
position = pd.read_csv('/datasets/position.csv')
position['timestamp'] = pd.to_datetime(
position['timestamp'], format='%Y-%m-%dT%H:%M:%S'
)
print (position.sort_values(by='level', ascending=False))
timestamp level page_id
22 2019-03-24 13:49:22 9 WklxK6k4
38 2019-04-27 12:48:14 8 5VRryKr6
35 2019-04-21 14:40:17 8 JvTMAbs7
30 2019-04-11 13:39:15 8 9mL07Mjl
21 2019-03-22 16:36:19 8 s24ZIat3
15 2019-03-10 13:12:57 7 Vih5ARKA
34 2019-04-19 15:43:24 7 MSHZViNg
31 2019-04-13 12:13:26 7 ILfc3WmK
29 2019-04-09 14:57:20 7 SfnhoGh6
27 2019-04-05 14:51:38 7 7JKRCdPA
20 2019-03-20 15:53:36 7 VkTjZ6co
37 2019-04-25 16:10:50 6 clLGJ4g3
33 2019-04-17 16:54:17 6 JjIZd3Jy
28 2019-04-07 16:29:58 6 bsORIc79
24 2019-03-28 15:28:17 6 aQdvnaZX
19 2019-03-18 16:47:36 6 057NPKXX
14 2019-03-08 12:34:43 6 zlrBrZ0d
18 2019-03-16 16:18:34 5 zPH6tQwc
36 2019-04-23 13:17:19 5 6KVLFFQF
13 2019-03-06 14:20:57 5 6YeTUHgm
23 2019-03-26 15:50:31 5 p4Ofo5uP
25 2019-04-01 13:43:49 5 7UCXvXJu
32 2019-04-15 12:28:54 5 sCKAcOTN
12 2019-03-04 15:34:46 4 OUBWQSCl
17 2019-03-14 12:46:19 4 g4si3TQ8
16 2019-03-12 15:33:28 3 Y3wTtqaJ
6 2019-02-16 14:52:23 3 bQXWpQ2z
11 2019-02-26 12:45:10 3 FEgRztcr
8 2019-02-20 16:35:12 3 zVuiSTm1
3 2019-02-10 16:50:22 2 M56OK96C
10 2019-02-24 12:39:30 2 MKDhBt9L
7 2019-02-18 15:45:33 2 gsFVGOTy
26 2019-04-03 15:12:15 2 NJ1D9dAt
9 2019-02-22 15:52:27 1 kuULtbnm
5 2019-02-14 15:10:45 1 LioXfSPk
4 2019-02-12 14:16:28 1 q2fqVqPc
1 2019-02-06 15:30:54 1 Q62R1Ue7
2 2019-02-08 14:53:45 1 GmfSxgPs
0 2019-02-04 13:22:34 1 6ukoNykP
Всего за пару месяцев сайт скатился в выдаче с первой позиции на седьмую и продолжает падать.
Задача №6
Добавьте столбец 'month' в таблицу position с номером месяца. Выведите на экран первые 5 строк таблицы position.
import pandas as pd
position = pd.read_csv('/datasets/position.csv')
position['timestamp'] = pd.to_datetime(
position['timestamp'], format='%Y-%m-%dT%H:%M:%S'
)
position['month'] = pd.DatetimeIndex(position['timestamp']).month
print (position.head())
timestamp level page_id month
0 2019-02-04 13:22:34 1 6ukoNykP 2
1 2019-02-06 15:30:54 1 Q62R1Ue7 2
2 2019-02-08 14:53:45 1 GmfSxgPs 2
3 2019-02-10 16:50:22 2 M56OK96C 2
4 2019-02-12 14:16:28 1 q2fqVqPc 2
Осталось проследить, как именно менялась средняя позиция сайта по месяцам. Быть может, всё не так плохо? Хотя бы в среднем?
Задача №7
Сгруппируйте данные по столбцу 'month' и найдите среднюю позицию в выдаче по месяцам (level). Результат группировки выведите на экран. Перезаписывать таблицу не нужно.
import pandas as pd
position = pd.read_csv('/datasets/position.csv')
position['timestamp'] = pd.to_datetime(
position['timestamp'], format='%Y-%m-%dT%H:%M:%S'
)
position['month'] = pd.DatetimeIndex(position['timestamp']).month
print (position.groupby('month')['level'].mean())
month
2 1.750000
3 5.769231
4 6.214286
Name: level, dtype: float64
Лишь мгновение ты наверху — и стремительно падаешь вниз.
--------------------------------------------------------------------------- ZeroDivisionError Traceback (most recent call last) Cell In[183], line 3 1 a = 1 2 b = 0 ----> 3 print(a / b) #распечатаем на экране результат деления на ноль 4 print ('Кстати, хорошего дня') ZeroDivisionError: division by zero
Python вернул ошибкуZeroDivisionError: division by zero
. Код упал, и пожелание хорошего дня после строки с ошибкой не напечаталось. Проделаем то же самое, но уже с конструкциейtry-except
:
a = 1
b = 0
try:
print(a / b)
except:
print('Проверьте значения параметров a и b')
print('Кстати, хорошего дня')
Проверьте значения параметров a и b Кстати, хорошего дня
Не в силах выполнить команду в блокеtry
, код не падает с ошибкой. Вместо этого выполняется команда из блокаexcept
, а следом за ней и оставшиеся команды. Таких команд с ошибками и без может быть сколько угодно — благодаряtry-except
и циклfor
не прервётся на ошибке, а продолжит работу:
numbers = [10, 1, 0, -3, 999]
# разделим каждое число из списка на само себя
for number in numbers:
try:
print(f'{number} / {number} равно {number / number}')
except:
print(f'Не получилось разделить {number} на {number}')
print('Хорошего дня!')
10 / 10 равно 1.0 1 / 1 равно 1.0 Не получилось разделить 0 на 0 -3 / -3 равно 1.0 999 / 999 равно 1.0 Хорошего дня!
Примените конструкцию try-except и обработайте ошибки, мешающие решению задачи. Создайте переменную wrong_lines для подсчета некорректных строк и в except посчитайте их количество. Выведите на экран общее количество строк и количество некорректных строк в формате:
Количество измерений ...
Количество некорректных строк ...
position = [
['2019-05-01', '- 6'],
['2019-05-02', '+5'],
['2019-05-03', ' 5'],
['2019-05-04', '4'],
['2019-05-05', '5'],
['2019-05-06', '5'],
['2019-05-07', '4'],
['2019-05-08', 'Error 5'],
['2019-05-09', '3'],
['2019-05-10', '3'],
]
count_lines = 0
total_position = 0
wrong_lines = 0
for row in position:
count_lines += 1
#в этой переменной сохраните позицию в выдаче
try:
level = int(row[1])
#сложите все позиции в этой переменной
total_position += level
except:
wrong_lines += 1
print ('Количество измерений',count_lines)
print ('Количество некорректных строк',wrong_lines)
Количество измерений 10 Количество некорректных строк 2
Потому что на десять измерений по статистике две некорректные строки.
Задача №5
Полезно знать не только сколько ошибок, но и где они. Добавьте возможность записывать строки с ошибками в список. Выведите на экран общее количество строк и список некорректных строк в формате:
Количество измерений ...
Некорректные строки [['...', '...'], ['...', '...']]
position = [
['2019-05-01', '- 6'],
['2019-05-02', '+5'],
['2019-05-03', ' 5'],
['2019-05-04', '4'],
['2019-05-05', '5'],
['2019-05-06', '5'],
['2019-05-07', '4'],
['2019-05-08', 'Error 5'],
['2019-05-09', '3'],
['2019-05-10', '3'],
]
count_lines = 0
wrong_lines_content = []
for row in position:
try:
count_lines += 1
level = int(row[1])
except:
wrong_lines_content += [row]
print ('Количество измерений',count_lines)
print ('Некорректные строки',wrong_lines_content)
Количество измерений 10 Некорректные строки [['2019-05-01', '- 6'], ['2019-05-08', 'Error 5']]
Объедините самостоятельно таблицы из переменных subcategory_dict и data. Результат сохраните в переменной data_subcategory и выведите на экран первые 10 строк новой таблицы.
import pandas as pd
data = pd.read_excel('/datasets/seo_data.xlsx', sheet_name='traffic_data')
subcategory_dict = pd.read_excel('/datasets/seo_data.xlsx', sheet_name='subcategory_ids')
data_subcategory = data.merge(subcategory_dict, on='subcategory_id', how='left')
print(data_subcategory.head(10))
subcategory_id source ... subcategory_name category_id
0 cf2e61c7af direct ... Мобильные телефоны 09f279a643
1 0cd903d1cc direct ... Ноутбуки 3509869a61
2 ef35bc88a7 direct ... Телевизоры 09f279a643
3 6ff9f4014c direct ... Планшеты 3509869a61
4 72bc238e4d direct ... Наушники и Bluetooth-гарнитуры 09f279a643
5 88c78ea685 direct ... Шины 65922fa39c
6 179bfacf4a direct ... Умные часы и браслеты 09f279a643
7 b0fb8f259a direct ... Мониторы 3509869a61
8 3c67eb2d90 direct ... Наручные часы 6074ad29ac
9 24e6c815c6 direct ... Лекарственные препараты и БАДы 10a493e03b
[10 rows x 5 columns]
Клеить таблицы проще, чем обои!
Задача №2
Объедините таблицы из переменных data_subcategory и category_dict. Результат сохраните в переменной data_final и выведите на экран первые 10 строк новой таблицы. Подсказка
import pandas as pd
data = pd.read_excel('/datasets/seo_data.xlsx', sheet_name='traffic_data')
subcategory_dict = pd.read_excel('/datasets/seo_data.xlsx', sheet_name='subcategory_ids')
category_dict = pd.read_excel('/datasets/seo_data.xlsx', sheet_name='category_ids')
data_subcategory = data.merge(subcategory_dict, on='subcategory_id', how='left')
data_final = data_subcategory.merge(category_dict, on='category_id', how='left')
print (data_final.head(10))
visits daily_visits
category_name subcategory_name source
Авто Автоакустика direct 5915 197.166667
organic 15433 514.433333
Автомагнитолы direct 7783 259.433333
organic 18690 623.000000
Автомобильные инверторы direct 145 4.833333
organic 150 5.000000
Автомобильные компрессоры direct 407 13.566667
organic 790 26.333333
Автомобильные телевизоры direct 975 32.500000
organic 2246 74.866667
Задача №1
Самостоятельно создайте сводную таблицу для набора data_final. Результат сохраните в переменной data_pivot и выведите первых 10 значений на экран.
import pandas as pd
data_final = pd.read_csv('/datasets/data_final.csv')
data_pivot = data_final.pivot_table(index=['category_name', 'subcategory_name'], columns='source', values='visits', aggfunc='sum')
print (data_pivot.head(10))
source direct organic
category_name subcategory_name
Авто Автоакустика 5915 15433
Автомагнитолы 7783 18690
Автомобильные инверторы 145 150
Автомобильные компрессоры 407 790
Автомобильные телевизоры 975 2246
Автомобильные холодильники 204 285
Автосигнализации 494 1026
Аккумуляторные батареи 1175 2657
Антифризы 736 1568
Багажники, рейлинги 342 664
Удобно видеть все данные сразу вместе! Но это ещё не окончательный рейтинг.
Задача №2
Создайте в таблице data_pivot новый столбец 'ratio' и сохраните в нём значение отношения органического трафика 'organic' к прямому 'direct'. Выведите первые 10 строк таблицы на экран.
import pandas as pd
data_final = pd.read_csv('/datasets/data_final.csv')
data_pivot = data_final.pivot_table(index=['category_name', 'subcategory_name'], columns='source', values='visits', aggfunc='sum')
data_pivot['ratio'] = data_pivot['organic']/data_pivot['direct']
print (data_pivot.head(10))
source direct organic ratio
category_name subcategory_name
Авто Автоакустика 5915 15433 2.609129
Автомагнитолы 7783 18690 2.401388
Автомобильные инверторы 145 150 1.034483
Автомобильные компрессоры 407 790 1.941032
Автомобильные телевизоры 975 2246 2.303590
Автомобильные холодильники 204 285 1.397059
Автосигнализации 494 1026 2.076923
Аккумуляторные батареи 1175 2657 2.261277
Антифризы 736 1568 2.130435
Багажники, рейлинги 342 664 1.941520
Рейтинг наш! Открылось положение вещей.
Чем меньше значение в столбце 'ratio' , тем хуже
у этой подкатегории дела с поисковой оптимизацией.
Задача №3
Отсортируйте таблицу по столбцу 'ratio' в порядке убывания. Выведите первые 10 строк. Отсортированную таблицу сохранять не нужно.
import pandas as pd
data_final = pd.read_csv('/datasets/data_final.csv')
data_pivot = data_final.pivot_table(index=['category_name', 'subcategory_name'], columns='source', values='visits', aggfunc='sum')
data_pivot['ratio'] = data_pivot['organic'] / data_pivot['direct']
print (data_pivot.sort_values(by='ratio', ascending=False).head(10))
source direct ... ratio
category_name subcategory_name ...
Авто Шины 39638 ... 3.881604
Бытовая техника Стиральные машины 22064 ... 2.926487
Спорт и отдых Велосипеды 16009 ... 2.878818
Детские товары Коляски 18079 ... 2.876542
Строительство и ремонт Сварочные аппараты 6175 ... 2.805668
Товары для дома Компьютерные кресла 6208 ... 2.803963
Компьютерная техника Клавиатуры 6224 ... 2.798361
Электроника Универсальные внешние аккумуляторы 6146 ... 2.784738
TV-тюнеры 6275 ... 2.777211
Бытовая техника Холодильники 20920 ... 2.771750
[10 rows x 3 columns]
Всё в порядке с шинами и стиральными машинами (внезапно). За них мы спокойны: проверим, какие категории товаров привлекают не так много трафика.
Задача №4
Отсортируйте таблицу по столбцу 'ratio' в порядке убывания. Выведите последние 10 значений. Отсортированную таблицу сохранять не нужно.
import pandas as pd
data_final = pd.read_csv('/datasets/data_final.csv')
data_pivot = data_final.pivot_table(index=['category_name', 'subcategory_name'], columns='source', values='visits', aggfunc='sum')
data_pivot['ratio'] = data_pivot['organic'] / data_pivot['direct']
print (data_pivot.sort_values(by='ratio', ascending=False).tail(10))
source direct ... ratio
category_name subcategory_name ...
Строительство и ремонт Душевые поддоны 90 ... 0.288889
Товары для красоты Кисти, спонжи и аппликаторы 96 ... 0.281250
Продукты Макароны 86 ... 0.279070
Детские товары Играем в салон красоты 88 ... 0.272727
Спорт и отдых Гребные тренажеры 89 ... 0.269663
Детские товары Блокноты 79 ... 0.265823
Строительство и ремонт Проволока 76 ... 0.197368
Одежда, обувь и аксессуары Термобелье 67 ... 0.194030
Авто Наклейки, шильдики и значки 50 ... 0.180000
Детские товары Гигиена полости рта 27 ... 0.148148
[10 rows x 3 columns]
Что общего у душевых поддонов, кистей и макарон? Верно, все они приносят сайту недостаточно трафика!
Задача №5
Отсортируйте таблицу по столбцу 'ratio' в порядке убывания и выведите последние 10 записей, где прямой трафик больше 1000. Выражение напишите в скобках функции print(), чтобы результат напечатался на экран.
import pandas as pd
data_final = pd.read_csv('/datasets/data_final.csv')
data_pivot = data_final.pivot_table(index=['category_name', 'subcategory_name'], columns='source', values='visits', aggfunc='sum')
data_pivot['ratio'] = data_pivot['organic'] / data_pivot['direct']
data_pivot = data_pivot.loc[data_pivot['direct'] > 1000]
print(data_pivot.sort_values(by='ratio', ascending=False).tail(10))
source direct ... ratio
category_name subcategory_name ...
Бытовая техника Оверлоки и распошивальные машины 1536 ... 2.093099
Товары для дома Компьютерные и письменные столы 1999 ... 2.089545
Люстры 2016 ... 2.087798
Строительство и ремонт Дисковые пилы 2040 ... 2.085784
Воздушные компрессоры 1690 ... 2.082840
Товары для здоровья Бандажи и ортезы 1659 ... 2.081374
Строительство и ремонт Нивелиры и лазерные уровни 1651 ... 2.081163
Электроника Защитные пленки и стекла 1560 ... 2.080769
Одежда, обувь и аксессуары Туфли 1035 ... 2.025121
Сапоги 1008 ... 2.004960
[10 rows x 3 columns]
Отчёт для коллег готов. А раз вы теперь свободны, можно наконец узнать у Яндекса, что же такое «оверлок», «ортез» и «нивелир».