Введение

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

Одним из таких алгоритмов машинного обучения, который можно использовать, является алгоритм Apriori, который использует методы обучения без учителя для выявления скрытых шаблонов и ассоциаций в больших наборах транзакционных данных. В этой статье мы рассмотрим, как алгоритм Apriori можно использовать для получения информации о покупательском поведении потребителей, используя набор данных о розничных онлайн-транзакциях от UCI («https://archive.ics.uci.edu/ml/datasets/online+). розничная торговля").

Информация о наборе данных

Набор данных, использованный для этой статьи, был загружен с веб-сайта UCI, который содержит данные о транзакциях, которые были записаны в соответствии с поведением покупателей в интернет-магазине. Набор данных содержал все транзакции, которые были совершены в период с 12.01.2010 по 12.09.2011, т. е. примерно за год в розничных интернет-магазинах, зарегистрированных в Великобритании.

Многие из клиентов, которые участвовали в этом отчете, были в основном оптовиками. Набор данных включает такую ​​информацию, как номера счетов, коды продуктов, описания, количества, даты счетов, цены за единицу, идентификаторы клиентов и названия стран. Он состоит из 541 909 записей, каждая из которых содержит восемь атрибутов.

Построение алгоритма

Используя приведенный выше набор данных, мы попытаемся создать систему интеллектуального анализа данных, которая понимает покупательские намерения клиентов и предоставляет персонализированные рекомендации по продуктам на основе правил ассоциации. Используемый алгоритм будет включать в себя расчет частотности товаров и группировку часто покупаемых товаров вместе с их StockCode и InvoiceNo.

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

Априорный алгоритм

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

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

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

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

  1. Поддержка

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

Support(item X) = (Transactions containing item X) / (Total transactions)

2. Уверенность

Он измеряет вероятность того, что товар Y будет куплен, если был куплен товар X. Он рассчитывается путем деления количества транзакций, в которых товары X и Y были куплены вместе, на количество транзакций, в которых был приобретен товар X.

Confidence(X → Y) = (Transactions containing both X and Y) / (Transactions containing X)

3. Подъем

Это показывает, во сколько раз увеличивается вероятность покупки товара Y при покупке товара X. Он получается путем деления достоверности двух элементов на поддержку элемента Y.

Lift(X → Y) = (Confidence(X → Y)) / (Support(Y))

Значение подъема больше 1 предполагает, что два продукта, скорее всего, будут покупать вместе, а значение меньше 1 указывает на маловероятную связь между продуктами.

Как был реализован априорный алгоритм

Алгоритм априори пытается извлечь некоторые возможные правила в каждой возможной комбинации продуктов, например. подъем можно рассчитать для продукта 1 и продукта 2, продукта 1 и 3, продукта 1 и 4, 2 и 3 и т. д., а также комбинации всех продуктов, т. е. комбинации между продуктами 1, 2, 3 и т. д. В случае большой набор данных, вычисление может быть очень большим, поэтому процесс может быть очень медленным. Чтобы помочь в более быстром вычислении, в нашем алгоритме будут реализованы следующие шаги.

  1. Установка минимального значения для коэффициента поддержки и достоверности. Это позволяет нам находить правила только для продуктов, которые соответствуют определенному порогу существования (поддержка), а также для совместного появления с другими продуктами (доверие). В нашем алгоритме минимальный порог как для поддержки, так и для достоверности был установлен на уровне 0,01.
  2. Затем мы извлекаем все дополнительные даты со значениями поддержки, большими, чем минимальный установленный порог.
  3. Также извлеките из подкомбинации те правила, значения которых больше или равны минимальному установленному порогу.
  4. Упорядочите правила в порядке убывания подъема, уверенности или поддержки в зависимости от выбранного компонента. В этом случае подъем будет использоваться по умолчанию для нашей рекомендации.

Фактическая реализация кода

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

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

# group the data by description and get the count of stock codes
stock_desc = df[["Description","StockCode"]].drop_duplicates()
stock_desc = stock_desc.groupby(["Description"]).agg({"StockCode":"count"}).reset_index()
stock_desc.rename(columns={'StockCode':'Code_Counter'}, inplace=True)
stock_desc = stock_desc[stock_desc["Code_Counter"] > 1]

# delete products with more than one stock code
df = df[~df["Description"].isin(stock_desc["Description"])]

# group the data by stock code and get the count of descriptions
stock_desc = df[["Description","StockCode"]].drop_duplicates()
stock_desc = stock_desc.groupby(["StockCode"]).agg({"Description":"count"}).reset_index()
stock_desc.rename(columns={'Description':'desc_Counter'}, inplace=True)

# delete products with more than one description
stock_desc = stock_desc[stock_desc["desc_Counter"] > 1]

# get the required data with a single description
df = df[~df["StockCode"].isin(stock_desc["StockCode"])]

Априорный алгоритм анализа правил ассоциации

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

def create_apriori_matrix_for_products(data):
    """
    this function groups the data against its invoice number and stock code and then creates a matrix between them.
    @param data: DataFrame - Data to be transformed
    @return: A DataFrame object with an unstacked matrix
    """
    return data.groupby(['InvoiceNo', "StockCode"])['Quantity'].sum().unstack().fillna(0).applymap(lambda val: 1 if val > 0 else 0)

Поиск рекомендуемых продуктов

Получив правила ассоциации, сгенерированные априорным алгоритмом, мы можем использовать их для определения рекомендуемых продуктов на основе истории покупок клиента. В нашем случае мы сосредоточимся на антецедентах (купленных товарах) и следствиях (рекомендуемых товарах) из правил ассоциации. Вот фрагмент кода для поиска рекомендуемых продуктов для данного товара:

def find_stock_by_id(data, stockCode):
    """
    this function returns details of a product given its stock code.
    @param stockCode: A string representing the code of the stock
    @returns:
        StockCode: A string representing the selected stock code
        product_desc: Description of the selected product
    """
    product_desc = data[data["StockCode"] == stockCode]["Description"].unique()
    return stockCode, product_desc[0]

Используя функцию find_stock_by_id, мы можем получить информацию о продукте на основе его биржевого кода.

Определение правил ассоциации

Чтобы определить правила ассоциации, мы вычисляем значения поддержки для каждой возможной конфигурации элемента. В нашем случае мы устанавливаем порог 2% (0,02) для минимального значения поддержки. Затем мы используем функцию association_rules для создания правил ассоциации на основе априорных данных о частоте. Вот фрагмент кода:

apriori_freq_data = apriori(invoice_group_sample, min_support=0.02, use_colnames=True)
association_rules_in_market = association_rules(apriori_freq_data, metric="lift", min_threshold=0.01)
association_rules_in_market.sort_values(['confidence', 'lift'], ascending=[False, False]).head(5)

Запустив приведенный выше код, мы можем получить правила ассоциации, отсортированные по значениям достоверности и подъема. Эти правила дают представление о том, какие продукты часто покупают вместе, и могут использоваться для получения рекомендаций.

Гибридная фильтрация рекомендаций по продуктам

Чтобы иметь возможность рекомендовать продукты на основе истории покупок клиента, мы можем использовать гибридный подход к фильтрации, который сочетает в себе показатели поддержки, подъема и доверия. Здесь используется следующий принцип: «если пользователь покупает продукт с идентификатором Stock ID X, какие продукты ему следует порекомендовать дальше?». Мы можем отсортировать рекомендации на основе вероятности покупки продуктов с идентификатором акции Y, определяемой их значениями достоверности, а также мы можем рассмотреть значение подъема, которое указывает, во сколько раз увеличивается вероятность покупки Y при получении X. Вот фрагмент кода для реализации этой стратегии рекомендаций:

items_recommended = []
# iterate through all antecedents
for idx, product in enumerate(sorted_association_rules_in_market["antecedents"]):
    # since the antecedent is a tuple, we need to extract each item ID
    for j in list(product):
        if str(j) == "X":  # Replace "X" with the desired Stock ID
            # let the ID of the current index
            items_recommended.append(list(sorted_association_rules_in_market.iloc[idx]["consequents"])[0])
            # remove duplicates using a dictionary as a key
            items_recommended = list(dict.fromkeys(items_recommended))

# print the top 10 recommended products
for pro_id in items_recommended[:10]:
    # query the product by its ID
    print(find_stock_by_id(df_sample, pro_id))

Если заменить "X"на желаемый идентификатор акции, приведенный выше код предоставит 10 лучших рекомендуемых продуктов на основе правил ассоциации и истории покупок клиента.

Объединение всего вместе.

При переходе в производственную среду описанный выше алгоритм может оказаться неэффективным, поскольку вам может потребоваться запустить все с данными, что займет много времени. Чтобы преодолеть это, нам нужно создать объект класса, который делает все, этот класс будет обучен, а затем сохранен как двоичный объект, такой как рассол. Затем мы можем использовать файл в качестве рассола в других приложениях и получать рекомендации.

В этом случае у нас есть приложение Flask, которое использует описанное выше, используя единую конечную точку, принимающую введенный пользователем код продукта и возвращающую рекомендуемые продукты. Мы предполагаем, что введенный код является продуктом, который покупает этот клиент. Рабочий код конечной точки показан ниже.

import pickle
from recommender import AprioriRecommentor
import json
import random
from flask import Flask, flash, request, redirect, render_template,url_for
app = Flask(__name__)
@app.route("/", methods=['POST', 'GET'])
def index():
    #load the model
    with open("./recommender_model.pkl", "rb") as model_object:
        model = pickle.load(model_object)
        model_object.close()
    #get random ids to show the user samples
    sample_product_ids =[]
    for prod_ids in model.sorted_association_rules_in_market["antecedents"]:
        sample_product_ids +=list(dict.fromkeys(prod_ids).keys())
    random_ids = " ,".join(str(x) for x in random.sample(sample_product_ids, 10))
    #check if request is post
    if request.method == 'POST':
        #extract the code typed
        product_code_entered = request.form['product_code']
        res = model.show_products_recommended_to_user(product_code_entered)
        if len(res['data']) ==0:
            return render_template("./res.html", result=None, result_id = None, random_ids_codes = random_ids)
        
        
        res_data = [list(da.values()) for da in res['data']]
        res_id = res['Product_Code']

        return render_template("./res.html", result=res_data, result_id = res_id, random_ids_codes = random_ids)
    else:
        return render_template("./res.html", result=None, result_id = 1, random_ids_codes = random_ids)

if __name__ == "__main__":
    app.run()

Пример результатов приложения flask показан на рисунке ниже.

Заключение

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

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