:::: MENU ::::

TalkingData's Blog

现在开始,用数据说话。

锐眼洞察 | 预测性客户分析Part 4——借助聚类和预测分析优化售后服务(翻译)

  • Mar 16 / 2018
  • 0
Data, Enterprise

锐眼洞察 | 预测性客户分析Part 4——借助聚类和预测分析优化售后服务(翻译)

作者:Ryan Aminollahi

原文:Predictive Customer Analytics — Part 4

译者:TalkingData研发副总裁 阎志涛 

本译文禁止商用,转载请注明来源!

本篇是这个系列文章的最后一个部分,将要说明的重点案例是利用聚类分析对售后问题进行分组,对不同分组进行分析,进而采取针对性的优化或者行动。

如果你读过以前的几篇文章,你知道在故事中,顾客X已经购买了一台笔记本电脑。现在想象一下,他正尝试在家里设置这台电脑。在设置的时候,他发现该电脑无法与无线键盘正常连接。他认为自己搞砸了设置并试图找到解决办法:他浏览产品网站查看是否有任何自助视频可帮助他找出原因,但他并没找到任何有用的信息。然后他打电话给公司,得到了一个自动提示让他提供所有的信息。

他在接下来的15分钟排队等候,最终,他排到了一位客户代表,客户代表再次要求他提供所有信息。正如你可以想象的那样,X变得更加恼火。客户代表在听到他的问题后,通过电话向他提供了一些指示,但X无法理解并按照步骤来操作。他要求提供现场帮助,但客户代表拒绝了他,说他的保修不包含现场服务。X感觉非常沮丧,开始考虑再也不从这家供应商购买任何东西。

这是因低质量服务和支持而感到沮丧的无数顾客中的一个例子。在今天的互联网世界中,更换供应商只需点击一下鼠标即可。企业需要更努力、更聪明地保持现有客户的满意度,并且通过他们的推荐获得新的客户。客户服务流程从为客户提供交互选项开始,从网站自助、电子邮件到电话支持,今天的支持中心运行在全方位的各种渠道上。

一旦客户发起联系,企业就需要为他们提供优质的服务:询问最少的问题并迅速解决问题。

这就要求企业不仅要了解客户,还要了解客户当前问题发生的背景以及与客户交互的整个过程。企业需要让客户感觉到企业真正了解并关心他的问题。

今天的客户服务世界已经开始转向使用交互式语音和聊天机器人的自助服务和自动化的时代。

这些自动化的服务需要智能地预测客户正在经历的事情,并能理解客户问题,提供快速的解决方案。预测性分析肯定会对客户服务领域有所帮助。

预测客户发起联系的目的

让我们思考一下前面做错了什么。假定客户X在销售阶段已经将自己的电话号码提供给了公司,客户支持难道不应该通过他的呼叫ID自动识别他吗?

客户X在笔记本电脑交付给他两天之内打电话,是否意味着这通电话非常有可能与这次购买有关呢?在第一次电话过程中,客户支持针对他的笔记本电脑键盘问题创建了一个问题记录,并且给了他一些建议。

然而,过了两个小时之后他又打电话过来,客户支持能否推测到他的第二个电话非常有可能与第一个问题记录有关系?这个用例的目标是建立一个预测模型,这个预测模型可以预测客户联系企业的可能性原因。知道这个原因可以帮助企业快速将客户对接到能解决相应问题的人那里,从而让问题在第一次交互时得到解决。这个用例中的数据是过去的所有客户和企业之间的交易数据。

这些数据包含销售的交易信息,包括产品、状态以及交付的详细数据。我们将来也会使用客户与企业以往联系的数据。对于每一次联系,我们会使用原因、处理这次联系的客户代表、时长、根本原因、解决方案、状态等数据。这是一个分类问题,因此前面我们使用过的算法就比较适合。让目标分类的数量小于10是非常重要的。

将要使用的算法会被用来产生预测目的模型,我们将会使用销售交易和与以前的联系相关的数据去产生这个模型,并将用模型预测客户联系的目的。行动计划如下:这个分类模型会离线进行构建,当一个客户通过电话或者聊天工具联系企业时,使用呼叫者ID或者用户ID去识别客户,然后使用算法去预测这次呼叫的原因。如果预测呼叫的原因是上一次的购买,则通过IVR回答客户“您好,请问您是因最近购买的笔记本电脑有问题而需要帮助吗”。客户一定会感到非常高兴,因为企业能够猜测他的问题,尽管这不一定是真正的原因。

这恰当地表明了我们理解他并且知道他正在经历什么困难。

寻找不满意的客户

一个企业该如何发现他的客户对于企业的产品或者服务是满意还是不满意呢?

第一, 不满意的客户通常会对调查问卷进行反馈。仔细想一下,因为X先生对服务以及产品感到不满意,他通常更愿意花时间去填写调查问卷和发泄。但是Y女士则未必会如此。

第二, 通常仅仅有10%的客户会对调查进行反馈。那么企业如何能够识别出那些沉默的、想要或者已经转移到其他企业的客户呢?这个用例的目标是构建一个模型,这个模型能够预测企业的所有用户的满意度,不管这个用户是否填写了调查问卷。构建这个模型的数据是从那些真实的已填写调查问卷的客户中得来的。

这份数据包括客户的人口统计学数据以及用户历史行为数据,包括与公司之间的事件和交易数据以及结果。特别需要指出的是,这些数据包括缺陷、退货、客户支持的记录、解决问题的时间以及呼叫服务电话的次数,这些数据构成了特征变量。目标变量是从调查问卷得来的度的分数。比较典型的是这个分数是从0到5或者是从0到10的有一位到两位小数的数字。

如果分数是离散的值,比如1、2、3、4、5,那么我们可以使用Gordon分类来处理。在我们的用例中,我们假定分数值是连续的,因此我们将会使用线性回归算法。利用人口统计学和历史的数据,构建一个可以用来预测客户满意度分数的线性回归方程。这个用例的行动计划是:利用真正回答了调查问卷的客户的数据构建一个预测模型,来预测客户满意度分数。我们需要将调查数据进行规范化,从而去掉可能会影响整体模型的异常值,然后我们将模型应用到所有客户,来发现客户的满意度评分。

然后我们的客户支持团队得到一个最不满意的客户列表,可以去主动联系这些客户,询问他们使用产品的感受和问题或者最终给他们一些折扣。

将问题进行类型分组

客户支持团队每天在处理不同的问题,有些问题会被经常问到并且简单直接,技术工程师甚至可以在客户解释完问题之前就能给出解决方案。另外一些问题则不那么常见并且比较复杂,需要多次的电话沟通以及现场服务才能解决。一个网络连接问题是非常容易诊断的,但是诊断一个笔记本电脑的蓝屏问题则要困难得多。实际上人力资源成本是非常高的,因此企业需要找到优化使用人力资源的方法。

这包含对一些问题提供在线帮助,包括对技术支持团队更严格的培训或者对复杂问题建立新的专家职位。为了帮助企业做这些决策,需要基于相似的属性对问题进行分组。这是这个用例的目标,对于一个问题类型列表,企业需要识别逻辑的问题分组,从而使用它们去开发优化那些消耗最少人力资源的解决方案。

这个用例的数据,是从技术支持团队记录下来的问题库数据中得到的问题统计数据。问题数据按照问题类型做汇总。特征数据是解决问题的平均时间、平均电话的次数、替换率等等。既然我们要创建逻辑分组,我们将要使用K-Means聚类算法或者相关的一些变种算法。通过多次采用不同的K值进行试验来衡量出一个最佳的分组数量。

利用问题统计数据,我们能够将相似的问题进行分组。行动计划如下:当问题类型已经被分组,我们将会分析每个分组去发现分组里边的相似性,比如解决问题花了更长的时间或者非常低的发生率。然后我们就可以得出优化解决方案的计划,例如在我们的网站上提供自帮助、在YouTube提供视频或者对这个问题领域的技术人员做更好的培训。

作为一个企业,我们想要达到客户支持的效率和有效性的最大化。这个用例帮助我们达到这个目标。

问题分组用例

我们如何能够将相似的问题分组到不同的问题类型,然后在组里对它们进行分析来判断是否有任何模式,紧接着采取某些行动去解决效率和有效性问题?

载入数据集

In [1]:

(注:左右滑动即可查看完整代码,下同)

%matplotlib inlinefrom pandas import Series, DataFrame
import pandas as pd
import numpy as np
import os
import matplotlib.pylab as plt
from sklearn.model_selection  import train_test_split
from sklearn.cluster import KMeans
import sklearn.metrics

raw_data = pd.read_csv(“issues.csv”)
raw_data.dtypes

Out [1]:

PROBLEM_TYPE             object
COUNT                     int64
AVG_CALLS_TO_RESOLVE    float64
AVG_RESOLUTION_TIME       int64
REOCCUR_RATE            float64
REPLACEMENT_RATE        float64
dtype: object

这个数据集对于每个唯一的问题类型有一条记录,每个类型包含一些度量值,例如总量,解决问题平均电话次数,解决问题平均时常等等。

raw_data.head()

将数据分到不同的相似聚类组中

现在我们将会使用K-Means聚类去根据属性将数据聚类到不同的组当中。首先,我们需要决定分组的最优的数量,为此,我们采用膝部法来测试确定什么时候这个膝状发生。(参照https://datasciencelab.wordpress.com/2013/12/27/finding-the-k-in-k-means-clustering/)

In [3]:

clust_data = raw_data.drop(“PROBLEM_TYPE”,axis=1)#Finding optimal no. of clusters
from scipy.spatial.distance import cdist
clusters=range(1,10)
meanDistortions=[]

for k in clusters:
model=KMeans(n_clusters=k)
model.fit(clust_data)
prediction=model.predict(clust_data)
meanDistortions.append(sum(np.min(cdist(clust_data, model.cluster_centers_, ‘euclidean’), axis=1)) / clust_data.shape[0])

#plt.cla()
plt.plot(clusters, meanDistortions, ‘bx-‘)
plt.xlabel(‘k’)
plt.ylabel(‘Average distortion’)
plt.title(‘Selecting k with the Elbow Method’)

Out [3]:

<matplotlib.text.Text at 0x27298f49eb8>

观察那些点,我们发现膝状发生在cluster=3的时候,这是聚类的最佳的数量,因此我们在实际操作中将会设置聚类的数量是3。然后我们在原始的数据集上添加聚类的ID。

In [4]:

#Optimal clusters is 3
final_model=KMeans(3)
final_model.fit(clust_data)
prediction=final_model.predict(clust_data)#Join predicted clusters back to raw data
raw_data[“GROUP”] = prediction
print(“Groups Assigned : \n”)
raw_data[[“GROUP”,“PROBLEM_TYPE”]]
Groups Assigned :

对分组进行分析

我们现在可以做一系列的箱型图去看这些不同组在不同的特征变量上的差异。我们从count先开始。

In [5]:

plt.cla()
plt.boxplot([[raw_data[“COUNT”][raw_data.GROUP==0]],
             [raw_data[“COUNT”][raw_data.GROUP==1]] ,
               [raw_data[“COUNT”][raw_data.GROUP==2]] ],
           labels=(‘GROUP 1′,’GROUP 2′,’GROUP 3’))

Out[5]:

{‘boxes’: [<matplotlib.lines.Line2D at 0x27299349ef0>,
<matplotlib.lines.Line2D at 0x27299362390>,
<matplotlib.lines.Line2D at 0x27299375cc0>],
‘caps’: [<matplotlib.lines.Line2D at 0x272993589b0>,
<matplotlib.lines.Line2D at 0x27299358ac8>,
<matplotlib.lines.Line2D at 0x2729936abe0>,
<matplotlib.lines.Line2D at 0x2729936eb38>,
<matplotlib.lines.Line2D at 0x2729937ec50>,
<matplotlib.lines.Line2D at 0x2729937ed68>],
‘fliers’: [<matplotlib.lines.Line2D at 0x2729935db38>,
<matplotlib.lines.Line2D at 0x27299375ba8>,
<matplotlib.lines.Line2D at 0x27299385dd8>],
‘means’: [],
‘medians’: [<matplotlib.lines.Line2D at 0x2729935d320>,
<matplotlib.lines.Line2D at 0x2729936ec50>,
<matplotlib.lines.Line2D at 0x272993855c0>],
‘whiskers’: [<matplotlib.lines.Line2D at 0x27299350940>,
<matplotlib.lines.Line2D at 0x27299350a58>,
<matplotlib.lines.Line2D at 0x27299362b00>,
<matplotlib.lines.Line2D at 0x2729936aac8>,
<matplotlib.lines.Line2D at 0x27299379be0>,
<matplotlib.lines.Line2D at 0x27299379cf8>]}

我们可以看到在不同的分组中问题的数量有明显的区别。
接下来我们看解决问题的平均电话数量。

In [6]:

#Now for Avg. Calls to resolve
plt.cla()
plt.boxplot([[raw_data[“AVG_CALLS_TO_RESOLVE”][raw_data.GROUP==0]],
             [raw_data[“AVG_CALLS_TO_RESOLVE”][raw_data.GROUP==1]] ,
               [raw_data[“AVG_CALLS_TO_RESOLVE”][raw_data.GROUP==2]] ],
           labels=(‘GROUP 1′,’GROUP 2′,’GROUP 3’))

Out[6]:

{‘boxes’: [<matplotlib.lines.Line2D at 0x272993f2ba8>,
<matplotlib.lines.Line2D at 0x27299405da0>,
<matplotlib.lines.Line2D at 0x2729941a710>],
‘caps’: [<matplotlib.lines.Line2D at 0x272993f8cc0>,
<matplotlib.lines.Line2D at 0x272993fdc18>,
<matplotlib.lines.Line2D at 0x2729940fd30>,
<matplotlib.lines.Line2D at 0x2729940fe48>,
<matplotlib.lines.Line2D at 0x27299421f60>,
<matplotlib.lines.Line2D at 0x27299428eb8>],
‘fliers’: [<matplotlib.lines.Line2D at 0x27299405c88>,
<matplotlib.lines.Line2D at 0x27299415eb8>,
<matplotlib.lines.Line2D at 0x2729942ef28>],
‘means’: [],
‘medians’: [<matplotlib.lines.Line2D at 0x272993fdd30>,
<matplotlib.lines.Line2D at 0x272994156a0>,
<matplotlib.lines.Line2D at 0x27299428fd0>],
‘whiskers’: [<matplotlib.lines.Line2D at 0x272993f2a90>,
<matplotlib.lines.Line2D at 0x272993f8ba8>,
<matplotlib.lines.Line2D at 0x2729940acc0>,
<matplotlib.lines.Line2D at 0x2729940add8>,
<matplotlib.lines.Line2D at 0x2729941ae80>,
<matplotlib.lines.Line2D at 0x27299421e48>]}

Group 2基本上不需要任何时间就能解决,这表明问题是非常简单和直接的。企业需要去看看这些问题然后给客户提供一个自服务的路径(产品帮助、在线帮助)而不是浪费客户代表的时间。

In [7]:

plt.cla()
plt.boxplot([[raw_data[“REOCCUR_RATE”][raw_data.GROUP==0]],
             [raw_data[“REOCCUR_RATE”][raw_data.GROUP==1]] ,
               [raw_data[“REOCCUR_RATE”][raw_data.GROUP==2]] ],
           labels=(‘GROUP 1′,’GROUP 2′,’GROUP 3’))

Out[7]:

{‘boxes’: [<matplotlib.lines.Line2D at 0x27299485c88>,
<matplotlib.lines.Line2D at 0x27299499e80>,
<matplotlib.lines.Line2D at 0x272994b07f0>],
‘caps’: [<matplotlib.lines.Line2D at 0x2729948eda0>,
<matplotlib.lines.Line2D at 0x27299494cf8>,
<matplotlib.lines.Line2D at 0x272994a4e10>,
<matplotlib.lines.Line2D at 0x272994a4f28>,
<matplotlib.lines.Line2D at 0x272994bc780>,
<matplotlib.lines.Line2D at 0x272994bcf98>],
‘fliers’: [<matplotlib.lines.Line2D at 0x27299499d68>,
<matplotlib.lines.Line2D at 0x272994a8f98>,
<matplotlib.lines.Line2D at 0x272994c2ef0>],
‘means’: [],
‘medians’: [<matplotlib.lines.Line2D at 0x27299494e10>,
<matplotlib.lines.Line2D at 0x272994a8780>,
<matplotlib.lines.Line2D at 0x272994c20f0>],
‘whiskers’: [<matplotlib.lines.Line2D at 0x27299485b70>,
<matplotlib.lines.Line2D at 0x2729948ec88>,
<matplotlib.lines.Line2D at 0x2729949eda0>,
<matplotlib.lines.Line2D at 0x2729949eeb8>,
<matplotlib.lines.Line2D at 0x272994b0f60>,
<matplotlib.lines.Line2D at 0x272994b6f28>]}

Group 2有非常高的复发率,这些问题需要进行分析去看看产品质量如何改进以防止这些问题再次发生。

In [8]:

plt.cla()
plt.boxplot([[raw_data[“REPLACEMENT_RATE”][raw_data.GROUP==0]],
             [raw_data[“REPLACEMENT_RATE”][raw_data.GROUP==1]] ,
               [raw_data[“REPLACEMENT_RATE”][raw_data.GROUP==2]] ],
           labels=(‘GROUP 1′,’GROUP 2′,’GROUP 3’))

Out[8]:

{‘boxes’: [<matplotlib.lines.Line2D at 0x27299526e10>,
<matplotlib.lines.Line2D at 0x27299538f98>,
<matplotlib.lines.Line2D at 0x2729954e978>],
‘caps’: [<matplotlib.lines.Line2D at 0x2729952ef28>,
<matplotlib.lines.Line2D at 0x27299532e80>,
<matplotlib.lines.Line2D at 0x27299544f98>,
<matplotlib.lines.Line2D at 0x272995497f0>,
<matplotlib.lines.Line2D at 0x2729955a908>,
<matplotlib.lines.Line2D at 0x2729955aa20>],
‘fliers’: [<matplotlib.lines.Line2D at 0x27299538ef0>,
<matplotlib.lines.Line2D at 0x2729954e860>,
<matplotlib.lines.Line2D at 0x2729955fa90>],
‘means’: [],
‘medians’: [<matplotlib.lines.Line2D at 0x27299532f98>,
<matplotlib.lines.Line2D at 0x27299549908>,
<matplotlib.lines.Line2D at 0x2729955f278>],
‘whiskers’: [<matplotlib.lines.Line2D at 0x27299526cf8>,
<matplotlib.lines.Line2D at 0x2729952ee10>,
<matplotlib.lines.Line2D at 0x2729953ff28>,
<matplotlib.lines.Line2D at 0x27299544780>,
<matplotlib.lines.Line2D at 0x27299555898>,
<matplotlib.lines.Line2D at 0x27299555fd0>]}

Group 1具有非常广的替换率,它不能给出任何实际可以操作的模式。

Group 2没有任何的替换,这是非常棒的。现在看到的组级别的一些倾向,我们可以基于这些分析做一些组级别的决策。例如Group 2呼叫了很多次,但是解决基本不需要花时间,因此我们可以对Group 2利用自服务。Group 1则不同,呼叫的次数少,但是花了很多的时间去解决,并且有很高的替换率以及复发率,我们可能需要去看看产品是否有问题或者已修复问题是否还在发生。

这就是我们如何利用聚类和预测分析去将我们的问题进行分组,然后基于组进行分析。

—  本系列文章完结  —

Leave a comment

随时欢迎您 联系我们