百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程字典 > 正文

用机器学习来提升你的用户增长:第五步,预测客户的下一个购买日

toyiye 2024-07-06 23:34 20 浏览 0 评论

作者:Bar?? KaramanFollow

编译:ronghuaiyang

正文共:7785 字 13 图

预计阅读时间:23 分钟

导读

当我们流失用户进行了预测之后,为了留住这些可能会流失的客户,我们需要采取一些措施,我们希望了解客户未来一段时间内的行为,然后采取相应的行动。

前文回顾:

用机器学习来提升你的用户增长:第一步,了解你的目标

用机器学习来提升你的用户增长:第二步,客户分群

用机器学习来提升你的用户增长:第三步,预测客户的终生价值

用机器学习来提升你的用户增长:第四步,客户流失预测

第五部分: 预测下一个购买日

我们在数据驱动增长系列中解释的大多数行为背后都有相同的心态:

在客户期望(如LTV预测)之前,以客户想要的方式对待他们,并在糟糕的事情发生之前采取行动(如客户流失)

预测分析对我们很有帮助。其中一个用途是预测客户的下一个购买日。如果你知道客户是否可能在7天内再次购买,该怎么办?

我们可以在此基础上建立我们的战略,并提出许多行动,如:

  • 不要再给促销优惠给这个客户,因为他/她肯定会进行购买
  • 如果在预测的时间窗口内没有购买的话,使用营销的方式推动客户(或者把做预测的家伙给炒了)

在本文中,我们将使用在线零售数据集,并遵循以下步骤:

  • 数据整理(创建前一次/下一次数据集并计算购买日时间差)
  • 特征工程
  • 选择机器学习模型
  • 多分类模型
  • 超参数调优

数据整理

让我们从导入数据开始,做初步的数据工作:

#import libraries
from datetime import datetime, timedelta,date
import pandas as pd
%matplotlib inline
from sklearn.metrics import classification_report,confusion_matrix
import matplotlib.pyplot as plt
import numpy as np
import seaborn as sns
from __future__ import division
from sklearn.cluster import KMeans

#do not show warnings
import warnings
warnings.filterwarnings("ignore")

#import plotly for visualization
import plotly.plotly as py
import plotly.offline as pyoff
import plotly.graph_objs as go

#import machine learning related libraries
from sklearn.svm import SVC
from sklearn.multioutput import MultiOutputClassifier
from sklearn.ensemble import GradientBoostingClassifier
from sklearn.tree import DecisionTreeClassifier
from sklearn.neighbors import KNeighborsClassifier
from sklearn.naive_bayes import GaussianNB
from sklearn.ensemble import RandomForestClassifier
from sklearn.linear_model import LogisticRegression
import xgboost as xgb
from sklearn.model_selection import KFold, cross_val_score, train_test_split

#initiate plotly
pyoff.init_notebook_mode()

#import the csv
tx_data = pd.read_csv('data.csv')

#print first 10 rows
tx_data.head(10)

#convert date field from string to datetime
tx_data['InvoiceDate'] = pd.to_datetime(tx_data['InvoiceDate'])

#create dataframe with uk data only
tx_uk = tx_data.query("Country=='United Kingdom'").reset_index(drop=True)

导入CSV文件以及数据字段转换

我们已经导入了CSV文件,将日期字段从字符串转换为DateTime类型,并过滤了除英国以外的其他国家。

为了建立我们的模型,我们把数据分成两部分:

模型的数据结构

我们使用六个月的行为数据来预测顾客在未来三个月内的首次购买日期。如果没有购买,我们也会预测。我们假设我们的截止日期是2011年9月9日,并分割数据:

tx_6m = tx_uk[(tx_uk.InvoiceDate < date(2011,9,1)) & (tx_uk.InvoiceDate >= date(2011,3,1))].reset_index(drop=True)

tx_next = tx_uk[(tx_uk.InvoiceDate >= date(2011,9,1)) & (tx_uk.InvoiceDate < date(2011,12,1))].reset_index(drop=True)

tx_6m表示六个月的表现,我们使用tx_next来查找tx_6m中最后一次购买日期与tx_next中第一次购买日期之间的天数。

此外,我们将创建一个名为tx_user的dataframe,包含了预测模型需要使用的用户级特征集合:

tx_user = pd.DataFrame(tx_6m['CustomerID'].unique())
tx_user.columns = ['CustomerID']

通过使用tx_next中的数据,我们需要计算我们的label(截止日期前最后一次购买到截止日期后第一次购买之间的天数):

#create a dataframe with customer id and first purchase date in tx_next
tx_next_first_purchase = tx_next.groupby('CustomerID').InvoiceDate.min().reset_index()
tx_next_first_purchase.columns = ['CustomerID','MinPurchaseDate']

#create a dataframe with customer id and last purchase date in tx_6m
tx_last_purchase = tx_6m.groupby('CustomerID').InvoiceDate.max().reset_index()
tx_last_purchase.columns = ['CustomerID','MaxPurchaseDate']

#merge two dataframes
tx_purchase_dates = pd.merge(tx_last_purchase,tx_next_first_purchase,on='CustomerID',how='left')

#calculate the time difference in days:
tx_purchase_dates['NextPurchaseDay'] = (tx_purchase_dates['MinPurchaseDate'] - tx_purchase_dates['MaxPurchaseDate']).dt.days

#merge with tx_user 
tx_user = pd.merge(tx_user, tx_purchase_dates[['CustomerID','NextPurchaseDay']],on='CustomerID',how='left')

#print tx_user
tx_user.head()

#fill NA values with 999
tx_user = tx_user.fillna(999)

现在,tx_user看起来像下面这样:

你很容易注意到,我们有NaN值,因为那些客户还没有进行任何购买。我们用999填入NaN以便稍后快速识别它们。

我们在这个dataframe中有客户id和相应的标签。我们加入特征集合,以构建我们的机器学习模型。


特征工程

对于这个项目,我们选择了我们的候选特征如下:

  • RFM得分和聚类
  • 最近三次购买之间的天数
  • 以天为单位的购买时间差的平均值和标准偏差

在添加这些特征之后,我们需要通过应用get_dummies方法来处理类别特征。

RFM我们在第二篇文章中已经介绍过了。

让我们来关注一下如何添加接下来的两个特征。在这一部分中,我们将经常使用shift()方法。

首先,我们用客户ID和购买日期(而不是datetime)创建一个dataframe。然后我们将删除重复值,因为客户可以在一天内进行多次购买,这些时间的差为0。

#create a dataframe with CustomerID and Invoice Date
tx_day_order = tx_6m[['CustomerID','InvoiceDate']]
#convert Invoice Datetime to day
tx_day_order['InvoiceDay'] = tx_6m['InvoiceDate'].dt.date
tx_day_order = tx_day_order.sort_values(['CustomerID','InvoiceDate'])
#drop duplicates
tx_day_order = tx_day_order.drop_duplicates(subset=['CustomerID','InvoiceDay'],keep='first')

接下来,通过使用shift,我们创建了一个新的列,显示最近3次购买的日期,看看我们的dataframe是什么样子的:

#shifting last 3 purchase dates
tx_day_order['PrevInvoiceDate'] = tx_day_order.groupby('CustomerID')['InvoiceDay'].shift(1)
tx_day_order['T2InvoiceDate'] = tx_day_order.groupby('CustomerID')['InvoiceDay'].shift(2)
tx_day_order['T3InvoiceDate'] = tx_day_order.groupby('CustomerID')['InvoiceDay'].shift(3)

输出:

让我们开始计算每个购买日期的天数差:

tx_day_order['DayDiff'] = (tx_day_order['InvoiceDay'] - tx_day_order['PrevInvoiceDate']).dt.days
tx_day_order['DayDiff2'] = (tx_day_order['InvoiceDay'] - tx_day_order['T2InvoiceDate']).dt.days
tx_day_order['DayDiff3'] = (tx_day_order['InvoiceDay'] - tx_day_order['T3InvoiceDate']).dt.days

输出:

对于每个客户ID,我们使用.agg()方法来找出购买日的差的平均值和标准差:

tx_day_diff = tx_day_order.groupby('CustomerID').agg({'DayDiff': ['mean','std']}).reset_index()
tx_day_diff.columns = ['CustomerID', 'DayDiffMean','DayDiffStd']

现在我们要做一个艰难的决定。上面的计算对于有很多购买的客户是非常有用的。但是对于1-2次购买的人来说,情况就不一样了。例如,将一个在很短时间内只购买了两件商品的顾客标记为“频繁光顾”还为时过早。

我们只保留那些购买次数>3的客户:

tx_day_order_last = tx_day_order.drop_duplicates(subset=['CustomerID'],keep='last')

最后,我们删除NA值,合并新的dataframes与tx_user,并应用.get_dummies()转换类别值:

tx_day_order_last = tx_day_order_last.dropna()
tx_day_order_last = pd.merge(tx_day_order_last, tx_day_diff, on='CustomerID')
tx_user = pd.merge(tx_user, tx_day_order_last[['CustomerID','DayDiff','DayDiff2','DayDiff3','DayDiffMean','DayDiffStd']], on='CustomerID')
#create tx_class as a copy of tx_user before applying get_dummies
tx_class = tx_user.copy()
tx_class = pd.get_dummies(tx_class)

我们的特征集合已经为构建好了,可以开始做分类模型了。但是有很多不同的模型,我们应该使用哪一个呢?


选择一个机器学习模型

在开始选择模型之前,我们需要采取两个行动。首先,我们需要标识标签中的分类。一般来说,用百分位数看可以。我们使用.describe()方法在NextPurchaseDay中查看它们:

对于统计数据和业务需求来说,确定边界都是一个问题。首先,它应该要有意义,另外需要很容易采取行动和沟通。考虑到这两个,我们分为三个类:

  • 0-20: 0-20天内购买的客户 — 类名:2
  • 21-49: 21-49天内购买的客户 — 类名:1
  • ≥50:在50天内购买的客户 — 类名:0
tx_class['NextPurchaseDayRange'] = 2
tx_class.loc[tx_class.NextPurchaseDay>20,'NextPurchaseDayRange'] = 1
tx_class.loc[tx_class.NextPurchaseDay>50,'NextPurchaseDayRange'] = 0

最后一步是查看我们的特征和标签之间的相关性。相关矩阵是最简洁的表示方法之一:

corr = tx_class[tx_class.columns].corr()
plt.figure(figsize = (30,20))
sns.heatmap(corr, annot = True, linewidths=0.2, fmt=".2f")

Overall Score的正相关系数最高(0.45),Recency的负相关系数最高(-0.54)。

对于这个特殊的问题,我们希望使用精度最高的模型。我们分别进行训练和测试,测试不同模型的准确性:

#train & test split
tx_class = tx_class.drop('NextPurchaseDay',axis=1)
X, y = tx_class.drop('NextPurchaseDayRange',axis=1), tx_class.NextPurchaseDayRange
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=44)

#create an array of models
models = []
models.append(("LR",LogisticRegression()))
models.append(("NB",GaussianNB()))
models.append(("RF",RandomForestClassifier()))
models.append(("SVC",SVC()))
models.append(("Dtree",DecisionTreeClassifier()))
models.append(("XGB",xgb.XGBClassifier()))
models.append(("KNN",KNeighborsClassifier()))

#measure the accuracy 
for name,model in models:
    kfold = KFold(n_splits=2, random_state=22)
    cv_result = cross_val_score(model,X_train,y_train, cv = kfold,scoring = "accuracy")
    print(name, cv_result)

选择准确率最高的机器学习模型

每个模型的准确率:

从这个结果可以看出,朴素贝叶斯是最优的一种算法(正确率约为64%)。但在那之前,让我们看看我们到底做了什么。我们在机器学习中应用了一个基本的概念,那就是交叉验证

我们如何确保机器学习模型在不同数据集上的稳定性?另外,如果在我们选择的测试集中有噪声会怎样?

交叉验证是一种衡量方法。它通过选择不同的测试集来得到模型的分数。如果偏差很小,则意味着模型是稳定的。在我们的例子中,分数之间的偏差是可以接受的(除了决策树分类器)。

通常,我们应该使用朴素贝叶斯。但是对于这个例子,让我们继续使用XGBoost来展示如何使用一些高级技术来改进现有的模型。

多分类模型

要构建我们的模型,我们将遵循前几篇文章中的步骤。但是为了进一步改进它,我们将执行超参数调优

通过编程,我们将找出我们的模型的最佳参数,使其提供最佳的准确性。让我们先从我们的模型代码开始:

xgb_model = xgb.XGBClassifier().fit(X_train, y_train)print('Accuracy of XGB classifier on training set: {:.2f}'
       .format(xgb_model.score(X_train, y_train)))
print('Accuracy of XGB classifier on test set: {:.2f}'
       .format(xgb_model.score(X_test[X_train.columns], y_test)))

在这个版本中,我们测试集的准确率为58%:

XGBClassifier有很多参数。你可以在这里找到这些参数的列表。对于本例,我们选择max_depthmin_child_weight.

下面的代码将为这些参数生成最佳值:

该算法表示,max_depth和min_child_weight的最佳值分别为3和5。看看它是如何提高准确性的:

我们的分数从58%上升到了62%。这是一个很大的进步。

知道下一个购买日也是预测销售的好指标。我们将在下一部分中深入探讨这个主题。


英文原文:https://towardsdatascience.com/predicting-next-purchase-day-15fae5548027

相关推荐

为何越来越多的编程语言使用JSON(为什么编程)

JSON是JavascriptObjectNotation的缩写,意思是Javascript对象表示法,是一种易于人类阅读和对编程友好的文本数据传递方法,是JavaScript语言规范定义的一个子...

何时在数据库中使用 JSON(数据库用json格式存储)

在本文中,您将了解何时应考虑将JSON数据类型添加到表中以及何时应避免使用它们。每天?分享?最新?软件?开发?,Devops,敏捷?,测试?以及?项目?管理?最新?,最热门?的?文章?,每天?花?...

MySQL 从零开始:05 数据类型(mysql数据类型有哪些,并举例)

前面的讲解中已经接触到了表的创建,表的创建是对字段的声明,比如:上述语句声明了字段的名称、类型、所占空间、默认值和是否可以为空等信息。其中的int、varchar、char和decimal都...

JSON对象花样进阶(json格式对象)

一、引言在现代Web开发中,JSON(JavaScriptObjectNotation)已经成为数据交换的标准格式。无论是从前端向后端发送数据,还是从后端接收数据,JSON都是不可或缺的一部分。...

深入理解 JSON 和 Form-data(json和formdata提交区别)

在讨论现代网络开发与API设计的语境下,理解客户端和服务器间如何有效且可靠地交换数据变得尤为关键。这里,特别值得关注的是两种主流数据格式:...

JSON 语法(json 语法 priority)

JSON语法是JavaScript语法的子集。JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔花括号保存对象方括号保存数组JS...

JSON语法详解(json的语法规则)

JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔大括号保存对象中括号保存数组注意:json的key是字符串,且必须是双引号,不能是单引号...

MySQL JSON数据类型操作(mysql的json)

概述mysql自5.7.8版本开始,就支持了json结构的数据存储和查询,这表明了mysql也在不断的学习和增加nosql数据库的有点。但mysql毕竟是关系型数据库,在处理json这种非结构化的数据...

JSON的数据模式(json数据格式示例)

像XML模式一样,JSON数据格式也有Schema,这是一个基于JSON格式的规范。JSON模式也以JSON格式编写。它用于验证JSON数据。JSON模式示例以下代码显示了基本的JSON模式。{"...

前端学习——JSON格式详解(后端json格式)

JSON(JavaScriptObjectNotation)是一种轻量级的数据交换格式。易于人阅读和编写。同时也易于机器解析和生成。它基于JavaScriptProgrammingLa...

什么是 JSON:详解 JSON 及其优势(什么叫json)

现在程序员还有谁不知道JSON吗?无论对于前端还是后端,JSON都是一种常见的数据格式。那么JSON到底是什么呢?JSON的定义...

PostgreSQL JSON 类型:处理结构化数据

PostgreSQL提供JSON类型,以存储结构化数据。JSON是一种开放的数据格式,可用于存储各种类型的值。什么是JSON类型?JSON类型表示JSON(JavaScriptO...

JavaScript:JSON、三种包装类(javascript 包)

JOSN:我们希望可以将一个对象在不同的语言中进行传递,以达到通信的目的,最佳方式就是将一个对象转换为字符串的形式JSON(JavaScriptObjectNotation)-JS的对象表示法...

Python数据分析 只要1分钟 教你玩转JSON 全程干货

Json简介:Json,全名JavaScriptObjectNotation,JSON(JavaScriptObjectNotation(记号、标记))是一种轻量级的数据交换格式。它基于J...

比较一下JSON与XML两种数据格式?(json和xml哪个好)

JSON(JavaScriptObjectNotation)和XML(eXtensibleMarkupLanguage)是在日常开发中比较常用的两种数据格式,它们主要的作用就是用来进行数据的传...

取消回复欢迎 发表评论:

请填写验证码