K-Means 客户分群 python

1.背景与挖掘目标

1.1背景

航空公司业务竞争激烈,从产品中心转化为客户中心。

针对不同类型客户,进行精准营销,实现利润最大化。

建立客户价值评估模型,进行客户分类,是解决问题的办法

1.2挖掘目标

借助航空公司客户数据,对客户进行分类。

对不同的客户类别进行特征分析,比较不同类客户的客户价值

对不同价值的客户类别提供个性化服务,制定相应的营销策略。

详情数据见数据集内容中的air_data.csv和客户信息属性说明

2.分析方法与过程

2.1分析方法

首先,明确目标是客户价值识别。

识别客户价值,应用最广泛的模型是三个指标(消费时间间隔(Recency),消费频率(Frequency),消费金额(Monetary))

以上指标简称RFM模型,作用是识别高价值的客户

消费金额,一般表示一段时间内,消费的总额。但是,因为航空票价收到距离和舱位等级的影响,同样金额对航空公司价值不同。

因此,需要修改指标。选定变量,舱位因素=舱位所对应的折扣系数的平均值=C,距离因素=一定时间内积累的飞行里程=M。

再考虑到,航空公司的会员系统,用户的入会时间长短能在一定程度上影响客户价值,所以增加指标L=入会时间长度=客户关系长度

总共确定了五个指标,消费时间间隔R,客户关系长度L,消费频率F,飞行里程M和折扣系数的平均值C

以上指标,作为航空公司识别客户价值指标,记为LRFMC模型

如果采用传统的RFM模型,如下图。它是依据,各个属性的平均值进行划分,但是,细分的客户群太多,精准营销的成本太高。

综上,这次案例,采用聚类的办法进行识别客户价值,以LRFMC模型为基础

本案例,总体流程如下图

2.2挖掘步骤

从航空公司,选择性抽取与新增数据抽取,形成历史数据和增量数据

对步骤一的两个数据,进行数据探索性分析和预处理,主要有缺失值与异常值的分析处理,属性规约、清洗和变换

利用步骤2中的已处理数据作为建模数据,基于旅客价值的LRFMC模型进行客户分群,对各个客户群再进行特征分析,识别有价值客户。

针对模型结果得到不同价值的客户,采用不同的营销手段,指定定制化的营销服务,或者针对性的优惠与关怀。(重点维护老客户)

2.3数据抽取

选取,2014-03-31为结束时间,选取宽度为两年的时间段,作为观测窗口,抽取观测窗口内所有客户的详细数据,形成历史数据

对于后续新增的客户信息,采用目前的时间作为重点,形成新增数据

2.4探索性分析

本案例的探索分析,主要对数据进行缺失值和异常值分析。

发现,存在票价为控制,折扣率为0,飞行公里数为0。票价为空值,可能是不存在飞行记录,其他空值可能是,飞机票来自于积分兑换等渠道,

查找每列属性观测值中空值的个数、最大值、最小值的代码如下。

importpandasaspd

datafile=r'/home/kesci/input/date27730/air_data.csv'#航空原始数据,第一行为属性标签

resultfile =r'/home/kesci/work/test.xls'#数据探索结果表

data = pd.read_csv(datafile, encoding ='utf-8')#读取原始数据,指定UTF-8编码(需要用文本编辑器将数据装换为UTF-8编码)

explore = data.describe(percentiles = [], include ='all').T#包括对数据的基本描述,percentiles参数是指定计算多少的分位数表(如1/4分位数、中位数等);T是转置,转置后更方便查阅

print(explore)

explore['null'] = len(data)-explore['count']#describe()函数自动计算非空值数,需要手动计算空值数

explore = explore[['null','max','min']]

explore.columns = [u'空值数',u'最大值',u'最小值']#表头重命名

print('-----------------------------------------------------------------以下是处理后数据')

print(explore)

'''这里只选取部分探索结果。

describe()函数自动计算的字段有count(非空值数)、unique(唯一值数)、top(频数最高者)、freq(最高频数)、mean(平均值)、std(方差)、min(最小值)、50%(中位数)、max(最大值)'''

-----------------------------------------------------------------以下是处理前数据

count unique         top   freq      mean       std

MEMBER_NO62988NaNNaNNaN31494.518183.2

FFP_DATE6298830682011/01/13184NaNNaN

FIRST_FLIGHT_DATE6298834062013/02/1696NaNNaN

GENDER629852男48134NaNNaN

FFP_TIER62988NaNNaNNaN4.102160.373856

WORK_CITY607193310广州9385NaNNaN

WORK_PROVINCE597401185广东17507NaNNaN

WORK_COUNTRY62962118CN57748NaNNaN

...

-----------------------------------------------------------------以下是处理后数据

空值数       最大值   最小值

MEMBER_NO0629881

FFP_DATE0NaNNaN

FIRST_FLIGHT_DATE0NaNNaN

GENDER3NaNNaN

FFP_TIER064

WORK_CITY2269NaNNaN

WORK_PROVINCE3248NaNNaN

WORK_COUNTRY26NaNNaN

AGE4201106

LOAD_TIME0NaNNaN

FLIGHT_COUNT02132

BP_SUM05053080

...

2.3数据预处理

数据清洗

丢弃票价为空记录

丢弃票价为0、平均折扣率不为0、总飞行公里数大于0的记录

import pandas as pd

datafile= '/home/kesci/input/date27730/air_data.csv'#航空原始数据,第一行为属性标签

cleanedfile = ''#数据清洗后保存的文件

data = pd.read_csv(datafile,encoding='utf-8')#读取原始数据,指定UTF-8编码(需要用文本编辑器将数据装换为UTF-8编码)

data = data[data['SUM_YR_1'].notnull() & data['SUM_YR_2'].notnull()]#票价非空值才保留

#只保留票价非零的,或者平均折扣率与总飞行公里数同时为0的记录。

index1 = data['SUM_YR_1'] != 0

index2 = data['SUM_YR_2'] != 0

index3 = (data['SEG_KM_SUM'] == 0) & (data['avg_discount'] == 0)#该规则是“与”,书上给的代码无法正常运行,修改'*'为'&'

data = data[index1 | index2 | index3]#该规则是“或”

print(data)

# data.to_excel(cleanedfile) #导出结果

————————————————————以下是处理后数据————————

MEMBER_NO    FFP_DATE FIRST_FLIGHT_DATE GENDER  FFP_TIER  \

0          54993  2006/11/02        2008/12/24      男         6

1          28065  2007/02/19        2007/08/03      男         6

2          55106  2007/02/01        2007/08/30      男         6

3          21189  2008/08/22        2008/08/23      男         5

4          39546  2009/04/10        2009/04/15      男         6

5          56972  2008/02/10        2009/09/29      男         6

6          44924  2006/03/22        2006/03/29      男         6

7          22631  2010/04/09        2010/04/09      女         6

8          32197  2011/06/07        2011/07/01      男         5

9          31645  2010/07/05        2010/07/05      女         6

属性规约

原始数据中属性太多,根据航空公司客户价值LRFMC模型,选择与模型相关的六个属性。

删除其他无用属性,如会员卡号等等

defreduction_data(data):

data = data[['LOAD_TIME','FFP_DATE','LAST_TO_END','FLIGHT_COUNT','SEG_KM_SUM','avg_discount']]

# data['L']=pd.datetime(data['LOAD_TIME'])-pd.datetime(data['FFP_DATE'])

# data['L']=int(((parse(data['LOAD_TIME'])-parse(data['FFP_ADTE'])).days)/30)

d_ffp = pd.to_datetime(data['FFP_DATE'])

d_load = pd.to_datetime(data['LOAD_TIME'])

res = d_load - d_ffp

data2=data.copy()

data2['L'] = res.map(lambdax: x / np.timedelta64(30*24*60,'m'))

data2['R'] = data['LAST_TO_END']

data2['F'] = data['FLIGHT_COUNT']

data2['M'] = data['SEG_KM_SUM']

data2['C'] = data['avg_discount']

data3 = data2[['L','R','F','M','C']]

returndata3

data3=reduction_data(data)

print(data3)

————————————以下是以上代码处理后数据————————————

LRFMC

0       90.2000001  210  580717  0.961639

1       86.5666677  140  293678  1.252314

2       87.16666711  135  283712  1.254676

3       68.23333397   23  281336  1.090870

4       60.5333335  152  309928  0.970658

5       74.70000079   92  294585  0.967692

6       97.7000001  101  287042  0.965347

7       48.4000003   73  287230  0.962070

8       34.2666676   56  321489  0.828478

数据变换

意思是,将原始数据转换成“适当”的格式,用来适应算法和分析等等的需要。

本案例,主要采用数据变换的方式为属性构造和数据标准化 3.需要构造LRFMC的五个指标

L=LOAD_TIME-FFP_DATE(会员入会时间距观测窗口结束的月数=观测窗口的结束时间-入会时间(单位:月))

R=LAST_TO_END(客户最近一次乘坐公司距观测窗口结束的月数=最后一次。。。)

F=FLIGHT_COUNT(观测窗口内的飞行次数)

M=SEG_KM_SUM(观测窗口的总飞行里程)

C=AVG_DISCOUNT(平均折扣率)

defzscore_data(data):

data = (data - data.mean(axis=0)) / data.std(axis=0)

data.columns = ['Z'+ iforiindata.columns]

returndata

data4 = zscore_data(data3)

data4

————————————以下是以上代码处理后数据————————————

ZLZRZFZMZC

0     1.435707-0.94494814.03401626.7611541.295540

1     1.307152-0.9118949.07321313.1268642.868176

2     1.328381-0.8898598.71886912.6534812.880950

3     0.658476-0.4160980.78158512.5406221.994714

4     0.386032-0.9229129.92363613.8987361.344335

5     0.887281-0.5152575.67151913.1699471.328291

模型构建

1.客户聚类

利用K-Means聚类算法对客户数据进行客户分群,聚成五类(根据业务理解和需要,分析与讨论后,确定客户类别数量)

代码如下

inputfile = r'/home/kesci/input/date27730/zscoreddata.xls'#待聚类的数据文件

k = 5#需要进行的聚类类别数

#读取数据并进行聚类分析

data = pd.read_excel(inputfile)#读取数据

#调用k-means算法,进行聚类分析

kmodel = KMeans(n_clusters = k, n_jobs = 4)#n_jobs是并行数,一般等于CPU数较好

kmodel.fit(data)#训练模型

r1 = pd.Series(kmodel.labels_).value_counts()

r2 = pd.DataFrame(kmodel.cluster_centers_)

r = pd.concat([r2, r1], axis=1)

r.columns = list(data.columns) + ['类别数目']

# print(r)

# r.to_excel(classoutfile,index=False)

r = pd.concat([data, pd.Series(kmodel.labels_, index=data.index)], axis=1)

r.columns = list(data.columns) + ['聚类类别']

print(kmodel.cluster_centers_)

print(kmodel.labels_)

r

[[-0.70078704 -0.41513666 -0.1607619  -0.16049688 -0.25665898]

[-0.31411607  1.68662534 -0.57386257 -0.53661609 -0.17243195]

[ 0.48347647 -0.79941777  2.48236495  2.42356419  0.30943042]

[ 1.16033496 -0.37744106 -0.0870043  -0.09499704 -0.15836889]

[ 0.05165705 -0.00258448 -0.23089344 -0.23513858  2.17775056]]

[3 3 3 ... 3 3 3]

ZLZRZFZMZC聚类类别

0     1.6898820.140299-0.6357880.068794-0.3371863

1     1.689882-0.3224420.8524530.843848-0.5536133

2     1.681743-0.487707-0.2105760.158569-1.0946803

3     1.534185-0.7851840.0020300.273091-1.1487873

4     0.890167-0.426559-0.635788-0.6851701.2319094

5-0.232618-0.690983-0.635788-0.603898-0.3912930

6-0.4969491.996225-0.706656-0.661752-1.3111071

就剩下最后一步,画图:

defdensity_plot(data):

plt.rcParams['font.sans-serif']=['SimHei']

plt.rcParams['axes.unicode_minus']=False

p=data.plot(kind='kde',linewidth=2,subplots=True,sharex=False)

[p[i].set_ylabel('密度')foriinrange(5)]

[p[i].set_title('客户群%d'%i)foriinrange(5)]

plt.legend()

plt.show()

returnplt

density_plot(data4)

clu = kmodel.cluster_centers_

x = [1,2,3,4,5]

colors = ['red','green','yellow','blue','black']

foriinrange(5):

plt.plot(x,clu[i],label='clustre '+str(i),linewidth

=6-i,color=colors[i],marker='o')

plt.xlabel('L  R  F  M  C')

plt.ylabel('values')

plt.show()

客户群1:red,客户群2:green,客户群3:yellow,客户群4:blue,客户群5:black

客户关系长度L,消费时间间隔R,消费频率F,飞行里程M,折扣系数的平均值C。

横坐标上,总共有五个节点,按顺序对应LRFMC。

对应节点上的客户群的属性值,代表该客户群的该属性的程度。

2.客户价值分析

我们重点关注的是L,F,M,从图中可以看到:

1、客户群4[blue] 的F,M很高,L也不低,可以看做是重要保持的客户;

2、客户群3[yellow] 重要发展客户

3、客户群1[red] 重要挽留客户,原因:入会时间长,但是F,M较低

4、客户群2[green] 一般客户

5、客户群5[black] 低价值客户

重要保持客户:R(最近乘坐航班)低,F(乘坐次数)、C(平均折扣率高,舱位较高)、M(里程数)高。最优先的目标,进行差异化管理,提高满意度。

重要发展客户:R低,C高,F或M较低,潜在价值客户。虽然说,当前价值不高,但是却有很大的发展潜力,促使这类客户在本公司消费和合作伙伴处消费。

重要挽留客户:C、F、M较高,但是较长时间没有乘坐(R)小。增加与这类客户的互动,了解情况,采取一定手段,延长客户生命周期。

一般与低价值客户:C、F、M、L低,R高。他们可能是在公司打折促销时才会乘坐本公司航班。

3.模型应用

会员的升级与保级(积分兑换原理相同)

会员可以分为,钻石,白金,金卡,银卡…

部分客户会因为不了解自身积分情况,错失升级机会,客户和航空公司都会有损失

在会员接近升级前,对高价值客户进行促销活动,刺激他们消费达到标准,双方获利

交叉销售

通过发行联名卡与非航空公司各做,使得企业在其他企业消费过程中获得本公司的积分,增强与本公司联系,提高忠诚度。

管理模式

企业要获得长期的丰厚利润,必须需要大量稳定的、高质量的客户。

维持老客户的成本远远低于新客户,保持优质客户是十分重要的。

精准营销中,也有成本因素,所以按照客户价值排名,进行优先的,特别的营销策略,是维持客户的关键。

4.小结

本文,结合航空公司客户价值案例的分析,重点介绍了数据挖掘算法中K-Means聚类算法的应用。 针对,传统RFM模型的不足,结合案例进行改造,设定了五个指标的LRFMC模型。最后通过聚类的结果,选出客户价值排行,并且制定相应策略

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342

推荐阅读更多精彩内容

  • # -*- coding: utf-8 -*- from __future__ import division i...
    小豆角lch阅读 1,105评论 0 0
  • 最近在写个性化推荐的论文,经常用到Python来处理数据,被pandas和numpy中的数据选取和索引问题绕的比较...
    shuhanrainbow阅读 4,531评论 6 19
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,580评论 18 139
  • 你不必思不必悔 不需包含多少惆怅 人生多坎多桀多痛苦 莫不是一抔黄土一缕青烟 明月皎皎 微风袅袅 水河潺潺 心绪忧...
    喵小玖阅读 376评论 0 0
  • 七夕那天我有点头晕,去看了医生,医生说:“你这个症状要食补,多吃点鸡蛋吧,那种小小的土鸡蛋。” 所以回家的路上我买...
    婉言不劝阅读 1,454评论 2 3