- •Об авторе
- •О научном редакторе
- •От издательства
- •Введение
- •Использование Python для data science
- •Для кого эта книга?
- •О чем эта книга?
- •Глава 1. Базовые знания о данных
- •Категории данных
- •Неструктурированные данные
- •Структурированные данные
- •Слабоструктурированные данные
- •Данные временных рядов
- •Источники данных
- •Веб-страницы
- •Базы данных
- •Файлы
- •Получение
- •Очистка
- •Преобразование
- •Анализ
- •Хранение
- •Питонический стиль
- •Выводы
- •Глава 2. Структуры данных Python
- •Списки
- •Создание списка
- •Использование общих методов списков
- •Использование срезов
- •Использование списка в качестве очереди
- •Использование списка в качестве стека
- •Использование списков и стеков для обработки естественного языка
- •Расширение функциональности с помощью списковых включений
- •Кортежи
- •Список кортежей
- •Неизменяемость
- •Словари
- •Список словарей
- •Добавление элементов в словарь с помощью setdefault()
- •Преобразование JSON в словарь
- •Множества
- •Удаление дубликатов из последовательности
- •Общие операции с множеством
- •Упражнение № 1: продвинутый анализ тегов фотографий
- •Выводы
- •NumPy
- •Установка NumPy
- •Создание массива NumPy
- •Выполнение поэлементных операций
- •Использование статистических функций NumPy
- •Упражнение № 2: использование статистических функций numpy
- •pandas
- •Установка pandas
- •pandas Series
- •Упражнение № 3: объединение трех серий
- •pandas DataFrame
- •Упражнение № 4: использование разных типов join
- •scikit-learn
- •Установка scikit-learn
- •Получение набора образцов
- •Преобразование загруженного датасета в pandas DataFrame
- •Разделение набора данных на обучающий и тестовый
- •Преобразование текста в числовые векторы признаков
- •Обучение и оценка модели
- •Создание прогнозов на новых данных
- •Выводы
- •Глава 4. Доступ к данным из файлов и API
- •Импортирование данных с помощью функции open()
- •Текстовые файлы
- •Файлы с табличными данными
- •Упражнение № 5: открытие json-файлов
- •Двоичные файлы
- •Экспортирование данных в файл
- •Доступ к удаленным файлам и API
- •Как работают HTTP-запросы
- •Библиотека urllib3
- •Библиотека Requests
- •Упражнение № 6: доступ к api с помощью requests
- •Перемещение данных в DataFrame и из него
- •Импортирование вложенных структур JSON
- •Конвертирование DataFrame в JSON
- •Выводы
- •Глава 5. Работа с базами данных
- •Реляционные базы данных
- •Понимание инструкций SQL
- •Начало работы с MySQL
- •Определение структуры базы данных
- •Вставка данных в БД
- •Запрос к базе данных
- •Упражнение № 8: объединение «один-ко-многим»
- •Использование инструментов аналитики баз данных
- •Базы данных NoSQL
- •Документоориентированные базы данных
- •Упражнение № 9: вставка и запрос нескольких документов
- •Выводы
- •Глава 6. Агрегирование данных
- •Данные для агрегирования
- •Объединение датафреймов
- •Группировка и агрегирование данных
- •Просмотр конкретных агрегированных показателей по MultiIndex
- •Срез диапазона агрегированных значений
- •Срезы на разных уровнях агрегирования
- •Добавление общего итога
- •Добавление промежуточных итогов
- •Выбор всех строк в группе
- •Выводы
- •Глава 7. Объединение датасетов
- •Объединение встроенных структур данных
- •Объединение списков и кортежей с помощью оператора +
- •Объединение словарей с помощью оператора **
- •Объединение строк из двух структур
- •Реализация join-объединений списков
- •Конкатенация массивов NumPy
- •Объединение структур данных pandas
- •Конкатенация датафреймов
- •Удаление столбцов/строк из датафрейма
- •Join-объединение двух датафреймов
- •Выводы
- •Глава 8. Визуализация
- •Распространенные способы визуализации
- •Линейные диаграммы
- •Столбчатые диаграммы
- •Круговые диаграммы
- •Гистограммы
- •Построение графиков с помощью Matplotlib
- •Установка Matplotlib
- •Использование matplotlib.pyplot
- •Работа с объектами Figure и Axes
- •Создание гистограммы с помощью subplots()
- •Совместимость Matplotlib с другими библиотеками
- •Построение графиков для данных pandas
- •Отображение данных геолокации с помощью Cartopy
- •Выводы
- •Глава 9. Анализ данных о местоположении
- •Получение данных о местоположении
- •Преобразование стандартного вида адреса в геокоординаты
- •Получение геокоординат движущегося объекта
- •Анализ пространственных данных с помощью geopy и Shapely
- •Поиск ближайшего объекта
- •Поиск объектов в определенной области
- •Объединение двух подходов
- •Упражнение № 15: совершенствование алгоритма подбора машины
- •Получение непространственных характеристик
- •Объединение датасетов с пространственными и непространственными данными
- •Выводы
- •Глава 10. Анализ данных временных рядов
- •Регулярные и нерегулярные временные ряды
- •Общие методы анализа временных рядов
- •Вычисление процентных изменений
- •Вычисление скользящего окна
- •Вычисление процентного изменения скользящего среднего
- •Многомерные временные ряды
- •Обработка многомерных временных рядов
- •Анализ зависимости между переменными
- •Выводы
- •Глава 11. Получение инсайтов из данных
- •Ассоциативные правила
- •Поддержка
- •Доверие
- •Лифт
- •Алгоритм Apriori
- •Создание датасета с транзакциями
- •Определение часто встречающихся наборов
- •Генерирование ассоциативных правил
- •Визуализация ассоциативных правил
- •Получение полезных инсайтов из ассоциативных правил
- •Генерирование рекомендаций
- •Планирование скидок на основе ассоциативных правил
- •Выводы
- •Глава 12. Машинное обучение для анализа данных
- •Почему машинное обучение?
- •Типы машинного обучения
- •Обучение с учителем
- •Обучение без учителя
- •Как работает машинное обучение
- •Данные для обучения
- •Статистическая модель
- •Неизвестные данные
- •Пример анализа тональности: классификация отзывов о товарах
- •Получение отзывов о товарах
- •Очистка данных
- •Разделение и преобразование данных
- •Обучение модели
- •Оценка модели
- •Упражнение № 19: расширение набора примеров
- •Прогнозирование тенденций фондового рынка
- •Получение данных
- •Извлечение признаков из непрерывных данных
- •Генерирование выходной переменной
- •Обучение и оценка модели
- •Выводы
238 Глава 11. Получение инсайтов из данных
Однако можно заметить, что для некоторых пар антецедент/консеквент на графике значение лифта несимметрично. Например, лифт для правила cheese -> bread равен 1.5, однако значения лифта для bread -> cheeseна графике нет. Это связано с тем, что когда мы изначально создавали ассоциативные правила с помощью функции mlxtend association_rules(), мы установили 50-процентный порог доверия. Это решение исключило многие потенциальные ассоциативные правила, включая bread -> cheeseс показателем доверия 37.5% против 60-про- центого доверия пары cheese -> bread. Таким образом, данные правила bread -> cheese не учитывались при построении графика.
Получение полезных инсайтов из ассоциативных правил
Используя алгоритм Apriori, мы определили часто встречающиеся наборы товаров в выборке данных о транзакциях и на их основе создали ассоциативные правила. По сути, эти правила показывают вероятность того, что покупатель приобретет какой-то продукт, если он уже купил другой, а визуализация значений лифта на тепловой карте позволяет определить самые четкие закономерности. Следующий логичный вопрос — как эта информация может быть полезна бизнесу?
В этом разделе мы рассмотрим два способа, с помощью которых компания может получить полезные инсайты из набора ассоциативных правил. Мы исследуем, как генерировать рекомендации на основе товаров, которые покупатель уже приобрел, и как эффективно планировать скидки на основе часто встречающихся наборов товаров. Обе эти техники помогают увеличить доход компании и одновременно обеспечить лучшее качество клиентского сервиса.
Генерирование рекомендаций
После того как покупатель положил какой-то товар в корзину, какой следующий товар он, скорее всего, добавит? Конечно, это нельзя определить наверняка, однако можно сделать прогноз на основе ассоциативных правил, полученных из данных о транзакциях. Результаты такого прогнозирования могут стать основой для формирования набора рекомендаций тех товаров, которые часто приобретают вместе с товаром, который уже находится в корзине. Ритейлеры обычно используют такие рекомендации, чтобы показать покупателям другие товары, которые им потенциально понадобятся.
Вероятно, самый естественный способ создания рекомендаций такого типа — рассмотрение всех ассоциативных правил, в которых товар, находящийся
Получение полезных инсайтов из ассоциативных правил 239
в корзине, выступает в качестве антецедента. Затем определяются самые значимые правила — например, три правила с самым высоким значением доверия — и извлекаются их консеквенты. Ниже показано, как выполнить этот алгоритм для товара butter (масло). Начинаем с поиска правил, в которых butter является антецедентом, используя возможности фильтрации библиотеки pandas:
butter_antecedent = rules[rules['antecedents'] == {'butter'}]
[['consequents','confidence']]
.sort_values('confidence', ascending = False)
В коде выше мы сортируем правила по столбцу confidence так, чтобы правила с наивысшим рейтингом доверия оказались в начале датафрейма butter_ antecedent. Далее используем списковое включение для извлечения трех основных консеквентов:
butter_consequents = [list(item) for item in butter_antecedent.iloc[0:3:,]
['consequents']]
В этом списковом включении мы проходим по столбцу consequents дата фрейма butter_antecedent, выбирая первые три значения. Для списка butter_ consequents можно сгенирировать рекомендации:
item = 'butter'
print('Items frequently bought together with', item, 'are:', butter_consequents)
Вот как они выглядят:
Items frequently bought together with butter are: [['bread'], ['cheese'],
['cheese', 'bread']]
Это указывает на то, что покупатели масла в дополнение к нему часто покупают либо хлеб или сыр, либо и то и другое.
Планирование скидок на основе ассоциативных правил
Ассоциативные правила, созданные для часто встречающихся наборов товаров, также применяются для выбора продуктов, на которые можно назначить скидки. В идеале продукт со скидкой должен быть в каждой значимой группе товаров, чтобы удовлетворить как можно больше покупателей. Другими словами, необходимо выбрать один товар для назначения скидки в каждом часто встречающемся наборе.
240 Глава 11. Получение инсайтов из данных
Для этого, прежде всего, такие наборы нужно найти. К сожалению, в дата фрейме rules, созданном ранее функцией association_rules(), содержатся колонки с антецедентами и консеквентами, а не с наборами товаров целиком. Поэтому необходимо создать колонку itemsets, объединив столбцы antecedents и consequents, как показано ниже:
from functools import reduce
rules['itemsets'] = rules[['antecedents', 'consequents']].apply(lambda x: reduce(frozenset.union, x), axis=1)
Мы используем функцию reduce()из модуля functools Python для применения метода frozenset.union()к значениям колонок antecedents и consequents. При этом отдельные неизменяемые множества (frozenset) из этих колонок объединяются в одно.
Чтобы посмотреть, что получилось в результате, можно вывести на экран только что созданный столбец itemsets вместе с колонками antecedents и consequents:
print(rules[['antecedents','consequents','itemsets']])
Вывод:
|
antecedents |
consequents |
itemsets |
0 |
(butter) |
(bread) |
(butter, bread) |
1 |
(bread) |
(butter) |
(butter, bread) |
2 |
(cheese) |
(bread) |
(bread, cheese) |
3 |
(milk) |
(bread) |
(milk, bread) |
4 |
(butter) |
(cheese) |
(butter, cheese) |
5 |
(pasta) |
(cheese) |
(pasta, cheese) |
6 |
(sour cream) |
(curd) |
(sour cream, curd) |
7 |
(curd) |
(sour cream) |
(sour cream, curd) |
8 |
(milk) |
(eggs) |
(milk, eggs) |
9 |
(eggs) |
(milk) |
(milk, eggs) |
10 |
(butter, cheese) |
(bread) |
(bread, butter, cheese) |
11 |
(butter, bread) |
(cheese) |
(butter, cheese, bread) |
12 |
(bread, cheese) |
(butter) |
(bread, butter, cheese) |
13 |
(butter) |
(bread, cheese) |
(butter, cheese, bread) |
|
|
|
|
Обратите внимание, что в новом столбце itemsets есть несколько дубликатов. Как уже говорилось, один и тот же набор товаров может образовывать более одного ассоциативного правила, поскольку порядок товаров влияет на некоторые метрики. Порядок товаров в наборе не имеет значения для
Получение полезных инсайтов из ассоциативных правил 241
текущей задачи, поэтому можно безопасно удалить дубли наборов, как показано ниже:
rules.drop_duplicates(subset=['itemsets'], keep='first', inplace=True)
Для этого используется метод датафрейма drop_duplicates(), осуществляющий поиск повторяющихся значений в столбце itemsets. Мы сохраняем первую строку множества дублирующихся строк и, задавая значение True для параметра inplace, удаляем дубликаты из существующего датафрейма вместо создания нового.
Выведем на экран колонку itemsets:
print(rules['itemsets'])
И получим:
0(bread, butter)
2(bread, cheese)
3(bread, milk)
4(butter, cheese)
5 |
(cheese, pasta) |
6(curd, sour cream)
8 |
(milk, eggs) |
10 |
(bread, cheese, butter) |
|
|
Затем из каждого набора выбираем по одному товару, который будет уценен:
discounted = [] others = []
for itemset in rules['itemsets']:
for i, item in enumerate(itemset):
if item not in others:
discounted.append(item)
itemset = set(itemset) itemset.discard(item)
others.extend(itemset) break
if i == len(itemset)-1: discounted.append(item) itemset = set(itemset) itemset.discard(item)
others.extend(itemset)
print(discounted)
242 Глава 11. Получение инсайтов из данных
Сначала создается список discounted для сохранения товаров, выбранных для скидки, и список others для получения товаров из набора, на которых скидки не будет. Затем мы проходим по каждому набору товаров и по каждому товару внутри набора . Мы ищем элемент, которого еще нет в списке others, поскольку такого элемента либо нет ни в одном из предыдущих наборов, либо он уже был выбран ранее в качестве уцененного товара для какого-то другого набора. Рационально выбрать его в качестве товара со скидкой и для текущего набора . Мы отправляем выбранный товар в список discounted , а остальные товары набора — в список others . Если мы перебрали все товары набора и не нашли элемент, которого еще нет в списке others, то выбираем последний элемент набора и отправляем его в список discounted .
Итоговый список discounted будет отличаться, поскольку множества frozenset, представляющие наборы товаров, не упорядочены. Вот как он будет выглядеть:
['bread', 'bread', 'bread', 'cheese', 'pasta', 'curd', 'eggs', 'bread']
Если сопоставить список с созданным ранее столбцом itemsets, можно заметить, что в каждом наборе есть один уцененный товар. Более того, благодаря тому, что мы грамотно распределили скидки, фактически уцененных товаров получилось значительно меньше, чем наборов. Это можно проверить, удалив дубликаты из списка discounted:
print(list(set(discounted)))
Как видно из результата, несмотря на то что у нас восемь наборов, сделать скидку пришлось лишь на пять товаров:
['cheese', 'eggs', 'bread', 'pasta', 'curd']
Таким образом, нам удалось уценить хотя бы один товар в каждом наборе (существенная выгода для многих покупателей) и не пришлось делать скидку на большее количество продуктов (существенная выгода для бизнеса).
УПРАЖНЕНИЕ № 18: ИЗВЛЕЧЕНИЕ ДАННЫХ
ОРЕАЛЬНЫХ ТРАНЗАКЦИЯХ
Вэтой главе мы работали с датасетом, содержащим всего 20 транзакций. Пришло время засучить рукава и поработать с большим набором данных.
Получение полезных инсайтов из ассоциативных правил 243
В этом упражнении вы будете формировать часто встречающиеся наборы товаров на основе реальной коллекции данных, содержащей более полумиллиона покупок. Этот датасет можно найти в репозитории UCI Machine Learning Repository1.
Загрузите файл Online Retail.xlsx на свой компьютер или воспользуйтесь прямой ссылкой2 для доступа к файлу. Прежде чем приступить к обработке, прочитайте Excel-файл и преобразуйте его в pandas DataFrame. Для этого установите библиотеку openpyxl. Она позволяет обрабатывать Excel-файлы в Python-скрипте. Установить ее можно с помощью pip следующим образом:
$ pip install openpyxl
После этого используйте openpyxl для загрузки и преобразования датасета в объект DataFrame:
import pandas as pd
df_retail = pd.read_excel('path/to/Online Retail.xlsx', index_col=0, engine='openpyxl')
В зависимости от компьютера процесс загрузки может занять несколько минут. Затем, чтобы убедиться, что загрузка прошла успешно, проверьте количество строк в датафрейме df_retailи выведите несколько первых строк:
print('The number of instances: ', len(df_retail)) print(df_retail.head())
Вы должны увидеть следующее:
The number of instances: 541909 |
|
|
|
|
||
|
StockCode |
Description |
Quantity |
InvoiceDate |
UnitPrice |
Country |
InvoiceNo |
|
|
|
|
|
|
536365 |
85123A |
WHITE HANGING HEART T-LIG... |
6 |
2010-12-01 |
2.55 |
UK |
536365 |
71053 |
WHITE METAL LANTERN |
6 |
2010-12-01 |
3.39 |
UK |
536365 |
84406B |
CREAM CUPID HEARTS COAT... |
8 |
2010-12-01 |
2.75 |
UK |
536365 |
84029G |
KNITTED UNION FLAG HOT... |
6 |
2010-12-01 |
3.39 |
UK |
1 https://archive.ics.uci.edu/ml/datasets/online+retail
2 https://archive.ics.uci.edu/ml/machine-learning-databases/00352/Online%20Retail.xlsx
244 Глава 11. Получение инсайтов из данных
536365 |
84029E |
RED WOOLLY HOTTIE WHITE... |
6 2010-12-01 3.39 |
UK |
[5 rows x 7 columns]
Реальные данные, подобные представленным, могут быть несовершенными, поэтому на этом этапе необходимо провести очистку, чтобы подготовить их к дальнейшей обработке. Для начала необходимо удалить все строки, имеющие значение NaN в поле Description. Это поле содержит названия товаров, поэтому значения NaN могут исказить процесс определения часто встречающихся наборов:
df_retail = df_retail.dropna(subset=['Description'])
Чтобы проверить, сработало ли это, выведем длину обновленного дата фрейма df_retail:
print(len(df_retail))
Мы получили значение 540455. Это означает, что теперь в датафрейме на 1454 строки меньше. Чтобы еще лучше подготовить данные, следует убедиться, что значения колонки Descriptionприведены к типу данных str:
df_retail = df_retail.astype({"Description":'str'})
Теперь мы готовы преобразовать датасет в формат, который можно обработать с помощью mlxtend. Сначала сгруппируем данные о транзакциях по столбцу InvoiceNo и преобразуем датафрейм в список списков, где каждый список содержит набор товаров одной транзакции:
trans = df_retail.groupby(['InvoiceNo'])['Description'].apply(list). to_list()
Теперь можно узнать количество фактических транзакций, представленных в датасете:
print(len(trans))
Должно получиться 24446.
Получение полезных инсайтов из ассоциативных правил 245
Следующие шаги анализа были подробно рассмотрены выше в этой главе.
Вобщих чертах необходимо сделать следующее:
1.Преобразовать список списков trans в булев OHE-массив с помощью объекта TransactionEncoder библиотеки mlxtend.
2.Сформировать часто встречающиеся наборы товаров с помощью функции apriori() (для рассматриваемого примера используйте min_support=0.025).
3.Сгенерировать ассоциативные правила с помощью функции association_rules() (для рассматриваемого примера используйте metric="confidence", min_threshold=0.3).
После выполнения этих шагов выведите на экран созданные правила:
print(rules.iloc[:,0:7])
Вывод должен получиться примерно таким:
|
antecedents |
consequents |
...confidence |
lift |
||
0 |
(ALARM CLOCK BAKELI... |
) |
(ALARM CLOCK BAKELIKE GREEN) |
... 0.5975 |
14.5942 |
|
1 |
(ALARM CLOCK BAKELI... |
) |
(ALARM CLOCK BAKELIKE RED) |
... 0.6453 |
14.5942 |
|
2 |
(GREEN REGENCY TEACUP AND... |
) |
(PINK REGENCY TEACUP AND... |
) |
... 0.6092 |
18.5945 |
3 |
(PINK REGENCY TEACUP AND... |
) |
(GREEN REGENCY TEACUP AND... |
) |
... 0.8039 |
18.5945 |
4 |
(GREEN REGENCY TEACUP AND... |
) |
(ROSES REGENCY TEACUP AND... |
) |
... 0.7417 |
16.1894 |
5 |
(ROSES REGENCY TEACUP AND... |
) |
(GREEN REGENCY TEACUP AND... |
) |
... 0.7000 |
16.1894 |
6 |
(JUMBO BAG PINK POLKADOT) |
|
(JUMBO BAG RED RETROSPOT) |
... 0.6766 |
7.7481 |
|
7 |
(JUMBO BAG RED RETROSPOT) |
|
(JUMBO BAG PINK POLKADOT) |
... 0.3901 |
7.7481 |
|
8 |
(JUMBO SHOPPER VINTAGE RED... |
) |
(JUMBO BAG RED RETROSPOT) |
... 0.5754 |
6.5883 |
|
9 |
(JUMBO BAG RED RET... |
) |
(JUMBO SHOPPER VINTAGE RED... |
) |
... 0.3199 |
6.5883 |
10 |
(JUMBO STORAGE BAG SUKI) |
(JUMBO BAG RED RETROSPOT) |
... 0.6103 |
6.9882 |
||
11 |
(JUMBO BAG RED RE... |
) |
(JUMBO STORAGE BAG... |
) |
... 0.3433 |
6.9882 |
12 |
(LUNCH BAG BLACK SKULL.) |
(LUNCH BAG RED RETROSPOT) |
... 0.5003 |
7.6119 |
||
13 |
(LUNCH BAG RED RETROSPOT) |
(LUNCH BAG BLACK SKULL) |
... 0.4032 |
7.6119 |
||
14 |
(LUNCH BAG PINK POLKADOT) |
(LUNCH BAG RED RETROSPOT) |
... 0.5522 |
8.4009 |
||
15 |
(LUNCH BAG RED RETROSPOT) |
(LUNCH BAG PINK POLKADOT) |
... 0.3814 |
8.4009 |
||
16 |
(PINK REGENCY TEACUP AND... |
) |
(ROSES REGENCY TEACUP AND... |
) |
... 0.7665 |
16.7311 |
17 |
(ROSES REGENCY TEACUP AND... |
) |
(PINK REGENCY TEACUP AND... |
) |
... 0.5482 |
16.7311 |
|
|
|
|
|
|
|
Чтобы создать коллекцию ассоциативных правил большего или меньшего размера, поэкспериментируйте с параметром min_support, передаваемым функции apriori(), а также с параметрами metric и threshold внутри функции association_rules().