第一章:机器学习基本概念(附代码)
第二章:KNN算法:从思想到实现(附代码)
第三章:决策树算法:从思想到实现(附代码)
第四章:机器学习简单案例:如何预测客户是否流失(附代码)
第五章:理解数据标准化处理
第六章:线性模型:从原理到实践
第七章:KMeans 聚类算法:从理论到实践(附代码)
第八章:搞懂线性回归与梯度下降原理(附代码)
第九章:深度学习框架PyTorch
第十章:逻辑回归:从基础到实践(附代码)
第十一章:集成学习(一):从理论到实战(附代码)
第十二章:集成学习(二):从理论到实战(附代码)
第十三章:机器学习算法大比武(附代码)
第十四章:理解并解决欠拟合与过拟合
第十五章:机器学习案例:幸福感指数预测
一、引言
客户流失预测是客户关系管理中的核心问题之一。通过分析用户的历史数据(如业务信息、人口统计信息等),我们可以构建二分类模型预测客户是否会流失。本文将展示一个客户流失预测项目的技术流程,涵盖数据清洗、特征工程、模型训练与评估、特征重要性分析等关键步骤。
- 人口统计学信息:年龄、性别、学历、婚姻、 …
- 业务信息:购买记录、浏览记录、 …
二、数据准备
2.1 数据来源与读取
使用信用卡客户流失数据集(信用卡客户流失数据集.csv),包含 21个特征 和 10134条样本。
import pandas as pd
# 读取数据
data = pd.read_csv("./信用卡客户流失数据集.csv")
print("数据形状:", data.shape) # 输出 (10134, 21)
# 输出数据信息
data.info()
# 输出前5个样本
data.head()
# 输出后3个样本
data.tail(n=3)
# 抽样输出3个样本
data.sample(n=3)
data.info()输出

data.head()输出

data.tail(n=3)输出

data.sample(n=3)输出

2.2 数据清洗
- 去重:根据用户唯一标识
CLIENTNUM删除重复记录。 - 处理缺失值:删除存在缺失值的样本。
- 删除无关列:移除用户ID列
CLIENTNUM。 - 处理异常值:对于样本的某一个特征值,处理存在明显的偏大或者偏小等情况
- 特征裁剪:样本中的特征和标签不一定都是强相关的,删除不相关的特征列
# 只是判断是否有重复
data.duplicated(subset=["CLIENTNUM"]).sum()
# 输出5
# 删除重复记录(注意:删除多余的,保留其中一条)
data.drop_duplicates(subset=["CLIENTNUM"], inplace=True)
data.info()
# 判断是否缺失
data.isna().sum()
# 处理缺失值
data.dropna(how="any", inplace=True)
data.info()
# 删除无关列
data.drop(columns=["CLIENTNUM"], inplace=True)
data.info()
print("清洗后数据形状:", data.shape) # 输出 (10127, 20)
判断是否缺失data.isna().sum()输出

特征裁剪
样本中的特征和标签不一定都是强相关的,能够影响标签的取值,可能只有一部分特征,甚至有一部分特征对于训练模型还存在相反的影响,训练模型之前可以分析出哪些特征和标签列相关性高,把相关性低的特征删除,不参与模型的训练。
根据标签与特征的相关性,筛选出相关性高的特征去参与模型的训练。
什么是特征的相关性?
相关系数是一种统计指标,用于衡量两个变量之间的线性关系强度和方向。通过 data.corr() 方法,可以得到一个相关系数矩阵,矩阵中的每个元素表示两列数据之间的相关性。
相关系数通常使用皮尔逊相关系数(Pearson correlation coefficient)来计算,其值范围从 -1 到 1:
- 1:完全正相关,表示两个变量的变化方向完全一致,一个变量增加时,另一个变量也增加。
- 0:无相关,表示两个变量之间没有线性关系。
- -1:完全负相关,表示两个变量的变化方向完全相反,一个变量增加时,另一个变量减少。
假设我们有一个包含多个特征的数据框 data,可以通过以下步骤计算相关系数矩阵:

上述代码将输出一个相关系数矩阵:

- A和B: 相关系数为1,表示A和B完全正相关。
- A和C:相关系数为-1,表示A和C完全负相关。
- A和D:相关系数为0,表示A和D无相关。
- D和D:相关系数为1,表示D和D完全相关(自身相关)。
2.3 数据预处理
data.shape
# 输出(10127, 20)
data.info()
检查每一个字段是否存在异常值,同时将分类变量(如性别、教育水平)转换为数值形式,将每个类别映射为唯一整数。
"""
1, Attrition_Flag
"""
# 判断有多少个离散的状态
data["Attrition_Flag"].unique()
# 构建 状态字典
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()}
"""
2, Customer_Age
| 按位或
& 按位与
! 按位取反
"""
# 异常判断
((data["Customer_Age"] < 0) | (data["Customer_Age"] > 150)).sum()
# 输出0
"""
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])
"""
4, Dependent_count
"""
data["Dependent_count"].unique()
# 输出array([3, 5, 4, 2, 0, 1], dtype=int64)
"""
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])
"""
6, Marital_Status
"""
data["Marital_Status"].unique()
# 构建 状态字典
marital_dict = {marital: idx for idx, marital in enumerate(data["Marital_Status"].unique())}
# 更新对应的列
data["Marital_Status"] = data["Marital_Status"].apply(func=lambda ele: marital_dict[ele])
"""
7, Income_Category
"""
data["Income_Category"].unique()
# 构建 状态字典
income_dict = {income: idx for idx, income in enumerate(data["Income_Category"].unique())}
# 更新对应的列
data["Income_Category"] = data["Income_Category"].apply(func=lambda ele: income_dict[ele])
"""
8,Card_Category
"""
data["Card_Category"].unique()
# 构建 状态字典
card_dict = {card: idx for idx, card in enumerate(data["Card_Category"].unique())}
# 更新对应的列
data["Card_Category"] = data["Card_Category"].apply(func=lambda ele: card_dict[ele])
"""
9, Months_on_book
"""
data["Months_on_book"].unique()
# 输出array([39, 44, 36, 34, 21, 46, 27, 31, 54, 30, 48, 37, 56, 42, 49, 33, 28,
38, 41, 43, 45, 52, 40, 50, 35, 47, 32, 20, 29, 25, 53, 24, 55, 23,
22, 26, 13, 51, 19, 15, 17, 18, 16, 14], dtype=int64)
"""
10, Total_Relationship_Count
"""
data["Total_Relationship_Count"].unique()
# 输出array([5, 6, 4, 3, 2, 1], dtype=int64)
"""
11, Months_Inactive_12_mon
"""
data["Months_Inactive_12_mon"].unique()
# 输出array([1, 4, 2, 3, 6, 0, 5], dtype=int64)
"""
12, Contacts_Count_12_mon
"""
data["Contacts_Count_12_mon"].unique()
# 输出array([3, 2, 0, 1, 4, 5, 6], dtype=int64)
"""
13, Credit_Limit
"""
data["Credit_Limit"].min(), data["Credit_Limit"].max(), data["Credit_Limit"].mean()
# 输出(1438.3, 34516.0, 8631.953698034955)
"""
14, Total_Revolving_Bal
"""
data["Total_Revolving_Bal"].min(), data["Total_Revolving_Bal"].max(), data["Total_Revolving_Bal"].mean()
# 输出(0, 2517, 1162.8140614199665)
"""
15, Avg_Open_To_Buy
"""
data["Avg_Open_To_Buy"].min(), data["Avg_Open_To_Buy"].max(), data["Avg_Open_To_Buy"].mean()
# 输出(3.0, 34516.0, 7469.139636614989)
"""
16, Total_Amt_Chng_Q4_Q1
"""
data["Total_Amt_Chng_Q4_Q1"].min(), data["Total_Amt_Chng_Q4_Q1"].max(), data["Total_Amt_Chng_Q4_Q1"].mean()
# 输出(0.0, 3.397, 0.7599406536980349)
"""
17, Total_Trans_Amt
"""
data["Total_Trans_Amt"].min(), data["Total_Trans_Amt"].max(), data["Total_Trans_Amt"].mean()
# 输出(510, 18484, 4404.086303939963)
"""
18, Total_Trans_Ct
"""
data["Total_Trans_Ct"].min(), data["Total_Trans_Ct"].max(), data["Total_Trans_Ct"].mean()
# 输出(10, 139, 64.85869457884863)
"""
19, Total_Ct_Chng_Q4_Q1
"""
data["Total_Ct_Chng_Q4_Q1"].min(), data["Total_Ct_Chng_Q4_Q1"].max(), data["Total_Ct_Chng_Q4_Q1"].mean()
#输出(0.0, 0.999, 0.2748935518909845)
"""
20,Avg_Utilization_Ratio
"""
data["Avg_Utilization_Ratio"].min(), data["Avg_Utilization_Ratio"].max(), data["Avg_Utilization_Ratio"].mean()
data.sample(n=3)
2.4 数据集拆分
from sklearn.model_selection import train_test_split
# 划分训练集和测试集
y = data["Attrition_Flag"].to_numpy()
X = data.drop(columns=["Attrition_Flag"]).to_numpy()
X.shape, y.shape
#输出((10127, 19), (10127,))
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=0)
2.5 数据标准化处理
从训练集中抽取预处理参数 mu 和 sigma
# 计算训练集 X_train 每个特征的平均值。
# axis=0 表示沿着垂直方向计算平均值,即对每一列(特征)分别求平均值。
# 结果是一个包含每个特征平均值的一维数组 mu。
mu = X_train.mean(axis=0)
# 计算训练集 X_train 每个特征的标准差。
# 同样地,axis=0 表示沿着垂直方向计算标准差,即对每一列(特征)分别求标准差。
# 结果是一个包含每个特征标准差的一维数组 sigma。
sigma = X_train.std(axis=0)
# (X_train - mu):从训练集 X_train 中减去每个特征的平均值 mu。这一步操作将每个特征的均值调整为0。
# / sigma:然后除以每个特征的标准差 sigma。这一步操作将每个特征的方差调整为1。
# 综合这两步操作,将训练集中的每个特征标准化到零均值和单位方差的形式。标准化后的数据更有利于许多机器学习算法的学习过程。
X_train = (X_train - mu) / sigma
# 对测试集 X_test 执行相同的标准化操作,
X_test = (X_test - mu) / sigma
在计算测试集的标准化时,使用的均值 mu 和标准差 sigma 是从训练集计算得到的,而不是直接从测试集中计算。这是因为我们希望测试集的数据转换与训练集保持一致,避免数据泄漏的问题。
上述步骤,完成对训练集和测试集的标准化处理:
均值归零:通过减去每个特征的平均值,使得每个特征的均值变为0。
方差归一:通过除以每个特征的标准差,使得每个特征的方差变为1。
这样做有几个好处:
- 提高了数值稳定性,特别是在使用梯度下降等优化算法时。
- 确保不同尺度的特征对模型的影响是一致的,防止具有较大数值范围的特征主导那些数值范围较小的特征。
- 加速了模型的收敛速度,特别是对于基于距离或梯度的方法。
注意,在实际应用中,总是使用训练集的统计量(如均值和标准差)来标准化测试集,这是为了避免信息泄露并确保模型泛化能力的有效评估。
也可以使用另外一种方式做标准化处理,使用StandardScale 进行标准化处理
from sklearn.preprocessing import StandardScaler
transfer = StandardScaler()
X_train_std_scl = transfer.fit_transform(X_train)
X_train_std_scl
X_test_std_scl = transfer.transform(X_test)
X_test_std_scl
关于数据标准化更多信息,可以看看这篇理解数据标准化处理
2.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.lxh")
三、模型训练与评估
数据加载
import joblib
[state_dict, data] = joblib.load(filename="all_data.lxh")
idx2label, gender_dict, education_dict, marital_dict, income_dict, card_dict, mu, sigma = state_dict
X_train, y_train, X_test, y_test = data
尝试多种算法
KNN,朴素贝叶斯,决策树,观察不同算法的的评价指标值,最后采用一种最好的算法
1. K近邻算法(KNN)
通过交叉验证选择最佳邻居数 n_neighbors,最终在测试集上准确率达 90.8%。
from sklearn.neighbors import KNeighborsClassifier
# 初始化相关参数
best_n_neighbor = 0
best_acc = 0
best_model = None
# 通过遍历不同的邻居数(n_neighbors),寻找最佳的K值
for n_neighbor in range(3, 31, 1):
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.lxh")
输出结果
找到一个更好的模型: 3, 0.9002961500493584
找到一个更好的模型: 5, 0.9042448173741362
找到一个更好的模型: 7, 0.9067127344521224
找到一个更好的模型: 9, 0.9081934846989141
best_n_neighbor:记录当前找到的最佳邻居数量
best_acc:记录当前找到的最佳准确率
best_model:保存当前性能最好的模型实例
代码解释
- for n_neighbor in range(3, 31, 1):
使用一个循环来遍历不同的邻居数量 n_neighbor,范围是从3到30(包括30)。选择这个范围是因为通常较小的K值(如1或2)可能会导致过拟合,而较大的K值可能过于泛化。 - knn = KNeighborsClassifier(n_neighbors=n_neighbor)
创建一个K近邻分类器实例 knn,并设置邻居数量为当前循环中的 n_neighbor 值。 - knn.fit(X=X_train, y=y_train)
使用训练数据 X_train 和对应的标签 y_train 来训练K近邻分类器。注意,尽管KNN是一种基于实例的学习方法,不需要显式的“训练”过程,但这里调用fit方法主要是为了存储训练数据以便后续预测使用。 - y_pred = knn.predict(X=X_test)
对测试集 X_test 进行预测,得到预测结果 y_pred。 - acc = (y_pred == y_test).mean()
计算预测结果 y_pred 和真实标签 y_test 的平均准确率。(y_pred == y_test) 会生成一个布尔数组,表示每个预测是否正确,.mean() 将这些布尔值(True=1, False=0)的平均值作为准确率。 - if acc > best_acc:
如果当前模型的准确率 acc 比之前记录的最佳准确率 best_acc 更高,则更新最佳邻居数量 best_n_neighbor、最佳准确率 best_acc 和最佳模型 best_model。
2. 高斯朴素贝叶斯
假设特征服从正态分布,测试集准确率为 88.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
输出0.8820335636722606
3. 决策树
决策树模型表现最佳,测试集准确率达 93.4%。
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
joblib.dump(value=dtc, filename="dtc.lxh")
输出0.9313919052319842
四、推理过程
选择2个客户的数据,赋值给变量x和和x1,写一个predict方法,使用上面训练准确率最好的决策树模型,推理x和和x1所代表的客户,是否会成为流失客户,
x = "787584108,55,M,3,Unknown,Married,$80K - $120K,Blue,47,4,2,3,3436,2016,1420,0.901,1097,33,0.833,0.587"
x1 = "719808558,55,F,2,Graduate,Married,Less than $40K,Blue,43,2,4,3,1438.3,0,1438.3,0.707,886,27,0.421,0"
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
predict(x=x1)
输出’Attrited Customer’
五、特征重要性分析
通过决策树的 feature_importances_ 属性评估特征重要性,筛选关键特征优化模型。
# 获取特征重要性排序
import joblib
_, data = joblib.load(filename="./all_data.lxh")
X_train, y_train, X_test, y_test = data
X_train.shape
#输出(8101, 19)
y_train.shape
#输出(8101,)
from sklearn.tree import DecisionTreeClassifier
dtc = DecisionTreeClassifier()
dtc.fit(X=X_train, y=y_train)
dtc.feature_importances_.sort()
feature_importances_ = dtc.feature_importances_
feature_importances_.sort()
feature_importances_
#输出array([0.00140957, 0.00185934, 0.00453397, 0.00491808, 0.00639797,
0.00720753, 0.00795253, 0.01206429, 0.01775464, 0.02035463,
0.02083363, 0.02269973, 0.0378027 , 0.04347222, 0.07855794,
0.09494261, 0.13249454, 0.19180965, 0.29293443])
六、分类问题的评价
准确率 accuracy:
- 计算公式:预测对了的个数 / 总的测试个数
- 样本均衡时,可靠!不同类别的样本,数量上不会相差太多!
- 样本不均衡时,这个指标有欺骗性!
数据中留存客户占比 83.7%,流失客户仅 16.3%。此时需结合 召回率(Recall) 和 精确率(Precision) 综合评估模型。
y_pred = dtc.predict(X=X_test)
(y_test == y_pred).mean()
#输出0.9343534057255676
from sklearn.metrics import accuracy_score
accuracy_score(y_true=y_test, y_pred=y_pred)
#输出0.9343534057255676
# 样本均衡问题
(y_train == 0).mean()
#输出0.8373040365386989
(y_train == 1).mean()
#输出0.16269596346130108
from sklearn.metrics import accuracy_score
from sklearn.metrics import recall_score
from sklearn.metrics import precision_score
from sklearn.metrics import f1_score
# 准确率为0.934,意味着大约93.4%的样本被正确分类。
accuracy_score(y_true=y_test, y_pred=y_pred, )
# 输出0.9343534057255676
# average=None:对于多分类问题,此参数指定不对各个类别的召回率进行平均处理,而是分别计算每个类别的召回率。
# recall_score:返回一个数组,其中每个元素对应一个类别的召回率。这里的输出表明有两个类别,第一个类别的召回率为0.961,第二个类别的召回率为0.786。
recall_score(y_true=y_test, y_pred=y_pred, average=None)
# 输出array([0.96097845, 0.78640777])
# average=None:同样地,这里不对各个类别的精确率进行平均处理。
# precision_score:返回一个数组,表示每个类别的精确率。在这个例子中,第一个类别的精确率为0.962,第二个类别的精确率为0.784。
precision_score(y_true=y_test, y_pred=y_pred, average=None)
# 输出array([0.96153846, 0.78387097])
# average=None:对于多分类问题,不进行平均处理,而是分别计算每个类别的F1分数。
f1_score(y_true=y_test, y_pred=y_pred, average=None)
# 输出array([0.96125837, 0.78513732])
计算模型在测试集上的准确率(accuracy)、召回率(recall)、精确率(precision)和F1分数(F1 score)
accuracy_score:用于计算分类模型的准确率,即正确预测的样本数占总样本数的比例。
recall_score:用于计算分类模型的召回率,即真实为正类的样本中被正确识别出的比例。
precision_score:用于计算分类模型的精确率,即预测为正类的样本中实际为正类的比例。
f1_score:用于计算分类模型的F1分数,它是精确率和召回率的调和平均数,提供了一个平衡两者的方法。
这段代码通过不同的评估指标来全面评价一个分类模型的性能:
准确率:整体上,模型有93.4%的预测是正确的。
召回率:对于不同类别,模型能够正确识别出的实际正例比例分别为96.1%和78.6%。
精确率:当模型预测某一样本属于某个类别时,其确实属于该类别的概率分别为96.2%和78.4%。
F1分数:提供了精确率和召回率的综合评价,适用于需要平衡这两者的场景。
七、特征筛选
干掉一部分不重要的特征,保留一部分重要的特征,剩下的特征还是原来的一部分
X_train.shape
# 输出(8101, 19)
dtc.feature_importances_
#输出array([0.0378027 , 0.00140957, 0.00491808, 0.00453397, 0.00720753,
0.00795253, 0.00185934, 0.01206429, 0.09494261, 0.02269973,
0.02083363, 0.01775464, 0.19180965, 0.02035463, 0.04347222,
0.13249454, 0.29293443, 0.07855794, 0.00639797])
"""
抽取出 5 个最重要的特征,然后测试准确率
"""
# dtc.feature_importances_:获取训练好的决策树模型 dtc 中每个特征的重要性分数。这些分数表示各个特征在模型中的相对重要性。
feature_importances_ = dtc.feature_importances_
# feature_importances_.argsort()[::-1]:首先使用 argsort() 对特征重要性进行升序排序,然后通过 [::-1] 反转得到降序排序的索引数组。
# [:5]:从排序后的索引中选取前5个最重要的特征索引。在这个例子中,输出的是 [16, 12, 15, 8, 17],即第17、13、16、9和18个特征(注意索引从0开始)。
selected_feature_idxes = feature_importances_.argsort()[::-1][:5]
selected_feature_idxes
# 输出array([16, 12, 15, 8, 17], dtype=int64)
# 根据选定的重要特征索引,从原始训练集和测试集中提取相应的特征列,形成新的训练集和测试集。
X_train1 = X_train[:, selected_feature_idxes]
X_test1 = X_test[:, selected_feature_idxes]
dtc1 = DecisionTreeClassifier()
# 使用新构建的训练集 X_train1 和对应的标签 y_train 来训练这个新的决策树模型。
dtc1.fit(X=X_train1, y=y_train)
y_pred1 = dtc1.predict(X=X_test1)
# 计算预测结果的准确率
acc1 = (y_pred1 == y_test).mean()
acc1
# 输出0.9348469891411648
# 遍历不同数量的重要特征进行评估
# 遍历从1到19的不同特征数量。
for num_features in range(1, 20, 1):
# 对于每次迭代,根据当前的 num_features 值选择相应数量的最重要特征。
selected_feature_idxes = feature_importances_.argsort()[::-1][:num_features]
X_train1 = X_train[:, selected_feature_idxes]
X_test1 = X_test[:, selected_feature_idxes]
# 使用选定的特征索引来构建新的训练集和测试集。
dtc1.fit(X=X_train1, y=y_train)
y_pred1 = dtc1.predict(X=X_test1)
acc1 = (y_pred1 == y_test).mean()
print(num_features, acc1)
输出
1 0.866238894373149
2 0.8845014807502468
3 0.9072063178677197
4 0.930898321816387
5 0.9353405725567621
6 0.9383020730503455
7 0.937314906219151
8 0.9363277393879565
9 0.9318854886475815
10 0.9358341559723593
11 0.9313919052319842
12 0.9264560710760118
13 0.9333662388943732
14 0.9338598223099703
15 0.9299111549851925
16 0.930898321816387
17 0.930898321816387
18 0.9338598223099703
19 0.930898321816387
这段代码的主要目的是通过特征选择来优化决策树模型的性能。具体步骤包括:
- 根据特征重要性选择最重要的特征。
- 使用选定的特征重新训练模型,并评估其性能。
- 通过循环尝试不同数量的重要特征,找到使模型性能最佳的特征数量。
九、结论
- 决策树模型在客户流失预测任务中表现最佳,准确率达 93.4%。
- 特征重要性分析显示,信用卡使用率(
Avg_Utilization_Ratio)和交易金额(Total_Trans_Amt)是关键特征。 - 针对样本不均衡问题,需结合召回率和精确率评估模型,避免单一准确率的误导。



被折叠的 条评论
为什么被折叠?



