Руководство по прогнозированию ценности жизни клиента (CLV) в Python с использованием метода BG-NBD и гамма-гаммы.
Пожизненная ценность клиента — это общая сумма, которую клиент потратит с момента приобретения до прекращения отношений с бизнесом. В моем последнем проекте я рассчитывал CLV с помощью Python.
Если вы хотите это увидеть:
На этот раз мы будем делать прогноз.
В чем разница между «предсказанием» и «расчетом»
Когда мы рассчитываем CLV, мы можем только проанализировать и изучить нашу текущую ситуацию, мы не можем угадать, когда клиент покупает новый продукт или уже достиг своих пределов. С прогнозированием мы добавим машинное обучение в наш процесс и сможем предсказать процесс отказа наших клиентов.
У каждого клиента свой показатель отказа, и с помощью инструментов машинного обучения мы свяжемся с ним.
Какие шаги?
- Подготовка данных
- Прогнозирование ожидаемых продаж с помощью модели BG-NBD
- Ожидаемая средняя прибыль с гамма-гамма-моделью
- Расчет CLTV с BG-NBD и гамма-гамма-моделью
- Создание сегментов по CLTV
1. Подготовка данных
- Информация о наборе данных
Компания электронной коммерции хочет сегментировать своих клиентов и определить маркетинговые стратегии в соответствии с этими сегментами.
Набор данных:
https://archive.ics.uci.edu/ml/datasets/Online+Retail+II
Набор данных показывает продажи британского интернет-магазина в период с 12.01.2009 по 12.09.2011.
InvoiceNo: номер счета. Номинал. 6-значный целочисленный номер, который однозначно присваивается каждой транзакции. Если этот код начинается с буквы «с», это означает отмену.
StockCode: код товара (товара). Номинал. 5-значный целочисленный номер, который уникально присваивается каждому отдельному продукту.
Описание: название продукта (элемента). Номинальное.
Количество: количество каждого продукта (элемента) за транзакцию. Числовой.
InvoiceDate: дата и время выставления счета. Числовой. День и время создания транзакции.
UnitPrice: цена за единицу. Числовой. Цена товара за единицу в фунтах стерлингов (£).
CustomerID: номер клиента. Номинал. 5-значный целочисленный номер, который присваивается каждому клиенту.
Страна: название страны. Номинал. Название страны, в которой проживает клиент.
- Необходимая библиотека и функции
pip install lifetimes pip install sqlalchemy from sqlalchemy import create_engine import datetime as dt import pandas as pd import matplotlib.pyplot as plt from lifetimes import BetaGeoFitter from lifetimes import GammaGammaFitter from lifetimes.plotting import plot_period_transactions def outlier_thresholds(dataframe, variable): quartile1 = dataframe[variable].quantile(0.01) quartile3 = dataframe[variable].quantile(0.99) interquantile_range = quartile3 — quartile1 up_limit = quartile3 + 1.5 * interquantile_range low_limit = quartile1–1.5 * interquantile_range return low_limit, up_limit def replace_with_thresholds(dataframe, variable): low_limit, up_limit = outlier_thresholds(dataframe, variable) dataframe.loc[(dataframe[variable] < low_limit), variable] = low_limit dataframe.loc[(dataframe[variable] > up_limit), variable] = up_limit # Additional info; 'outlier_thresholds' function, is so useful function you can use it in your data preparation process, it finds out outlier_thresholds and equals it either up_limit or low_limit. They are simultaneously used with replace_with_thresholds function. With the help of these two function, We will equalize our outlier thresholds to determined low_limit and up_limit values without taking a long time. #Where you can find the dataset https://archive.ics.uci.edu/ml/datasets/Online+Retail+II df_ = pd.read_excel(“online_retail_II.xlsx”, sheet_name=”Year 2010–2011") df = df_.copy() df.shape OUT = (541910, 8) df.describe().T
df.dropna(inplace=True) #For focusing on CLV prediction ,I fastly deleted all missing values. df = df[~df["Invoice"].str.contains("C", na=False)] # removing Cancellations from the data replace_with_thresholds(df, "Quantity") replace_with_thresholds(df, "Price") #After our transactions, Let's check it out how describe looks like. df.describe().T
- Подготовка структуры жизненных данных
df[“TotalPrice”] = df[“Quantity”] * df[“Price”] df.head()
Давность = Время, прошедшее с момента последней покупки [Еженедельно]
[Если вы читали другую статью, о которой я упоминал выше, мы рассчитали давность в соответствии с сегодняшним днем [потому что это было расчет, И мы рассчитываем текущее значение CLV], но здесь receny будет рассчитываться индивидуально для каждого клиента.
T = за какое время до даты анализа была сделана первая покупка [Еженедельно]
Частота = общее количество повторных покупок
monetary_value = средний доход за покупку
cltv_df = df.groupby(‘Customer ID’).agg({‘InvoiceDate’: [lambda date: (date.max() — date.min()).days, lambda date: (today_date — date.min()).days], ‘Invoice’: lambda num: num.nunique(), ‘TotalPrice’: lambda TotalPrice: TotalPrice.sum()}) cltv_df.head(8)
cltv_df.columns = cltv_df.columns.droplevel(0) cltv_df.columns = ['recency', 'T', 'frequency', 'monetary'] cltv_df.head(5)
Мы создали наши переменные R-T-F-M, но осталось еще несколько проблем. Теперь нам нужно преобразовать в соответствующий формат данных.
Например; Денежный показатель должен быть «Средним доходом», но он показывает нам общий доход клиента. Итак, с помощью базовых кодов Python мы преобразуем его.
#Expressing "monetary value" as average earnings per purchase cltv_df["monetary"] = cltv_df["monetary"] / cltv_df["frequency"] # selection of monetary values greater than zero cltv_df = cltv_df[cltv_df["monetary"] > 0] # Expression of "recency "and "T" in weekly terms cltv_df["recency"] = cltv_df["recency"] / 7 cltv_df["T"] = cltv_df["T"] / 7 #frequency must be greater than 1. cltv_df = cltv_df[(cltv_df['frequency'] > 1)] After all trasformation ,lets check how our data looks like now. ctlv_df.head()
Мы организовали весь набор данных для запуска в модели BG-NBD.
2. Создание модели BG-NBD/прогнозирование ожидаемых продаж с помощью модели BG-NBD
bgf = BetaGeoFitter(penalizer_coef=0.001) #setting up the model bgf.fit(cltv_df['frequency'], cltv_df['recency'], cltv_df['T']) #fitting of all dataset
Теперь наша модель подходит, и процесс машинного обучения завершен. Мы можем создавать осмысленные модели из данных. Давайте зададим несколько вопросов и попробуем найти ответы.
- Кого из 10 клиентов мы ожидаем больше всего в неделю?
bgf.conditional_expected_number_of_purchases_up_to_time(1, cltv_df['frequency'], cltv_df['recency'], cltv_df['T']).sort_values(ascending=False).head(10) #1 = 1 week
Давайте назначим его переменной и отобразим в наших данных.
cltv_df["expected_purc_1_week"] = bgf.predict(1, cltv_df['frequency'], cltv_df['recency'], cltv_df['T']) #conditional_expected_number_of_purchases_up_to_time and predict are basically same. cltv_df.head(5)
- Кого из 10 клиентов мы ожидаем больше всего в течение 1 месяца?
bgf.predict(4, cltv_df['frequency'], cltv_df['recency'], cltv_df['T']).sort_values(ascending=False).head(10)
cltv_df[“expected_purc_1_month”] = bgf.predict(4, cltv_df[‘frequency’], cltv_df[‘recency’], cltv_df[‘T’]) cltv_df.sort_values("expected_purc_1_month", ascending=False).head(10) #Sorted the variables accourding to 1month expected purchase prediction.
- Какое ожидаемое количество продаж всей компании за 1 месяц?
bgf.predict(4,cltv_df['frequency'],cltv_df['recency'],cltv_df['T']).sum() OUTPUT = 1777.1450731636987 #It is a transaction amount that is expected in the next month.
- Оценка результатов прогноза
plot_period_transactions(bgf) plt.show()
Мы видим более или менее успешное прогнозирование нашей модели.
3. Определение модели ГАММА-ГАММА/ожидаемой средней прибыли с помощью модели Гамма-Гамма
Итак, во второй главе мы предсказали нашу прибыль с помощью модели BG-NBD, для модели BG-NBD мы использовали 3 переменные: частоту, недавность и T. В модели Гамма-Гамма нам нужны только 2 переменные, частотная и денежная. Итак, приступим к анализу.
ggf = GammaGammaFitter(penalizer_coef=0.01) ggf.fit(cltv_df['frequency'], cltv_df['monetary']) #As I mentioned above, we only use two variables . We used 3 variables on BG-NBD model. ggf.conditional_expected_average_profit(cltv_df['frequency'], cltv_df['monetary']).head(10)
ggf.conditional_expected_average_profit(cltv_df[‘frequency’], cltv_df[‘monetary’]).sort_values(ascending=False).head(10) #Let's sorted values from largest to smallest
cltv_df["expected_average_profit"] = ggf.conditional_expected_average_profit(cltv_df['frequency'], cltv_df['monetary']) cltv_df.head(10)
cltv_df.sort_values("expected_average_profit",ascending=False).head(10) #Sorted values according to expected_avarage_profit
4. Расчет CLTV с BG-NBD и гамма-гамма-моделью
Теперь мы смешаем обе модели и получим чистые, проанализированные значения CLTV.
cltv = ggf.customer_lifetime_value(bgf, cltv_df[‘frequency’], cltv_df[‘recency’], cltv_df[‘T’], cltv_df[‘monetary’], time=3, # 3 Months freq=”W”, # Frequency of T ,in this case it is 'weekly' discount_rate=0.01) cltv.head(5)
cltv.shape OUTPUT = (2845,) cltv = cltv.reset_index() cltv.head()
cltv.sort_values(by="clv", ascending=False).head(10)
Мы нашли список самых важных для меня клиентов за 3 месяца, в порядке от большего к меньшему.
cltv_final = cltv_df.merge(cltv, on="Customer ID", how="left") #merging our real dataset and cltv_df data. cltv_final
cltv_final.sort_values(by=”clv”, ascending=False).head(10) #Sorting values by 'clv' variable.
- Стандартизация CLTV
scaler = MinMaxScaler(feature_range=(0, 1)) #score between 0-1 ,1 is best 0 is worst. You can change by your wish, if you want you can score between 0-100 . scaler.fit(cltv_final[[“clv”]]) cltv_final[“scaled_clv”] = scaler.transform(cltv_final[[“clv”]]) cltv_final.sort_values(by="scaled_clv", ascending=False).head() #So let's observe it.
5. Создание сегментов с помощью CLTV
# Let's divide the customers into 4 groups: cltv_final["segment"] = pd.qcut(cltv_final["scaled_clv"], 4, labels=["D", "C", "B", "A"]) cltv_final.head()
cltv_final.sort_values(by="scaled_clv", ascending=False).head(10)
Конец
Итак, с помощью CLV мы сегментировали наших клиентов, теперь мы можем генерировать разные маркетинговые стратегии для разных сегментов. Таким образом, мы можем более эффективно использовать наш маркетинговый бюджет.
Если вы хотите узнать больше о CLV, вы можете посмотреть мою другую статью:
Спасибо за чтение.
Больше контента на plainenglish.io. Подпишитесь на нашу бесплатную еженедельную рассылку здесь.