自学内容网 自学内容网

机器学习项目实例:如何预测客户是否流失

  一、项目分析        

  1. 项目背景    

        在当前竞争激烈的市场环境中,企业与客户的关系日益复杂且多变。为了更好地了解客户行为模式,预测哪些客户可能流失,哪些客户可能继续留存,本项目旨在通过机器学习,构建客户流失预测模型。这不仅能够帮助企业及时识别潜在流失客户,采取相应的挽留措施,还能提升企业的客户忠诚度和市场竞争力。

  2. 可行性分析    

2.1 重要性

        客户流失对企业而言是一个巨大的挑战,它不仅影响企业的收入和市场份额,还可能对品牌形象和口碑造成负面影响。因此,构建一个客户流失预测模型对于提高企业竞争力和客户满意度至关重要。

2.2 目的

  • 提供数据驱动决策,减少客户流失;
  • 企业提前采取预防措施,提高客户留存率。

2.3 现状痛点

  • 数据收集不全面,缺乏系统性和连贯性;
  • 分析方法简单,难以深入挖掘客户流失的根本原因;
  • 预测模型准确性不高,难以为企业提供可靠的决策支持。

2.4 可行性

  • 数据分析技术
  • 数据可视化技术
  • 数据集成技术
  • 机器学习
    • 输入是什么?
      • ⼤量留存和流失的⽤户历史数据
    • 输出是什么?
      • 先分析这是分类项目还是回归项目?
      • 由于分类问题预测的标签是一个离散型变量,回归问题预测的标签是一个连续型变量;而客户的流失或留存属于离散的2种状态,故该项目为二分类预测项目。
      • 可以使用分类问题相关的模型,如:逻辑回归、KNN、朴素贝叶斯、支持向量机、决策树和集成学习。

  3. 业务场景分析    

3.1 目标客户群体

  • 企业的所有客户

3.2 使用场景

  • 快速识别可能流失的客户,并采取预防措施;
  • 针对不同的客户群体,制定个性化的服务方案,提高客户满意度和忠诚度。

3.3 产品需求

  • 客户基础信息数据的导入功能
  • 现有情况的展示
  • 输入客户的基本信息,预测是否有流失的风险,并能生成报告

3.4 预期产品特性

  • 强大的数据分析和预测能力
  • 界面易用,数据可视化
  • 灵活的报告生成工具
  • 高度的安全性和数据隐私保护

  4. 理论与实践依据    

4.1 理论依据

  • 各类文献、研究报告参考

4.2 MVP技术

  • 前端:Streamlit构建用户界面
  • 后端:Python
  • 机器学习Scikit-learn数据分析、模型训练

  二、数据来源与处理        

  1. 数据收集    

数据来源:《信用卡客户流失数据集》icon-default.png?t=O83Ahttp://idatascience.cn/dataset-detail?table_id=178

  2. 数据预处理    

2.1 特征工程

  • 数据清洗
    • 重复值
    • 缺失值
    • 异常值
    • 无效特征

2.2 向量化及编码

离散型变量的两种编码方法

  • zero-index编码
    • 将类别映射为 0 ~ N-1
    • 不会增加特征维度,但可能引⼊类别⼤⼩关系。
  • one-hot编码
    • 每个类别对应⼀个⼆进制特征。
    • state 0: [1,0,0,0,……,0]

      state 1: [0,1,0,0,……,0]

      state N: [0,0,0,0,……,1]

              一个特征变成N个特征

  • 会增加特征维度,构建稀疏矩阵(大量的0,少数的有用数据),浪费存储和计算资源。

2.3 构建数据集

  • 训练集
  • 验证集&测试集

2.4 预处理

  • 中心化:减去均值,使数据均值为0。
    • ( x - mu )
  • 归一化:将数据压缩到 [ 0, 1 ] 区间。
    • ( x - min ) / ( max - min )
  • 标准化:减均值后除以标准差,目的是得到均值为0,标准差为1的服从标准正态分布的数据。
    • ( x - mu )/ sigma
"""
1. 数据读取
"""
import pandas as pd
data = pd.read_csv(filepath_or_buffer="/Users/csblog/信用卡客户流失数据集.csv")

#打印data的形状,以元组(行数, 列数)的形式给出。以便快速了解数据集的大小
data.shape

#打印data的摘要,用于了解数据集的基本结构和数据类型的分布
data.info()

#返回data的最后3行数据(n=3指定了返回的行数)。
data.tail(n=3)

#从data中随机抽取3行数据。便于快速查看数据集的样本或进行随机抽样分析。
data.sample(n=3)

#注意:虽然data.tail(n=3)和data.sample(n=3)都返回了数据框的几行,
#但它们的目的不同。tail返回的是数据集末尾的几行,而sample返回的是随机选取的几行。

"""
2. 数据清洗
重复 什么叫重复?user_id? 缺失 异常
"""
# 判断是否有重复
data.duplicated(subset=["CLIENTNUM"]).sum()

#删除重复(保留其中一条) 
data.drop_duplicates(subset=["CLIENTNUM"],inplace=True)

data.info()


#用于检查data中每列(或每行,如果你对行操作的话)中缺失值(NaN,即“Not a Number”)的数量
data.isna().sum()


#删除CLIENTNUM列
data.drop(columns="CLIENTNUM",inplace=True)

"""
 3. 数据预处理
        编码问题
        异常问题
        量纲问题
"""
# 判断Attrition_Flag有几个离散状态
data["Attrition_Flag"].unique()

#构建状态字典,enumerate() 很适合在 for 循环中同时获取索引和值。
attrition_dict = {attrition:idx for idx, attrition in enumerate(data["Attrition_Flag"].unique())}


#更新对应的列
data["Attrition_Flag"]=data["Attrition_Flag"].apply(func=lambda ele:attrition_dict[ele])

idx2label = {idx:attrition for attrition,idx in attrition_dict.items()}

"""
3.2, Customer_Age
按位或 |
按位与 &
否定,按位取反 !
"""

#判断有多少个年龄小于0或是大于150岁的异常数据
((data["Customer_Age"] < 0) | (data["Customer_Age"]>150)).sum()

"""
3.3, Gender
"""
# 判断有多少个离散状态
data["Gender"].unique()
#构建状态字典
gender_dict = {gender:idx for idx,gender in enumerate(data["Gender"].unique())}
#更新对应的列
data["Gender"] = data["Gender"].apply(func = lambda ele:gender_dict[ele])

"""
3.5, Education_Level
"""
#判断有多少个离散状态
data["Education_Level"].unique()
#构建状态字典
education_dict = {education:idx for idx,education in enumerate(data["Education_Level"].unique())}
#更新对应列
data["Education_Level"] = data["Education_Level"].apply(func=lambda ele:education_dict[ele])


"""
4,数据拆分
"""
y = data["Attrition_Flag"].to_numpy()
X = data.drop(columns = ["Attrition_Flag"]).to_numpy()

X.shape,y.shape

from sklearn.model_selection import train_test_split
X_train,X_test,y_train,y_test = train_test_split(X,y,test_size=0.2,random_state=0)

X_train.shape
y_train.shape

"""
5, 数据标准化处理
"""
#从训练集中抽取预处理参数mu和sigma
#计算数组X沿着指定轴的均值
#axis=0表示沿着数组的第一个轴(通常是行)进行操作,即计算每一列的平均值。
#对于二维数组(矩阵)来说,axis=0会将所有行的对应元素相加,然后除以行数,得到每一列的均值。
mu = X_train.mean(axis=0)
sigma = X_train.std(axis=0)

#执行标准化操作
X_train = (X_train - mu)/sigma
X_test = (X_test - mu)/sigma

"""
6, 数据保存
    特征编码时的状态字典
    特征的各种异常判断
    标准化处理的参数

"""
import joblib

state_dict = [idx2label, gender_dict, education_dict, marital_dict, income_dict, card_dict, mu, sigma]
data = [X_train, y_train, X_test, y_test]

joblib.dump(value=[state_dict, data], filename="all_data.csblog")

 

  三、选择模型,训练模型        

  1. 各模型的预测结果     

1.1 KNN

1.2 朴素贝叶斯

1.3 决策树

1.4 逻辑回归

1.5 支持向量机

1.6 集成学习

"""
1. 数据加载

"""
import joblib

[state_dict,data]=joblib.load(filename="all_data.csblog")

idx2label, gender_dict, education_dict, marital_dict, income_dict, card_dict, mu, sigma = state_dict
X_train, y_train, X_test, y_test = data

X_train.shape


"""
2. 尝试所有算法
    二分类问题:
    算法:
        KNN
        朴素贝叶斯
        决策树
        逻辑回归
        支持向量机
        集成学习   
"""

"""
2.1 KNN算法
"""

# 从sklearn的neighbors模块中导入KNeighborsClassifier类,用于实现K最近邻算法。
from sklearn.neighbors import KNeighborsClassifier

# 初始化相关参数
best_n_neighbor = 0
best_acc = 0
best_model = None
# 简单遍历,寻找比较好的 N
for n_neighbor in range(3, 31, 1):
# 创建KNN分类器实例
#n_neighbors=5指定了在预测时使用最近的5个邻居
    knn = KNeighborsClassifier(n_neighbors=n_neighbor)
# 使用训练数据训练模型 
    knn.fit(X=X_train, y=y_train)
# 使用训练好的模型对测试集进行预测
    y_pred = knn.predict(X=X_test)
    acc = (y_pred == y_test).mean()
    if acc > best_acc:
        best_n_neighbor = n_neighbor
        best_acc = acc
        best_model = knn
        print(f"找到一个更好的模型: {best_n_neighbor}, {best_acc}")
# 保存模型
joblib.dump(value=[best_n_neighbor, best_acc, best_model], filename="best_knn.csblog")



"""
2.2 朴素贝叶斯
    高斯朴素贝叶斯
    高斯:假定所有的特征都是连续型的
"""
from sklearn.naive_bayes import GaussianNB
gnb = GaussianNB()
gnb.fit(X=X_train, y=y_train)
y_pred = gnb.predict(X=X_test)
acc = (y_pred == y_test).mean()
acc


"""
2.3 决策树
"""
from sklearn.tree import DecisionTreeClassifier
dtc = DecisionTreeClassifier()
dtc.fit(X=X_train, y=y_train)
y_pred = dtc.predict(X=X_test)
acc = (y_pred == y_test).mean()
acc

"""
2.4 逻辑回归
    使⽤Sigmoid函数将线性组合转换为概率
"""


"""
2.5 支持向量机
    
"""

"""
2.6 集成学习
    
"""


"""
3. 推理过程
    从原始数据开始推理  
"""
x = "709967358,48,M,4,Post-Graduate,Single,$80K - $120K,Blue,36,6,2,3,30367,2362,28005,1.708,1671,27,0.929,0.078"

def predict(x):
    """
        推理函数
    """
    import numpy as np
    # print(f"原始输入:{x}")
    x = x.split(",")[1:]
    # print(f"切分之后:{x}")
    temp = []
    # 1, age
    temp.append(float(x[0]))
    # 2, gender
    temp.append(gender_dict[x[1]])
    # 3, 
    temp.append(float(x[2]))
    # 4, 
    temp.append(education_dict[x[3]])

    # 5, 
    temp.append(marital_dict[x[4]])
    # 6,
    temp.append(income_dict[x[5]])

    # 7, 
    temp.append(card_dict[x[6]])

    # 8 - 19
    temp.extend([float(ele) for ele in x[7: ]])
    
    # print(f"编码之后:{temp}")

    # 标准化之后
    x = np.array(temp)
    x = (x - mu) / sigma
    # print(f"标准化之后:{x}")

    # 模型推理

    y_pred = dtc.predict(X=[x])
    # print(f"推理结果:{y_pred}")

    # 结果解析
    final_result = idx2label[y_pred[0]]
    # print(f"最终结果:{final_result}")
    return final_result   

  四、模型评估与验证        

  1. 不同分类算法的优缺点对比    

图表:

评估指标

  • 训练耗时(*)
  • 推理耗时(***)
  • 准确率情况(***)

  2. 改进与优化    

  五、保存和部署模型        

  1. 保存和部署模型    

  2. Streamlit效果演示    


原文地址:https://blog.csdn.net/CSBLOG/article/details/142876174

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!