Следующая тема: ПД. Поиск дубликатов

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

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

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

2.Как читать файлы из Excel

Задача №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())

Задача №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 методы анализа.

3.Такие неидеальные данные

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

Сгруппируем датафрейм '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())

Переведите значения столбца '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())
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())
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())
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'])

Задача №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())

Задача №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())
4.Перевод строковых значений в числа
 
5.Неявные ошибки в числовых значениях. Метод abs()
 
Некорректный тип данных у числовых значений — не единственная проблема, с которой можно столкнуться. Посмотрите на пример ниже:
import pandas as pd

data = [
    ['600748331392', 'C', 17515.4],
    ['600748331404', 'B', -10117.6],
    ['600748331412', 'B', 18489.3],
    ['600748331430', 'B', 6620.22],
    ['600748331447', 'C', -7559.9]
]

transactions = pd.DataFrame(data, columns=['id', 'category', 'amount'])
print(transactions)
import pandas as pd

data = [
    ['600748331392', 'C', 17515.4],
    ['600748331404', 'B', -10117.6],
    ['600748331412', 'B', 18489.3],
    ['600748331430', 'B', 6620.22],
    ['600748331447', 'C', -7559.9]
]

transactions = pd.DataFrame(data, columns=['id', 'category', 'amount'])
# используем метод abs(), чтобы привести все значения к неотрицательным
transactions['amount'] = transactions['amount'].abs()
print(transactions)
 
6.Методы Pandas для работы с датой и временем

Pandas умеет не только переводить строки в числа, но и работать с датами.

Восточноевропейские пользователи привыкли обозначать даты так: день.месяц.год. Например, 8 марта 2019 года записывается 08.03.2019. А в США принят другой формат: месяц/день/год. Поэтому для жителей США восточноевропейское восьмое марта будет третьим августа.

image

Несмотря на трудности перевода, Excel поймёт и тех, и других. Однако даже он не всеяден. Выгружая значения дат из баз данных, можно столкнуться с форматом вида 2019-08-03Z17:25:00 или 03, Aug 19, 5:25 PM — такого Excel уже не разберёт.

Вне зависимости от способа записи, дату и время нужно вводить в арифметические операции. Для этого в Python существует особый тип данных — datetime. Осталось научиться приводить к нему строки.

Представьте: сотрудник регулярно опаздывал на планёрки в 11 часов утра. Не желая остаться без премии, он обещал руководству не опаздывать больше, чем на 10 минут. Прошло две недели. Поднимем базу пропускной системы и узнаем, удалось ли сотруднику сдержать слово:

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
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 

Задача №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

Лишь мгновение ты наверху — и стремительно падаешь вниз.

 
7.Обработка ошибок: try-except

Выгружая данные из разных систем, готовьтесь к сюрпризам

  • Некорректный формат приводит к невыполнению кода. Говорят, что «код падает с ошибкой». Здесь вы уже опытны: например, если числа в наборе данных вдруг стали строками, умеете вызвать метод to_numeric();
  • Ошибки в данных встречаются ближе к концу файла, и код на строках с неверными значениями не выполняется. Значит, пропадают расчёты для предыдущих, «безошибочных» строк;
  • Данные могут поменяться. К примеру, в выгрузку для бухгалтерии с появлением нового контрагента могут проникнуть некорректные данные, из-за которых код упадёт.

К сожалению, предсказать все потенциальные ошибки невозможно. Но и останавливать работу кода всякий раз, когда он спотыкается о некорректное значение, нельзя. image Для работы с непредсказуемым поведением данных есть конструкция try-except. Принцип работы такой: исходный код помещают в блок try. Если при выполнении кода из блока try возникнет ошибка, воспроизведётся код из блока except.

Заведомо напишем код с ошибкой:

a = 1
b = 0
print(a / b) #распечатаем на экране результат деления на ноль
print ('Кстати, хорошего дня') #заодно пожелаем хорошего дня
a = 1
b = 0
try:
    print(a / b)
except:
    print('Проверьте значения параметров a и b')
print('Кстати, хорошего дня')
numbers = [10, 1, 0, -3, 999]

# разделим каждое число из списка на само себя

for number in numbers:
    try:
        print(f'{number} / {number} равно {number / number}')
    except:
        print(f'Не получилось разделить {number} на {number}')
print('Хорошего дня!')

Примените конструкцию 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)
 
8.Метод merge()

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

Данные хранят в Excel-таблице из нескольких листов. Как смотреть на категории, подкатегории и трафик в одном месте? Идея — склеить таблицы!

Объединим несколько таблиц в одну методом merge(). Передавая тот или иной аргумент методу merge(), можно по-разному объединять таблицы. Подробнее об этом будет рассказано в следующем спринте.

merge() применяют к таблице, к которой присоединяют другую. У метода следующие аргументы:

  • right — имя DataFrame или Series, присоединяемого к исходной таблице.
  • on — название общего списка в двух соединяемых таблицах: по нему происходит слияние.
  • how — чьи id включать в итоговую таблицу. Аргумент how может принять значение left: тогда в итоговую таблицу будут включены id из левой таблицы. Аргумент right включает id из правой таблицы.

Объединим таблицы data и subcategory_dict со следующими условиями:

  • data — таблица, к которой надо присоединить другую таблицу.
  • subcategory_dict — таблица, которую присоединяем к data.
  • 'subcategory_id' — общий столбец в двух таблицах. По нему будем объединять.
  • how='left'id таблицы data включены в итоговую таблицу data_subcategory
    data_subcategory = data.merge(subcategory_dict, on='subcategory_id', how='left')
    print(data_subcategory.head(10))

     

    \ subcategory_id source visits subcategory_name category_id
    0 cf2e61c7af direct 501165 Мобильные телефоны 09f279a643
    1 0cd903d1cc direct 126342 Ноутбуки 3509869a61
    2 ef35bc88a7 direct 95626 Телевизоры 09f279a643

Задача №1

Объедините самостоятельно таблицы из переменных 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))

  subcategory_id  source  ... category_id category_name
0     cf2e61c7af  direct  ...  09f279a643   Электроника
1     cf2e61c7af  direct  ...  09f279a643   Электроника
2     cf2e61c7af  direct  ...  09f279a643   Электроника
3     cf2e61c7af  direct  ...  09f279a643   Электроника
4     cf2e61c7af  direct  ...  09f279a643   Электроника
5     cf2e61c7af  direct  ...  09f279a643   Электроника
6     cf2e61c7af  direct  ...  09f279a643   Электроника
7     cf2e61c7af  direct  ...  09f279a643   Электроника
8     cf2e61c7af  direct  ...  09f279a643   Электроника
9     cf2e61c7af  direct  ...  09f279a643   Электроника

[10 rows x 6 columns]
Таблица готова к получению финальных результатов.

 
9.Сводные таблицы
 

Сводная таблица — ваш помощник для обобщения данных и их наглядного представления.

Перед вами таблица со статистикой продаж товаров в интернет-магазине. Известны название товара, дата продажи, количество, цена и стоимость доставки. image Ответьте на вопрос: «Сколько товара продал интернет-магазин 4 июня 2019 года?». Трудно сделать это быстро? Взгляните на сводную таблицу! image По сводным таблицам можно точно сказать, сколько товара было продано в определённый день. Умение строить сводные таблицы позволяет быстро анализировать данные и сразу подготовить отчёты.

В Pandas для подготовки сводных таблиц вызывают метод pivot_table().

Аргументы метода:

  • index — столбец или столбцы, по которым группируют данные (название товара)
  • columns — столбец, по значениям которого происходит группировка (даты)
  • values — значения, по которым мы хотим увидеть сводную таблицу (количество проданного товара)
  • aggfunc — функция, применяемая к значениям (сумма товаров)

Построим сводную таблицу для задачи по поисковой оптимизации. Таблица data_final из предыдущего урока выглядела так:

\ subcategory_id source visits subcategory_name category_id category_name
0 cf2e61c7af direct 501166 Мобильные телефоны 09f279a643 Электроника
1 0cd903d1cc direct 126342 Ноутбуки 3509869a61 Компьютерная техника

Сделаем по ней сводную таблицу методом pivot_table():

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
 
source category_name            subcategory_name  direct  organic
0               Авто                Автоакустика    5915    15433
1               Авто               Автомагнитолы    7783    18690
2               Авто     Автомобильные инверторы     145      150
3               Авто   Автомобильные компрессоры     407      790
4               Авто    Автомобильные телевизоры     975     2246
5               Авто  Автомобильные холодильники     204      285
6               Авто            Автосигнализации     494     1026
7               Авто      Аккумуляторные батареи    1175     2657
8               Авто                   Антифризы     736     1568
9               Авто         Багажники, рейлинги     342      664
 
                                                 visits
category_name subcategory_name          source         
Авто          Автоакустика              direct     5915
                                        organic   15433
              Автомагнитолы             direct     7783
                                        organic   18690
              Автомобильные инверторы   direct      145
                                        organic     150
              Автомобильные компрессоры direct      407
                                        organic     790
              Автомобильные телевизоры  direct      975
                                        organic    2246
 
Сгруппировав данные методами groupby() и agg() вместо pivot_table(), мы получили точно такие же данные, но в несколько другом виде. Он называется «длинный». Методы groupby() и agg() удобны, когда нужно применить функцию к столбцу со сгруппированными визитами visits или создать новый столбец на его основе:
data_grouped['daily_visits'] = data_grouped['visits'] / 30
print(data_grouped.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]


Отчёт для коллег готов. А раз вы теперь свободны, можно наконец узнать у Яндекса, что же такое «оверлок», «ортез» и «нивелир».

 
10.Заключение
 
В этой теме вы определили, какие товарные категории и подкатегории Яндекс.Маркета представлены в поисковиках хуже всего. Вы группировали данные и нашли отношение органического трафика к прямому. Применив сводные таблицы, оценили, над какими категориями стоит поработать. Такие товары нужно поднимать в выдаче.
 
11.Проверочные задания. Изменение типов данных