1. 项目背景
电信行业是典型的数据密集型行业,只有正确地分析用户数据,发现更多商机,做出正确的决策,从而更好的向用户提供服务。电信行业的决策,在很大程度上依赖于客户的分类,针对不同类型的客户,实施相应的策略,从而获得客户的满意,征得客户的信任,把握真诚的客户群,最终是的企业自身获益。客户的分类依赖于客户价值的分析,本项目通过对客户价值的详细分析,并利用
CFSFDP 聚类算法,对客户进行类型的划分,可以获知客户价值的大小,客户价值的类型,从而得到客户的分类。
从客户需求出发,了解客户需要什么,他们有怎么样的特征,电信运营商为客户设置不同的优惠套餐,以争取更多的用户:推出不同的优惠套餐,降低客户流失率、提高收入、增加
ARPU 值(average revenue per user 每个用户平均收益),实现精准的市场营销策略定制。
2. 功能组成
基于 CFSFDP 聚类算法的电信客户价值分析的功能主要包括:
3. 数据读取与预处理
custinfo = pd.read_csv(‘custinfo.csv’)
custcall = pd.read_csv(‘custcall.csv’)
# 数据聚合:–对整个DataFrame数值求平均值,删除最后一列【month】
custcall2 = custcall.groupby(custcall[‘Customer_ID’]).mean()
custcall3 = custcall2.drop(‘month’, 1)
# 数据合并
data = pd.merge(custinfo,custcall3,left_on=‘Customer_ID’,right_index=True)
data.index = data[‘Customer_ID’]
data = data.drop(‘Customer_ID’,1)
# 数据探索:(mean,std,min,max,25%,50%,75%)
data.describe()
Columns| Gender| Age| L_O_S| Peak_calls| Peak_mins| OffPeak_calls|
OffPeak_mins| Weekend_calls| Weekend_mins| International_mins| Nat_call_cost
—|—|—|—|—|—|—|—|—|—|—|—
count| 18550.000000| 18550.000000| 18550.000000| 18550.000000| 18550.000000|
18550.000000| 18550.000000| 18550.000000| 18550.000000| 18550.000000|
18550.000000
mean| 0.482102| 31.506253| 33.710032| 39.756397| 118.768764| 17.356514|
51.603952| 2.790836| 8.356949| 28.292598| 2.944807
std| 0.499693| 12.848472| 14.093977| 39.677670| 84.289974| 16.120243|
33.003937| 2.836811| 6.097823| 23.488567| 4.593809
min| 0.000000| 12.000000| 9.533333| 0.000000| 0.000000| 0.000000| 0.000000|
0.000000| 0.000000| 0.001840| 0.000000
25%| 0.000000| 22.000000| 21.333333| 10.333333| 52.600000| 4.666667|
24.562500| 0.666667| 3.600000| 10.920083| 0.000000
50%| 0.000000| 30.000000| 33.666667| 26.833333| 101.100000| 12.333333|
48.350000| 1.833333| 7.316667| 22.397491| 1.000000
75%| 1.000000| 39.000000| 45.866667| 56.333333| 169.300000| 25.833333|
73.800000| 4.000000| 12.200000| 39.357374| 4.333333
max| 1.000000| 82.000000| 58.200000| 287.500000| 483.600000| 105.666667|
191.000000| 20.666667| 33.700000| 169.136422| 33.000000
4. 数据探索式分析
4.1 性别分布情况
fig = plt.figure(figsize=(10, 5))
sns.countplot(data[‘Gender’])
plt.title(‘Gender’)
plt.show()
4.2 Tariff 分布情况
4.3 Handset 分布情况
4.4 其他类别特征密度分布图
5. 特征工程
5.1 类别型的特征进行编码
encoder = LabelEncoder()
encoder = encoder.fit(data[‘Gender’])
data[‘Gender’] = encoder.transform(data[‘Gender’])
encoder = LabelEncoder()
encoder = encoder.fit(data[‘Tariff’])
data[‘Tariff’] = encoder.transform(data[‘Tariff’])
encoder = LabelEncoder()
encoder = encoder.fit(data[‘Handset’])
data[‘Handset’] = encoder.transform(data[‘Handset’])
5.2 数据标准化和数据降维
由于这些数据的特征可能都不在一个数量级,这就很难使用一些聚类算法进行分析,因此,我们需要使用sklearn中有关数据处理的算法MinMaxScaler(),对数据进行标准化,将数据缩放到0~1之间,以便聚类分析。
# 引入第三方库
from sklearn.preprocessing import MinMaxScaler
# 初始化MinMaxScaler()
min_max_model = MinMaxScaler()
# 使用数据进行拟合并转化
data = min_max_model.fit_transform(data)
6. 基于 CFSFDP 算法的电信客户价值聚类
6.1 CFSDP 聚类算法算法原理及实现
聚类分析又称聚类,是把一个数据集合划分为多个集群(cluster)的过程,使得相同集群内的数据之间具有相似性,不同集群的数据之间具有差异性。聚类是数据挖掘、统计分析的主要任务之一,应用于机器学习、模式识别、图像处理、信息检索、生物信息、数据压缩和计算机图像等领域。(From
维基百科)
常用的聚类算法包括:
(1)启发式分割算法:起始确定K个中心点,用距离公式来判断数据点归属,用代价函数(如最小化平方和)评价聚类结果,迭代直至最优,例如:K-Means,K-Medoids。
(2)基于模型的算法:起始随机确定若干个模型中心,用基于概率的方法判断数据点归属,通过迭代的方法找寻适合各个类的模型,例如:Gaussian Mixture
Model。
(3)降维的方法:通过降维,找寻数据间的特征,再完成聚类,例如:Spectral Clustering,Normalised-Cut。
(4)基于密度的方法:定义数据点密度,从少数对象开始拓展得到集群,例如:DBSCAN,CFSFDP。
CFSFDP算法即为Clustering by fast search and find of density peaks,这是由Alex
Rodriguez 和Alessandro
Laio于2014年发表在《Science》期刊的聚类算法。该算法的基本假设有两个,一是聚类中心附近的数据点具有较低的密度,二是数据点与其他密度更大的中心距离较远。
![在这里插入图片描述](https://img-blog.csdnimg.cn/202104261935562.jpg?x-oss-
process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2JhaWR1XzM1MjMxNzc4,size_16,color_FFFFFF,t_70#pic_center)
# 计算任意两点之间的欧氏距离,并存储为矩阵
def caldistance(v):
distance = np.zeros(shape=(len(v), len(v)))
for i in range(len(v)):
for j in range(len(v)):
if i > j:
distance[i][j] = distance[j][i]
elif i < j:
distance[i][j] = np.sqrt(np.sum(np.power(v[i] - v[j], 2)))
return distance
…
# 通过数距离小于dc的点的个数来衡量一个点的密度(离散型)**
def count_density(distance, dc):
density = np.zeros(shape=len(distance))
for index, node in enumerate(distance):
density[index] = len(node[node < dc])
return density
# 通过公式np.sum(np.exp(-(node / dc) ** 2))衡量一个店的密度(连续型)**
#node=dij
def continous_density(distance, dc):
density = np.zeros(shape=len(distance))
for index, node in enumerate(distance):
density[index] = np.sum(np.exp(-(node / dc) ** 2))
return density
# 计算密度大于自身的点中距离自己最近的距离以及该点的直属上级
def node_detal(density, distance):
detal_ls = np.zeros(shape=len(distance))
closest_leader = np.zeros(shape=len(distance), dtype=np.int32)
for index, node in enumerate(distance):
# 点密度大于当前点的点集合(一维数组)
density_larger_than_node = np.squeeze(np.argwhere(density > density[index]))
# 存在密度大于自己的点
if density_larger_than_node.size != 0:
…
return detal_ls, closest_leader
…
# 确定每点的最终分类
def clustering(closest_leader, chose_list):
for i in range(len(closest_leader)):
while closest_leader[i] not in chose_list:
j = closest_leader[i]
closest_leader[i] = closest_leader[j]
new_class = closest_leader[:]
return new_class # new_class[i]表示第i点所属最终分类
6.2 聚类结果可视化
def show_result(new_class, norm_data, chose_list):
colors = [
‘#FF0000’, ‘#FFA500’, ‘#FFFF00’, ‘#00FF00’, ‘#228B22’,
‘#0000FF’, ‘#FF1493’, ‘#EE82EE’, ‘#000000’, ‘#FFA500’,
‘#00FF00’, ‘#006400’, ‘#00FFFF’, ‘#0000FF’, ‘#FFFACD’,
‘#770077’, ‘#008866’, ‘#000088’, ‘#9F88FF’,‘#3A0088’,
‘#660077’, ‘#FF00FF’,‘#0066FF’, ‘#00FF00’, ‘#7744FF’,
‘#33FFDD’, ‘#CC6600’, ‘#886600’, ‘#227700’, ‘#008888’,
‘#FFFF77’, ‘#D1BBFF’
]
# 画最终聚类效果图
leader_color = {}
main_leaders = dict(collections.Counter(new_class)).keys()
for index, i in enumerate(main_leaders):
leader_color[i] = index
plt.figure(num=3, figsize=(15, 15))
for node, class_ in enumerate(new_class):
# 标出每一类的聚类中心点
if node in chose_list:
plt.scatter(x=norm_data[node, 0], y=norm_data[node, 1], marker=‘*’, s=500, c=‘black’,alpha=1)
else:
plt.scatter(x=norm_data[node, 0], y=norm_data[node, 1], c=colors[leader_color[class_]], s=100, marker=‘o’,alpha=1)
plt.title(‘The Result Of Cluster’)
plt.show()
# 画detal图和原始数据图
def show_optionmal(den, det, v):
plt.figure(num=1, figsize=(15, 9))
ax1 = plt.subplot(121)
for i in range(len(v)):
plt.scatter(x=den[i], y=det[i], c=‘k’, marker=‘o’, s=15)
plt.xlabel(‘Density’)
plt.ylabel(‘Detal’)
plt.title(‘Chose Leader’)
plt.sca(ax1)
ax2 = plt.subplot(122)
for j in range(len(v)):
plt.scatter(x=v[j, 0], y=v[j, 1], marker=‘o’, c=‘k’, s=15)
plt.xlabel(‘axis_x’)
plt.ylabel(‘axis_y’)
plt.title(‘Dataset’)
plt.sca(ax2)
plt.show()
项目分享
项目分享:
https://gitee.com/asoonis/feed-neo