程序员在旅途

用这生命中的每一秒,给自己一个不后悔的未来!

0%

利用Python分析航空公司客户价值

一、背景介绍

  随着社会生活中数据量的急剧增多,如何从这些海量的数据中提取与发掘出对我们决策有用的信息成为当前亟待解决的题,因此,数据分析与挖掘技术在这些年得到了广泛的发展,也受到了足够的重视。面对不同领域的数据,不同的任务目标,我们在进行数据分析时也会选择不同的模型来进行建模,从而发现数据中的特征,提取其中的价值。常见的数据挖掘模型有:分类与预测、聚类分析、关联规则、时序模式、离群点检测等。这些模型,在我们的生活中已经有了广泛的应用。例如航空公司的客户价值分析,就是对用户数据进行聚类分析,发掘出不同价值群的用户,然后有针对性的制定相应的营销手段,实现精准化运营,以期获取最大的用户转化率。

本篇博文的实例来源于《Python数据分析与挖掘实践》(第二版)中的第七章。实现的主要目标是:
  1,借助航空公司客户数据,对客户进行分类。
  2,对不同客户类别进行特征分析,比较不同类别的客户价值。
  3,针对不同价值的客户类别制定相应的营销策略,为其提供个性化服务。

二、分析步骤与流程

  此案例的总体流程图如下所示。简单来说就是:因为最开始只是要构建模型,所以不需要使用航空公司的全部客户数据,只需要先从业务系统中抽取某一时段的客户数据作为训练即可,然后对数据从宏观上进行分析,之后对数据进行处理,使之能够达到建模的要求,最后选择合适的聚类算法建模并且对结果进行反馈。
分析流程图

2.1、建模数据的获取:

   这个可以从公司的业务系统选择性抽取,例如抽取最近两年的数据。数据的属性说明如下图所示:
属性说明图

2.2、数据的宏观性探索分析:

  2.2.1、描述性统计分析 - 查看属性字段的缺失值、平均值、最大值、最小值等情况,从宏观层面上了解数据。

1
2
3
4
5
6
7
8
9
10
11
12
import pandas as pd

datafile = r'C:\Users\itour\Desktop\air_customer_data.csv'
data = pd.read_csv(datafile, encoding='utf-8')

explore = data.describe(percentiles=[], include='all').T # 使用统计函数对数据进行统计分析
explore['null'] = len(data) - explore['count'] # 计算空值数
# describe有很多统计子项,这里就取我们要用到的即可
explore = explore[['null', 'mean', 'max', 'min']]
explore.columns = ['空值记录数', '最大值', '最小值', '平均值']

print(explore)

描述性统计分析图
  通过上图可以看出有一些记录含有空值,这样的数据对建模可能会有影响,因此,在后面的数据预处理环节,要把这些空值删掉。
  2.2.2、数据的分布分析 - 寻找客户信息的分布规律,例如入会时间分布、年龄分布、性别分布、会员等级分布等等。
  1)入会时间分布图展示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import pandas as pd
from datetime import datetime
import matplotlib.pyplot as plt

datafile = r'C:\Users\itour\Desktop\air_customer_data.csv'
data = pd.read_csv(datafile, encoding='utf-8')

ffp = data['FFP_DATE'].apply(lambda x: datetime.strptime(x, '%Y/%m/%d'))
ffp_year = ffp.map(lambda x: x.year)

plt.rcParams['font.sans-serif'] = 'SimHei'
plt.rcParams['axes.unicode_minus'] = False
# 绘制各年份会员入会人数直方图
plt.hist(ffp_year, bins='auto', color='green')
plt.xlabel('年份')
plt.ylabel('入会人数')
plt.title('各年份会员入会人数')

plt.show()

入会时间分布图
  2)会员性别比例分布图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import matplotlib.pyplot as plt

datafile = r'C:\Users\itour\Desktop\air_customer_data.csv'
data = pd.read_csv(datafile, encoding='utf-8')

# 获取会员中不同的性别人数
male = pd.value_counts(data['GENDER'])['男']
female = pd.value_counts(data['GENDER'])['女']

# 绘制会员分布饼状图
plt.rcParams['font.sans-serif'] = 'SimHei'
plt.rcParams['axes.unicode_minus'] = False

plt.pie([male, female], labels=['男', '女'], colors=['lightskyblue', 'green'], autopct='%1.1f%%')
plt.title('会员性别比例')
plt.show()

会员性别比例分布图
  3)会员年龄分布箱型图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
 import pandas as pd
from datetime import datetime
import matplotlib.pyplot as plt

datafile = r'C:\Users\itour\Desktop\air_customer_data.csv'
data = pd.read_csv(datafile, encoding='utf-8')

# 提取会员的年龄
age = data['AGE'].dropna()
age = age.astype('int64')

# 绘制会员年龄分布箱型图
plt.rcParams['font.sans-serif'] = 'SimHei'
plt.rcParams['axes.unicode_minus'] = False

plt.boxplot(age, patch_artist=True, labels=['会员年龄'], boxprops={'facecolor': 'lightblue'})
plt.title('会员年龄分布箱型图')
plt.grid(axis='y')
plt.show()

会员年龄分布箱型图
  2.2.3、数据属性之间的相关性分析 - 这对特征的选择来说非常有用,通过分析属性之间的关联性,可以确定选择哪些属性作为特征值,哪些则是可以忽略的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import pandas as pd
from datetime import datetime

datafile = r'C:\Users\itour\Desktop\air_customer_data.csv'
data = pd.read_csv(datafile, encoding='utf-8')

data_corr = data[['FFP_TIER', 'FLIGHT_COUNT', 'LAST_TO_END', 'SEG_KM_SUM', 'EXCHANGE_COUNT', 'Points_Sum']]
age_1 = data['AGE'].fillna(0)
data_corr['AGE'] = age_1.astype('int64')

ffp = data['FFP_DATE'].apply(lambda x: datetime.strptime(x, '%Y/%m/%d'))
ffp_year = ffp.map(lambda x: x.year)
data_corr['ffp_year'] = ffp_year

# 计算相关性矩阵
dt_corr = data_corr.corr(method='pearson')
print(dt_corr)

数据属性之间的相关性分析
  从上面的图可以看出,有些属性的相关性较强,有些则较弱。例如 ffp_year与FFP_TIER的相关性就弱,已经是负相关了。而FLIGHT与FFP_TIER的相关性就稍微强一些。属性之间的相关性关系,也是在做特征降维的一个重要参考量,有时候特征较多会严重增加建模的时间,为了提高效率,需要对特征进行降维,构建有代表性的特征进行建模。

2.3、数据预处理:

  通过前面的宏观分析我们也看到,有一些记录是空值,还有一些值出现了明显的错误,而且,在我们后面要构建的LRFMC模型中,这三个特征并不能直接从属性中抽取,而是要根据规则重新计算得到,因此,需要对这些从业务系统中抽取的数据做预处理,使之能够适合建模的需要。数据预处理主要包括数据清洗、属性规约、数据变换等步骤。
  2.3.1、数据清洗  - 删除异常值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import pandas as pd
from datetime import datetime

datafile = r'C:\Users\itour\Desktop\air_customer_data.csv'

clean_datafile = r'C:\Users\itour\Desktop\air_customer_data_clean.csv'

data = pd.read_csv(datafile, encoding='utf-8')

print('原始数据的数据大小:', data.shape)

# 去除票价为空的票价
airline_notnull = data.loc[data['SUM_YR_1'].notnull() & data['SUM_YR_2'].notnull(), :]
print(airline_notnull.shape)

# 只保留票价非0的,或者平均折扣率不为0且总飞行公里数大于0的记录
index1 = airline_notnull['SUM_YR_1'] != 0
index2 = airline_notnull['SUM_YR_2'] != 0
index3 = (airline_notnull['SEG_KM_SUM'] > 0) & (airline_notnull['avg_discount'] != 0)
index4 = airline_notnull['AGE'] > 0
clean_data = airline_notnull[(index1 | index2) & index3 & ~index4]
print(clean_data.shape)
# 保存清洗后的文件
clean_data.to_csv(clean_datafile)

  2.3.2、属性规约 - 选取参与建模的属性
  属性规约的目的就是从众多的属性中选取需要参与建模的、能够反应数据整体特征的属性,删除不相关、弱相关、或者冗余的属性 ,从而提高建模效率。在属性特征选择过程中,可以根据上面步骤的相关性分析,大致了解属性的相关性,然后推导出参与建模的属性。在客户价值识别方面,应用最广泛的模型就是RFM模型,其中,R(Recency)代表指的是最近一次消费时间与截止时间的间隔,F(Frequency)指客户某段时间内所消费的次数,M(Monetary)指客户在某段时间内所消费的金额。在RFM模型中,(R,F,M)是计算客户价值的最重要的特征。在航空公司客户价值领域,常用的是LRFMC模型,需要在上述模型的基础上再加两个特征,LRFMC模型的属性意义如下图:
参与建模的属性
  根据LRFMC模型,需要选择的属性有:FFP_DATE,LOAD_TIME,FLIGHT_COUNT,AVG_DISCOUNT,SEG_KM_SUM,LAST_TO_END。从数据集中选取需要的属性,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import pandas as pd
from datetime import datetime

clean_datafile = r'C:\Users\itour\Desktop\air_customer_data_clean.csv'

guiyue_datafile = r'C:\Users\itour\Desktop\air_customer_data_guiyue.csv'

clean_data = pd.read_csv(clean_datafile, encoding='utf-8')

# 选取需要的属性
air_selection = clean_data[['FFP_DATE', 'LOAD_TIME', 'LAST_TO_END', 'FLIGHT_COUNT', 'SEG_KM_SUM', 'avg_discount']]

print(air_selection.head())

# 保存规约后的数据
air_selection.to_csv(guiyue_datafile)

选择的属性
  2.3.3、数据变换 - 构建建模特征值,进行数据标准化
  在LRFMC模型中,这其中的特征值需要经过规约后的属性通过变换得到,得到这些特征值之后,往往还需要对数据集进行标准化处理,为什么要进行标准化呢?因为不同属性的值通常具有不同的计量单位和数量级。当各指标间的水平相差很大时,如果直接用原始指标值进行分析,就会突出数值较高的指标在综合分析中的作用,相对削弱数值水平较低指标的作用。因此,为了保证结果的可靠性,需要对原始指标数据进行标准化处理。做法通常有:将数据按比例缩放,使之落入一个小的特定区间。去除数据的单位限制,将其转化为无单位限制的纯数值,便于不同单位或量级的指标能够进行比较和加权处理。
  数据变换代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import pandas as pd
import numpy as np
from sklearn.preprocessing import StandardScaler

guiyue_datafile = r'C:\Users\itour\Desktop\air_customer_data_guiyue.csv'
stand_datafile = r'C:\Users\itour\Desktop\air_customer_data_std.npz'

guiyue_data = pd.read_csv(guiyue_datafile, encoding='utf-8')

# 特征构造,并将时间类型转化为int类型
L = pd.to_datetime(guiyue_data['LOAD_TIME']) - pd.to_datetime(guiyue_data['FFP_DATE'])
L = (L.astype('str').str.split().str[0]).astype('int') / 30

air_feature = pd.concat([L, guiyue_data.iloc[:, 3:]], axis=1)
print('构建的 LRFMC 模型属性的前5个数据为:\n', air_feature.head())

# 数据标准化
std_data = StandardScaler().fit_transform(air_feature)
np.savez(stand_datafile, std_data)

print('标准化后 LRFMC 的 前5个属性数据为:\n', std_data[:5, :])

构建建模特征值-数据

2.4、模型构建:

  客户的价值模型构建主要有两个部分组成:第一部分,根据之前归纳出的5个特征,对客户进行聚类分群;第二部分,对每个群的客户进行特征分析,探索其中的客户价值规律,并对各个客户群进行排名。
  2.4.1、聚类分群

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import pandas as pd
import numpy as np
from sklearn.cluster import KMeans

guiyue_datafile = r'C:\Users\itour\Desktop\air_customer_data_guiyue.csv'
stand_datafile = r'C:\Users\itour\Desktop\air_customer_data_std.npz'

# 读取标准化之后的数据
std_data = np.load(stand_datafile)['arr_0']

k = 5 # 确定聚类中心数,这里选择5,也就是分为5个群。这个值的确定,是有一定的要求的,这里不做描述

# 模型训练
kmeans_model = KMeans(n_clusters=k, n_jobs=4, random_state=123)
fit_kmeans = kmeans_model.fit(std_data)

# 查看聚类结果
kmeans_cc = kmeans_model.cluster_centers_ # 聚类中心
print('各聚类中心为: \n', kmeans_cc)

kmeans_label = kmeans_model.labels_ # 样本的类别标签

r = pd.Series(kmeans_label).value_counts() # 统计不同类别样本的数目
print('每个类别的数目为:\n', r)

# 输出聚类分群的结果
cluster_center = pd.DataFrame(kmeans_cc, columns=['ZL', 'ZR', 'ZF', 'ZM', 'ZC'])

cluster_center['聚类个数'] = r

cluster_center.index = pd.DataFrame(kmeans_label).drop_duplicates().iloc[:, 0]

print('聚类结果如下表所示:\n', cluster_center)

聚类分群
  2.4.2、客户价值分析
  针对聚类的结果进行特征分析,绘制客户分群雷达图,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
import pandas as pd
import numpy as np
from sklearn.cluster import KMeans
import matplotlib.pyplot as plt

guiyue_datafile = r'C:\Users\itour\Desktop\air_customer_data_guiyue.csv'
stand_datafile = r'C:\Users\itour\Desktop\air_customer_data_std.npz'

# 读取标准化之后的数据
std_data = np.load(stand_datafile)['arr_0']

k = 5 # 确定聚类中心数,这里选择5,也就是分为5个群。这个值的确定,是有一定的要求的,这里不做描述

# 模型训练
kmeans_model = KMeans(n_clusters=k, n_jobs=4, random_state=123)
fit_kmeans = kmeans_model.fit(std_data)

# 查看聚类结果
kmeans_cc = kmeans_model.cluster_centers_ # 聚类中心

kmeans_label = kmeans_model.labels_ # 样本的类别标签

# 输出聚类分群的结果
labels = ['ZL', 'ZR', 'ZF', 'ZM', 'ZC']

cluster_center = pd.DataFrame(kmeans_cc, columns=labels)

legen = ['客户群' + str(i + 1) for i in cluster_center.index] # 客户群命名

lstype = ['-', '--', (0, (3, 5, 1, 5, 1, 5)), ':', '-.']

kinds = list(cluster_center.iloc[:, 0])

cluster_center = pd.concat([cluster_center, cluster_center[['ZL']]], axis=1)

centers = np.array(cluster_center.iloc[:, 0:])

# 分割圆周长,让其闭合
n = len(labels)
angle = np.linspace(0, 2 * np.pi, n, endpoint=False)
angle = np.concatenate((angle, [angle[0]]))

# 绘制雷达图
fig = plt.figure(figsize=(8, 6))
ax = fig.add_subplot(111, polar=True) # 以极坐标的形式绘制图形
# 处理中文显示问题
plt.rcParams['font.sans-serif'] = 'SimHei'
plt.rcParams['axes.unicode_minus'] = False # 正常显示负号

# 画线
for i in range(len(kinds)):
ax.plot(angle, centers[i], linestyle=lstype[i], linewidth=2, label=kinds[i])
# 添加属性标签
ax.set_thetagrids(angle * 180 / np.pi, labels)

plt.title('客户特征分析雷达图')
plt.legend(legen)
plt.show()

各个客户群的雷达图
  通过分析各个客户群的雷达图,可以看到不同类的客户偏好还是有一些差别的,我们可以根据这些差别制定符合客户群的营销手段和策略。

三、总结

  这篇博文的示例以航空公司客户价值分析为基础,介绍了原始数据的宏观性分析、数据预处理、数据建模的一整套流程,涉及了数据分析的主要过程。因此,还是非常有借鉴意义的。通过这个案例,可以很好的够掌握建模过程中的基本方法,以及Python这种语言的基本用法。
源码下载(亲,如果下载源码,并且感觉博文及整理好的源码对你有价值,不忘打赏哦QAQ)