机器学习实战:银行客户是否认购定期存款

devtools/2024/11/24 6:59:49/

项目结构与步骤

1. 项目概述

  • 项目名称:葡萄牙银行电话营销活动分析与定期存款认购预测
  • 目标:通过分析银行的电话营销数据,构建模型预测客户是否会认购定期存款。
  • 数据来源:葡萄牙银行营销活动数据集
  • 关键挑战:数据不平衡,数据中认购定期存款的客户较少。

2. 问题定义

  • 业务问题:提高银行电话营销活动的成功率,优化客户名单,减少不必要的联系,提高存款认购率。
  • 任务:分类问题,预测目标变量 y(客户是否认购定期存款)。

3. 变量说明与分析

# 数据来源于国外的数据库


分析过程

1、导数数据,看一下并一下数据的相关信息,检测有没有缺失值。

import pandas as pd
data0 = pd.read_csv("bank.csv")
# 数据分析前最好拷贝一份数据
data = data.copy()
print(data.info())

就结果来看,一个4521条数据,16个特征变量,一个目标变量y,每一特征列都没有缺失值。数据量不算很大(<1w条,小规模数据集),如果对精度有要求,可以直接用CatBoost模型,但是训练速度较慢。

2、我们输出最后10行看看数据大概长什么样。

3、发现类别特征为英文文本(比如job),二分类特征(比如default)也为英文文本("Yes" or "No"),因此我们要对这些变量进行编码,转换成计算机能处理的数值型变量。

# 将部分二元分类特征转换为数值(yes -> 1, no -> 0)
binary_columns = ['default', 'housing', 'loan', 'y']
for col in binary_columns:data[col] = data[col].map({"yes": 1, "no": 0})# 对类别特征进行独热编码
data = pd.get_dummies(data, columns=['job', 'marital', 'education', 'contact', 'poutcome'], drop_first=True)# 将月份映射为数值
month_mapping = {"jan": 1, "feb": 2, "mar": 3, "apr": 4, "may": 5, "jun": 6, "jul": 7,"aug": 8, "sep": 9, "oct": 10, "nov": 11, "dec": 12
}
data['month'] = data['month'].map(month_mapping)# 分离特征和目标变量
X = data.drop("y", axis=1)
y = data['y']

4、由于数据集目标变量y类别不平衡,会影响模型效果,我们先处理类别不平衡,这里我们使用欠采样(减少多数类数据)来处理。

from imblearn.under_sampling import RandomUnderSampler# 处理类别不平衡问题(欠采样)
rus = RandomUnderSampler(random_state=40)
X, y = rus.fit_resample(X, y)# 检查一下是否平衡
print(y.value_counts())
# 输出后10条数据,检查一下类别变量是否都成功编码
print(X.tail(10))

类别平衡了,编码也没问题。

5、这里我们用普通决策树分类器、随机森林、GBDT、CatBoost练练手。

我们先使用决策树分类器(CART算法)训练模型,并利用网格搜索 + 交叉验证来优化超参数。根据我们的任务需求,我们模型预测准确度要尽可能高,因此我们用准确的来评估模型。

from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import train_test_split, GridSearchCV
from sklearn.metrics import accuracy_score
import time# 数据集划分
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, stratify=y)# 决策树分类器 + 超参数网格搜索
dt = DecisionTreeClassifier(random_state=40)param_grid = {'criterion': ['gini', 'entropy'],  # 分裂标准'max_depth': [None, 9, 10, 11],  # 树的最大深度'min_samples_split': [2, 4, 5, 7, 10],  # 节点分裂的最小样本数'min_samples_leaf': [1, 2, 3, 4, 5, 10],    # 叶节点的最小样本数
}# 开始计时
start_time = time.time()# 网格搜索 + 5折交叉验证
grid_search = GridSearchCV(estimator=dt, param_grid=param_grid, scoring='accuracy', cv=5, n_jobs=-1)
grid_search.fit(X_train, y_train)# 输出最佳参数和模型
best_params = grid_search.best_params_
best_model = grid_search.best_estimator_# 预测和评估
y_pred = best_model.predict(X_test)
end_time = time.time()# 打印结果
print("最佳参数:", best_params)
print("训练时间: {:.2f}秒".format(end_time - start_time))
print("测试集准确率:", accuracy_score(y_test, y_pred))

单颗决策树,得出最好的模型准确率80%,效果还可以,我们希望可以更高一些。

6、我们这次选用随机森林来预测。

import time
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split, GridSearchCV
from sklearn.metrics import accuracy_score# 数据集划分
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, stratify=y, random_state=42)start_time = time.time()# 模型构建
rf = RandomForestClassifier(random_state=42)# 设置超参数搜索网格
param_grid = {'n_estimators': [34, 36, 38, 40, 42],'max_depth': [18, 20, 22, 24, 26],'min_samples_split': [8, 10, 12, 15, 18],'min_samples_leaf': [2, 3, 4, 5, 6],'bootstrap': [True, False]
}# 超参数调优
grid_search = GridSearchCV(estimator=rf, param_grid=param_grid, scoring='accuracy', cv=5, n_jobs=-1)
grid_search.fit(X_train, y_train)# 模型评估
best_model = grid_search.best_estimator_
y_pred = best_model.predict(X_test)
end_time = time.time() 
training_time = end_time - start_time# 计算准确率
accuracy = accuracy_score(y_test, y_pred)
print(f"训练时间: {training_time:.2f} 秒")
print("最优参数:", grid_search.best_params_)
print("测试集准确率:", accuracy)

随机森林模型准确率在85%左右,提高了很大,效果已经很好了。

8、不妨再试试GBDT模型。

import time
from sklearn.ensemble import GradientBoostingClassifier
from sklearn.model_selection import train_test_split, GridSearchCV
from sklearn.metrics import accuracy_score# 数据集划分
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, stratify=y, random_state=42)start_time = time.time()
# 定义 GBDT 模型
gbdt_model = GradientBoostingClassifier(random_state=42)# 设置超参数搜索网格
param_grid = {'n_estimators': [100, 200, 250],        # 弱学习器(树)的数量'learning_rate': [0.01, 0.05, 0.1],    # 学习率'max_depth': [3, 4, 5],                # 每棵树的深度'min_samples_split': [5,10, 15],     # 内部节点划分的最小样本数'min_samples_leaf': [1, 3, 5],         # 叶节点的最小样本数
}# 使用 GridSearchCV 进行超参数调优
grid_search = GridSearchCV(estimator=gbdt_model, param_grid=param_grid, scoring='accuracy', cv=5, n_jobs=-1)
grid_search.fit(X_train, y_train)# 模型评估、预测
best_model = grid_search.best_estimator_
y_pred = best_model.predict(X_test)# 计算准确率
accuracy = accuracy_score(y_test, y_pred)
end_time = time.time() # 输出最优参数
print("最优参数:", grid_search.best_params_)
print("测试集准确率:", accuracy)
training_time = end_time - start_time
print(f"训练时间: {training_time:.2f} 秒")

效果跟随机森林差不多。

9、由于数据集中,类别特征较多,非常适合使用CatBoost模型。对于catboost而言,不用对类别进行独热编码,只要进行简单的标签编码即可。

import time
import pandas as pd
from sklearn.preprocessing import LabelEncoder
from imblearn.under_sampling import RandomUnderSampler
from catboost import CatBoostClassifier
from sklearn.model_selection import train_test_split, GridSearchCV
from sklearn.metrics import accuracy_score, precision_score# 数据加载
data = pd.read_csv("bank.csv").copy()# 将部分二元分类特征转换为数值(yes -> 1, no -> 0)
binary_columns = ['default', 'housing', 'loan', 'y']
for col in binary_columns:data[col] = data[col].map({"yes": 1, "no": 0})# 使用 LabelEncoder 对类别特征进行标签编码
label_columns = ['job', 'marital', 'education', 'contact', 'poutcome', 'month']
label_encoders = {}for col in label_columns:le = LabelEncoder()data[col] = le.fit_transform(data[col])label_encoders[col] = le  # 保存每个列的编码器(如果需要解码)# 分离特征和目标变量
X = data.drop("y", axis=1)
y = data['y']# 处理类别不平衡问题(欠采样)
rus = RandomUnderSampler(random_state=40)
X, y = rus.fit_resample(X, y)# 数据集划分
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, stratify=y, random_state=42)# 定义 CatBoost 模型
start_time = time.time()
catboost_model = CatBoostClassifier(verbose=0, random_state=42)# 设置超参数搜索网格
# 这是我多次测试的数据,已经是经过压缩的,所以只有一个参数
param_grid = {'iterations': [285,290,295],'depth': [6],'learning_rate': [0.05],'l2_leaf_reg': [6]
}# 使用 GridSearchCV 进行超参数调优
grid_search = GridSearchCV(estimator=catboost_model, param_grid=param_grid, scoring='accuracy', cv=5, n_jobs=-1)
grid_search.fit(X_train, y_train)# 模型评估、预测
best_model = grid_search.best_estimator_
best_params = grid_search.best_params_
y_pred = best_model.predict(X_test)# 计算准确率
accuracy = accuracy_score(y_test, y_pred)
end_time = time.time()print("最佳参数:", best_params)
print("训练时间: {:.2f}秒".format(end_time - start_time))
print("测试集准确率:", accuracy_score(y_test, y_pred))

# 文章哪里可以改进的,或者哪里做的不好的,欢迎大家讨论分享,希望能指点我!


http://www.ppmy.cn/devtools/136486.html

相关文章

YOLOv8-ultralytics-8.2.103部分代码阅读笔记-utils.py

utils.py ultralytics\nn\modules\utils.py 目录 utils.py 1.所需的库和模块 2.def _get_clones(module, n): 3.def bias_init_with_prob(prior_prob0.01): 4.def linear_init(module): 5.def inverse_sigmoid(x, eps1e-5): 6.def multi_scale_deformable_attn_py…

vscode下面python调试报错ImportError: cannot import name ‘Literal‘ from ‘typing‘

1 问题描述 我在vscode下面编写python程序&#xff0c;这个程序是在一个英伟达anoconda环境下的项目。之前能运行能调试&#xff0c;最近发现只能运行ctlf5&#xff0c;但是使用f5进行调试时&#xff0c;报错“File “c:\Users\86137.vscode\extensions\ms-python.debugpy-202…

详解八大排序(五)------(计数排序,时间复杂度)

文章目录 1. 计数排序&#xff08;CountSort&#xff09;1.1 核心思路1.2 实现代码 2. 时间复杂度比较 1. 计数排序&#xff08;CountSort&#xff09; 1.1 核心思路 计数排序的核心思路是另外创建一个数组&#xff0c;记录原数组中出现的成员个数&#xff0c;再依次打印新数组…

SpringSecurity基于内存的多个登录用户支持

Spring Security 支持各种来源的用户数据&#xff0c;包括内存、数据库、LDAP 等&#xff0c;它们被抽象为一个 UserDetailsService 接口&#xff0c;任何实现了 UserDetailsService 接口的对象都可以作为认证数据源。在这种设计模式下&#xff0c;Spring Security 显得尤为灵活…

Android Activity 基础接口知识和常见问题

Activity 知识点及问题点 接口onMultiWindowModeChangedonConfigurationChanged 常见问题Android解决点击桌面图标&#xff0c;就重新启动应用程序问题 接口 onMultiWindowModeChanged 定义 onMultiWindowModeChanged是Android中Activity类的一个回调方法。它会在活动&#xf…

挂壁式空气净化器什么牌子净化好?测评高热度品牌排行

近年来&#xff0c;挂壁式空气净化器日益成为消费者关注的焦点。随着市场需求的激增&#xff0c;其品牌和型号亦愈发丰富。作为家电测评领域的专业人士&#xff0c;我已评测了众多挂壁式空气净化器&#xff0c;发现部分产品存在质量问题&#xff0c;净化效果不佳&#xff0c;尤…

第二十九章 TCP 客户端 服务器通信 - 记录的拼接

文章目录 第二十九章 TCP 客户端 服务器通信 - 记录的拼接记录的拼接多路复用 TCP设备正在关闭连接使用CLOSE命令断开连接 第二十九章 TCP 客户端 服务器通信 - 记录的拼接 记录的拼接 在某些情况下&#xff0c;TCP会将不同的记录连接在一起形成单个记录。如果客户端或服务器…

HTML5实现剪刀石头布小游戏(附源码)

文章目录 1.设计来源1.1 主界面1.2 皮肤风格1.2 游戏中界面 2.效果和源码源码下载万套模板&#xff0c;程序开发&#xff0c;在线开发&#xff0c;在线沟通 作者&#xff1a;xcLeigh 文章地址&#xff1a;https://blog.csdn.net/weixin_43151418/article/details/143798520 HTM…