IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Python知识库 -> 互联网服务客户流失分析(个人练习+源代码) -> 正文阅读

[Python知识库]互联网服务客户流失分析(个人练习+源代码)

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns

plt.rcParams['font.family'] = ['SimHei']    # 显示中文,解决图中无法显示中文的问题
plt.rcParams['axes.unicode_minus']=False
# 导入数据
data = pd.read_csv('internet_service_churn.csv')
# 查看数据大小
data.shape
(72274, 11)
# 查看前五行
data.head()
idis_tv_subscriberis_movie_package_subscribersubscription_agebill_avgreamining_contractservice_failure_countdownload_avgupload_avgdownload_over_limitchurn
0151011.95250.1408.42.300
118008.220NaN00.00.001
223108.91160.00013.70.901
327006.8721NaN10.00.001
434006.390NaN00.00.001
# 查看基本信息
data.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 72274 entries, 0 to 72273
Data columns (total 11 columns):
 #   Column                       Non-Null Count  Dtype  
---  ------                       --------------  -----  
 0   id                           72274 non-null  int64  
 1   is_tv_subscriber             72274 non-null  int64  
 2   is_movie_package_subscriber  72274 non-null  int64  
 3   subscription_age             72274 non-null  float64
 4   bill_avg                     72274 non-null  int64  
 5   reamining_contract           50702 non-null  float64
 6   service_failure_count        72274 non-null  int64  
 7   download_avg                 71893 non-null  float64
 8   upload_avg                   71893 non-null  float64
 9   download_over_limit          72274 non-null  int64  
 10  churn                        72274 non-null  int64  
dtypes: float64(4), int64(7)
memory usage: 6.1 MB
# 为特征重命名
data.columns = ['用户标识', '是否为电视订阅用户', '是否为电影包订阅用户', '客户年限', '平均账单金额',
               '合同剩余年限', '投诉次数', '平均下载量', '平均上传量', '下载超过限制', '是否流失']

字段解释:

用户标识:唯一的用户id

是否为电视订阅用户:用户是否有电视订阅,是为1,否则为0

是否为电影包订阅用户:用户是否有电影套餐,是为1,否则为0

客户年限:客户使用我们的服务多少年

平均账单金额:过去3个月账单平均消费

合同剩余年限:客户合同还剩多少年?如果为空,代表客户没有合同。

投诉次数:过去3个月客户因服务失败,而呼叫服务中心的次数

平均下载量:过去3个月的互联网下载情况(GB)

平均上传量:过去3个月平均上传量(GB)

下载超过限制:大多数客户都有下载限制。如果他们达到了这个极限,他们必须为此付费

是否流失:用户是否取消了服务

# 查看缺失值
data.isnull().sum()
用户标识              0
是否为电视订阅用户         0
是否为电影包订阅用户        0
客户年限              0
平均账单金额            0
合同剩余年限        21572
投诉次数              0
平均下载量           381
平均上传量           381
下载超过限制            0
是否流失              0
dtype: int64
# 这里使用0进行填充,这里认为空值为没有合同,因此将合同剩余年限设置为0
# 下载量和上传量在0处分布最多,同样使用0进行填充
data = data.fillna(0)
# 观察数据是否有重复值
data.duplicated().sum()
0
# 对分类型变量和连续型变量进行区分
col_c = ['是否为电视订阅用户', '是否为电影包订阅用户', '投诉次数', '下载超过限制', '是否流失']
col_n = ['客户年限', '平均账单金额', '合同剩余年限', '平均下载量', '平均上传量']
# 查看分类型特征分布情况
for i in col_c:
    plt.figure(figsize=(6,4))
    sns.countplot(x=i, data=data)

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

# 查看连续型特征分布情况
fig, ax = plt.subplots(3,2,figsize=(10,8))
axes = ax.flatten()
for i in range(len(col_n)):
    axes[i].hist(x=data[col_n[i]], bins=20)
    axes[i].set_title(col_n[i])
plt.tight_layout()

在这里插入图片描述

# 用seaborn绘图
for i in col_n:
    plt.figure(figsize=(12,6))
    sns.distplot(data[i], kde=True)

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

# 描述性统计
data.describe()
用户标识是否为电视订阅用户是否为电影包订阅用户客户年限平均账单金额合同剩余年限投诉次数平均下载量平均上传量下载超过限制是否流失
count7.227400e+0472274.00000072274.00000072274.00000072274.00000072274.00000072274.00000072274.00000072274.00000072274.00000072274.000000
mean8.463182e+050.8152590.3346292.45005118.9424830.5023190.27423443.4595954.1699770.2076130.554141
std4.891022e+050.3880900.4718642.03499013.2153860.6695240.81662163.3177069.7976850.9971230.497064
min1.500000e+010.0000000.000000-0.0200000.0000000.0000000.0000000.0000000.0000000.0000000.000000
25%4.222165e+051.0000000.0000000.93000013.0000000.0000000.0000006.4000000.5000000.0000000.000000
50%8.477840e+051.0000000.0000001.98000019.0000000.0000000.00000027.5000002.1000000.0000001.000000
75%1.269562e+061.0000001.0000003.30000022.0000001.0400000.00000060.2000004.8000000.0000001.000000
max1.689744e+061.0000001.00000012.800000406.0000002.92000019.0000004415.200000453.3000007.0000001.000000
# 作热力图探究特征相关性
# 可以看出下载超过限制次数和投诉次数与流失呈正相关性,订阅、剩余年限、上传下载数量等于流失呈负相关,这符合我们的认知
corr = data.corr()
plt.figure(figsize=(20, 10))
sns.heatmap(corr, annot=True, cmap='coolwarm')
<AxesSubplot:>

在这里插入图片描述

# 提取自变量和因变量
X = data[['是否为电视订阅用户', '是否为电影包订阅用户', '投诉次数', '下载超过限制', '客户年限', 
         '平均账单金额', '合同剩余年限', '平均下载量', '平均上传量']]
y = data[['是否流失']]
from sklearn.preprocessing import StandardScaler
# 对数据进行标准化处理
ss = StandardScaler()
X = ss.fit_transform(X)
y = np.ravel(y)
# 切分训练集和测试集
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=42)
# 导入KNN模型
from sklearn.neighbors import KNeighborsClassifier
model = KNeighborsClassifier() # 实例化
model.fit(X_train,y_train) # 拟合
model_pre = model.predict(X_test) # 预测测试集结果
# 导入accuracy库
from sklearn.metrics import accuracy_score
print('准确率为{}'.format(accuracy_score(y_test, model_pre)))
准确率为0.9076318556643976
con = pd.concat([pd.pivot_table(data, index='是否流失', values='用户标识', aggfunc='count'), 
                 pd.pivot_table(data, index='是否流失', aggfunc='mean').drop(['用户标识'], axis=1)], axis=1).reset_index()
con
是否流失用户标识下载超过限制合同剩余年限客户年限平均上传量平均下载量平均账单金额投诉次数是否为电影包订阅用户是否为电视订阅用户
00322240.0316221.0110772.7278285.91281764.11756519.2527310.2545930.4962140.956989
11400500.3492130.0929762.2265542.76769826.83831218.6928590.2900370.2046190.701223
# 查看流失用户和非流失用户的不同特征
col = ['用户标识', '下载超过限制', '合同剩余年限', '客户年限', '平均上传量', '平均下载量', '平均账单金额', '投诉次数', '是否为电影包订阅用户', '是否为电视订阅用户']
fig, ax = plt.subplots(3, 3, figsize=(18,15))
axes = ax.flatten()
for i in range(len(col) - 1):
    axes[i].bar(x='是否流失', height=col[i], data=con, width=0.3, color=['pink', 'purple'], edgecolor='black', tick_label=[0, 1])
    axes[i].set_title(col[i])
plt.tight_layout()

在这里插入图片描述

# 获取流失用户数据
churn = data[data['是否流失']==1].reset_index(drop=True)
churn.head()
用户标识是否为电视订阅用户是否为电影包订阅用户客户年限平均账单金额合同剩余年限投诉次数平均下载量平均上传量下载超过限制是否流失
018008.2200.000.00.001
123108.91160.0013.70.901
227006.87210.010.00.001
334006.3900.000.00.001
471008.96180.0021.32.001
churn.describe()
用户标识是否为电视订阅用户是否为电影包订阅用户客户年限平均账单金额合同剩余年限投诉次数平均下载量平均上传量下载超过限制是否流失
count4.005000e+0440050.00000040050.00000040050.00000040050.00000040050.00000040050.00000040050.00000040050.00000040050.00000040050.0
mean6.483943e+050.7012230.2046192.22655418.6928590.0929760.29003726.8383122.7676980.3492131.0
std4.322926e+050.4577270.4034281.70943813.0737940.3391110.86513446.1371977.9322451.2905450.0
min1.800000e+010.0000000.000000-0.0200000.0000000.0000000.0000000.0000000.0000000.0000001.0
25%2.863745e+050.0000000.0000000.98000013.0000000.0000000.0000000.0000000.0000000.0000001.0
50%5.907300e+051.0000000.0000001.97000020.0000000.0000000.00000011.9000000.9000000.0000001.0
75%9.498655e+051.0000000.0000002.94000023.0000000.0000000.00000036.7000002.9000000.0000001.0
max1.689744e+061.0000001.00000012.800000278.0000002.31000019.0000001706.200000327.2000007.0000001.0
# C(合同状态) = 合同剩余年限	
# M(消费金额) = 平均下载量 + 平均上传量 + 平均账单金额
# A(活跃度) = 是否为电视订阅用户 + 是否为电影包订阅用户
# S(满意度) = 投诉次数 + 下载超过限制
# L(服务时长) = 客户年限
# 进行特征组合

clf = {
    'C':churn['合同剩余年限'],
    'M':churn['平均下载量'] + churn['平均上传量'] + churn['平均账单金额'],
    'A':churn['是否为电视订阅用户'] + churn['是否为电影包订阅用户'],
    'S':churn['投诉次数'] + churn['下载超过限制'],
    'L':churn['客户年限']
}

data_clf = pd.DataFrame(clf)
data_clf
CMASL
00.000.0008.22
10.0030.6108.91
20.0021.0016.87
30.000.0006.39
40.0041.3008.96
..................
400451.250.0200.09
400461.631.8100.06
400472.191.7100.02
400480.720.0000.01
400490.820.0200.01

40050 rows × 5 columns

# 对新数据进行标准化
data_clf = ss.fit_transform(data_clf)
data_clf = pd.DataFrame(data_clf, columns=['C', 'M', 'A', 'S', 'L'])
data_clf
CMASL
0-0.274177-0.835332-1.288250-0.4110603.506135
1-0.274177-0.3061030.133906-0.4110603.909781
2-0.274177-0.472136-1.2882500.2319742.716392
3-0.274177-0.835332-1.288250-0.4110602.435594
4-0.274177-0.121046-1.288250-0.4110603.939031
..................
400453.411973-0.8353321.556063-0.411060-1.249873
400464.532562-0.8042010.133906-0.411060-1.267422
400476.183957-0.8059310.133906-0.411060-1.290822
400481.849045-0.835332-1.288250-0.411060-1.296672
400492.143937-0.8353321.556063-0.411060-1.296672

40050 rows × 5 columns

# 导入聚类相关库
from sklearn.cluster import KMeans
from sklearn.metrics import silhouette_score
# 通过学习曲线选择一个合适簇数
scores = []
inertias = []

for i in range(2,10):
    kmeans = KMeans(n_clusters=i, random_state=42)
    kmeans.fit(data_clf)
    score = silhouette_score(data_clf, kmeans.labels_, sample_size=180)
    scores.append(score)
    inertias.append(kmeans.inertia_)

plt.figure(figsize=(10, 8))
plt.plot(range(2,10), scores)
plt.xlabel('K')
plt.ylabel('score')
plt.title('Performance of K-means')

plt.figure(figsize=(10, 8))
plt.plot(range(2,10), inertias)
plt.xlabel('K')
plt.ylabel('inertia')
plt.title('Inertia of K-means')
plt.show()

在这里插入图片描述

在这里插入图片描述

# 设定簇数为6,并获取标签以及簇心
model = KMeans(n_clusters=6, random_state=42)
model.fit(data_clf)

centers = model.cluster_centers_
labels = model.labels_
#将六个簇心转换成DataFrame
centers = pd.DataFrame(centers, columns=['C', 'M', 'A', 'S', 'L'])
centers
CMASL
0-0.2188280.0755370.313688-0.2279041.782962
1-0.237469-0.0944780.480242-0.257323-0.375447
23.7536650.2382780.508351-0.154067-0.280738
3-0.255118-0.252971-1.288250-0.220537-0.298799
4-0.203795-0.555980-0.0370283.2140760.172612
5-0.1146583.3007280.133906-0.074866-0.072260
# 将用户类型和人数转换成DataFrame类型
labels = pd.DataFrame(labels, columns=['用户类型'])
labels = pd.DataFrame(labels.value_counts()).sort_index().reset_index()
labels = labels.rename(columns={0:'人数'})
# 合并数据
final = pd.concat([labels, centers], axis=1)
final['用户类型'] = ['class_1','class_2','class_3','class_4','class_5','class_6']
final
用户类型人数CMASL
0class_15659-0.2188280.0755370.313688-0.2279041.782962
1class_218663-0.237469-0.0944780.480242-0.257323-0.375447
2class_323323.7536650.2382780.508351-0.154067-0.280738
3class_49322-0.255118-0.252971-1.288250-0.220537-0.298799
4class_52679-0.203795-0.555980-0.0370283.2140760.172612
5class-61395-0.1146583.3007280.133906-0.074866-0.072260
# 绘制环形图
plt.figure(figsize=(8, 8))
plt.pie(final['人数'], wedgeprops={'width':0.3}, startangle=90, labels=final['用户类型'])
plt.show()

在这里插入图片描述

# 绘制用户类型和CMASL的关系热力图
plt.figure(figsize=(15,6))
sns.heatmap(data=centers, xticklabels=centers.columns, yticklabels = final["用户类型"], annot=True, cmap='coolwarm')
<AxesSubplot:>

在这里插入图片描述

# 将数据转换成字典结构
results = centers.to_dict('records')
# 将极坐标根据数据长度进行等分
data_length = len(results[0])
angles = np.linspace(0, 2*np.pi, data_length, endpoint=False)
labels = [key for key in results[0].keys()]
score = [[v for v in result.values()] for result in results]
# 使雷达图数据封闭
class_all = []
for i in range(6):
    class_0 = np.concatenate((score[i], [score[i][0]]))
    class_all.append(class_0)

angles = np.concatenate((angles, [angles[0]]))
labels = np.concatenate((labels, [labels[0]]))
# 设置图形的大小
fig = plt.figure(figsize=(8, 6), dpi=100)
# 新建一个子图
ax = plt.subplot(111, polar=True)
# 绘制雷达图
for i in range(6):
    ax.plot(angles, class_all[i])
    
# 设置雷达图中每一项的标签显示
ax.set_thetagrids(angles*180/np.pi, labels)

# 设置雷达图的0度起始位置
ax.set_theta_zero_location('N')

# 设置雷达图的坐标值显示角度,相对于起始角度的偏移量
ax.set_rlabel_position(270)

ax.set_title('各类型用户特征')
plt.legend(['class_1','class_2','class_3','class_4','class_5','class_6'], loc='best')
plt.show()

在这里插入图片描述

计算公式:

C(合同状态) = 合同剩余年限
M(消费金额) = 平均下载量 + 平均上传量 + 平均账单金额
A(活跃度) = 是否为电视订阅用户 + 是否为电影包订阅用户
S(满意度) = 投诉次数 + 下载超过限制
L(服务时长) = 客户年限

聚类分析&策略建议:

(1)class_1:
    · 在“L”维度明显很高,其他4个维度表现一般
    · 表明这类流失客户是服务年限较长的老客户
    · 一般来说,丢失一个老客户付出的成本是很高的,建议针对这些老客户做一些抽样回访和调研,或许他们能提供很多用户视角的有效建议
(2)class_2:
    · 各个维度不是特别突出,相对来说“A”维度会较高一些
    · 表明他们订阅了电视或者电影套餐,但是没有表现出其他的特征
    · 这类客户虽然特征不明显,但是占比权重最大,属于自然流失群体。
(3)class_3:
    · 在“C”维度表现突出,在“S”和“L”维度相对较低
    · 从相关系数上看,订阅合同是避免流失的最重要因素,而这类客户很多都是已经签署了contract的客户,他们的消费水平、活跃度、满意度也比较高,客户年限上表现得较为年轻,表明他们虽然人数不多,但是属于潜力客户。
    · 建议将这类客户标记为“种子用户”,对他们做好重点维护
(4)class_4:
    · 这类客户人数占比较大,在“A”维度明显短缺
    · 表明这类客户属于没有或很少订阅过电视或者电影套餐服务的群体
    · 建议对这类客户增加订阅服务的次数,或者推送一些订阅服务指南之类的内容,打开他们使用产品的基本操作。
(5)class_5:
    · 在“S”维度表现突出,在“M”维度明显短缺
    · 表明这类客户属于的满意度较低,且不爱消费的客户
    · 可能这些客户不喜欢这款产品,他们产出的消费价值较低,在流失客户中占比也较低,建议可以战略性放弃。
(6)class_6:
    · 在“M”维度表现突出
    · 表明这类客户属于具有明显消费能力,平时下载和上传需求较大的客户群体
    · 建议加强对这类客户的推荐系统配置,例如更精准地判断他们的喜好,更高频率地推送相关内容,满足他们的大量需求

  Python知识库 最新文章
Python中String模块
【Python】 14-CVS文件操作
python的panda库读写文件
使用Nordic的nrf52840实现蓝牙DFU过程
【Python学习记录】numpy数组用法整理
Python学习笔记
python字符串和列表
python如何从txt文件中解析出有效的数据
Python编程从入门到实践自学/3.1-3.2
python变量
上一篇文章      下一篇文章      查看所有文章
加:2022-01-30 18:53:50  更:2022-01-30 18:55:02 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/16 1:26:44-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码