news 2026/6/23 0:41:29

Day15 不平衡数据集的处理

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Day15 不平衡数据集的处理

@浙大疏锦行

一、数据准备与基线模型

# 先运行之前预处理好的代码 import pandas as pd import pandas as pd #用于数据处理和分析,可处理表格数据。 import numpy as np #用于数值计算,提供了高效的数组操作。 import matplotlib.pyplot as plt #用于绘制各种类型的图表 import seaborn as sns #基于matplotlib的高级绘图库,能绘制更美观的统计图形。 import warnings warnings.filterwarnings("ignore") # 设置中文字体(解决中文显示问题) plt.rcParams['font.sans-serif'] = ['SimHei'] # Windows系统常用黑体字体 plt.rcParams['axes.unicode_minus'] = False # 正常显示负号 data = pd.read_csv('E:\study\PythonStudy\python60-days-challenge-master\data.csv') #读取数据 # 先筛选字符串变量 discrete_features = data.select_dtypes(include=['object']).columns.tolist() # Home Ownership 标签编码 home_ownership_mapping = { 'Own Home': 1, 'Rent': 2, 'Have Mortgage': 3, 'Home Mortgage': 4 } data['Home Ownership'] = data['Home Ownership'].map(home_ownership_mapping) # Years in current job 标签编码 years_in_job_mapping = { '< 1 year': 1, '1 year': 2, '2 years': 3, '3 years': 4, '4 years': 5, '5 years': 6, '6 years': 7, '7 years': 8, '8 years': 9, '9 years': 10, '10+ years': 11 } data['Years in current job'] = data['Years in current job'].map(years_in_job_mapping) # Purpose 独热编码,记得需要将bool类型转换为数值 data = pd.get_dummies(data, columns=['Purpose']) data2 = pd.read_csv("E:\study\PythonStudy\python60-days-challenge-master\data.csv") # 重新读取数据,用来做列名对比 list_final = [] # 新建一个空列表,用于存放独热编码后新增的特征名 for i in data.columns: if i not in data2.columns: list_final.append(i) # 这里打印出来的就是独热编码后的特征名 for i in list_final: data[i] = data[i].astype(int) # 这里的i就是独热编码后的特征名 # Term 0 - 1 映射 term_mapping = { 'Short Term': 0, 'Long Term': 1 } data['Term'] = data['Term'].map(term_mapping) data.rename(columns={'Term': 'Long Term'}, inplace=True) # 重命名列 continuous_features = data.select_dtypes(include=['int64', 'float64']).columns.tolist() #把筛选出来的列名转换成列表 # 连续特征用中位数补全 for feature in continuous_features: mode_value = data[feature].mode()[0] #获取该列的众数。 data[feature].fillna(mode_value, inplace=True) #用众数填充该列的缺失值,inplace=True表示直接在原数据上修改。 # 最开始也说了 很多调参函数自带交叉验证,甚至是必选的参数,你如果想要不交叉反而实现起来会麻烦很多 # 所以这里我们还是只划分一次数据集 from sklearn.model_selection import train_test_split X = data.drop(['Credit Default'], axis=1) # 特征,axis=1表示按列删除 y = data['Credit Default'] # 标签 # 按照8:2划分训练集和测试集 X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42) # 80%训练集,20%测试集 from sklearn.ensemble import RandomForestClassifier #随机森林分类器 from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score # 用于评估分类器性能的指标 from sklearn.metrics import classification_report, confusion_matrix #用于生成分类报告和混淆矩阵 import warnings #用于忽略警告信息 warnings.filterwarnings("ignore") # 忽略所有警告信息 # --- 1. 默认参数的随机森林 --- # 评估基准模型,这里确实不需要验证集 print("--- 1. 默认参数随机森林 (训练集 -> 测试集) ---") rf_model = RandomForestClassifier(random_state=42) rf_model.fit(X_train, y_train) # 在训练集上训练 rf_pred = rf_model.predict(X_test) # 在测试集上预测 print("\n默认随机森林 在测试集上的分类报告:") print(classification_report(y_test, rf_pred)) print("默认随机森林 在测试集上的混淆矩阵:") print(confusion_matrix(y_test, rf_pred))

二、数据层面处理方法

2.1过采样方法

## --- 2. 随机过采样 (Random Oversampling) --- print("\n--- 2. 随机过采样 (Random Oversampling) ---") # 导入随机过采样器 from imblearn.over_sampling import RandomOverSampler import time # 实例化随机过采样器,设置 sampling_strategy='minority' 表示只对少数类进行采样 # random_state 用于确保结果可复现 ros = RandomOverSampler(sampling_strategy='minority', random_state=42) # 对训练集进行过采样。注意:只对训练集进行操作,测试集保持不变 start_time = time.time() X_resampled_ros, y_resampled_ros = ros.fit_resample(X_train, y_train) end_time = time.time() print(f"随机过采样耗时: {end_time - start_time:.4f} 秒") # 检查采样后的类别分布 print("\n随机过采样后训练集类别分布:") print(pd.Series(y_resampled_ros).value_counts()) # 使用过采样后的数据训练随机森林模型 rf_model_ros = RandomForestClassifier(random_state=42) rf_model_ros.fit(X_resampled_ros, y_resampled_ros) # 在过采样后的训练集上训练 rf_pred_ros = rf_model_ros.predict(X_test) # 在原始测试集上预测 print("\n随机过采样后模型 在测试集上的分类报告:") print(classification_report(y_test, rf_pred_ros)) print("随机过采样后模型 在测试集上的混淆矩阵:") print(confusion_matrix(y_test, rf_pred_ros)) ## --- 3. SMOTE 过采样 (Synthetic Minority Over-sampling Technique) --- print("\n--- 3. SMOTE 过采样 (Synthetic Minority Over-sampling Technique) ---") # 导入 SMOTE 过采样器 from imblearn.over_sampling import SMOTE # 实例化 SMOTE 过采样器 smote = SMOTE(random_state=42) # 对训练集进行 SMOTE 过采样 start_time = time.time() X_resampled_smote, y_resampled_smote = smote.fit_resample(X_train, y_train) end_time = time.time() print(f"SMOTE 过采样耗时: {end_time - start_time:.4f} 秒") # 检查采样后的类别分布 print("\nSMOTE 过采样后训练集类别分布:") print(pd.Series(y_resampled_smote).value_counts()) # 使用 SMOTE 过采样后的数据训练随机森林模型 rf_model_smote = RandomForestClassifier(random_state=42) rf_model_smote.fit(X_resampled_smote, y_resampled_smote) # 在过采样后的训练集上训练 rf_pred_smote = rf_model_smote.predict(X_test) # 在原始测试集上预测 print("\nSMOTE 过采样后模型 在测试集上的分类报告:") print(classification_report(y_test, rf_pred_smote)) print("SMOTE 过采样后模型 在测试集上的混淆矩阵:") print(confusion_matrix(y_test, rf_pred_smote)) ## --- 6. 欠采样:随机欠采样 (Random Under-Sampling) --- print("\n--- 6. 欠采样:随机欠采样 (Random Under-Sampling) ---") # 导入随机欠采样器 from imblearn.under_sampling import RandomUnderSampler # 实例化随机欠采样器,sampling_strategy='majority' 表示只对多数类进行采样 rus = RandomUnderSampler(sampling_strategy='majority', random_state=42) # 对训练集进行欠采样 start_time = time.time() # X_resampled_rus 和 y_resampled_rus 是欠采样后的训练集 X_resampled_rus, y_resampled_rus = rus.fit_resample(X_train, y_train) end_time = time.time() print(f"随机欠采样耗时: {end_time - start_time:.4f} 秒") # 检查采样后的类别分布 print("\n随机欠采样后训练集类别分布:") # 欠采样后,多数类样本数量将等于少数类样本数量 print(pd.Series(y_resampled_rus).value_counts()) # 使用欠采样后的数据训练随机森林模型 rf_model_rus = RandomForestClassifier(random_state=42) rf_model_rus.fit(X_resampled_rus, y_resampled_rus) rf_pred_rus = rf_model_rus.predict(X_test) # 在原始测试集上预测 print("\n随机欠采样后模型 在测试集上的分类报告:") print(classification_report(y_test, rf_pred_rus)) print(confusion_matrix(y_test, rf_pred_rus)) ## --- 7. 欠采样:Edited Nearest Neighbors (ENN) --- print("\n--- 7. 欠采样:Edited Nearest Neighbors (ENN) ---") from imblearn.under_sampling import EditedNearestNeighbours # 实例化 ENN (默认参数通常用于清理多数类样本) # sampling_strategy='all' 表示对所有类别应用规则,但实际主要移除多数类中的噪声 enn = EditedNearestNeighbours(sampling_strategy='all', n_neighbors=3, kind_sel='all') # 对训练集进行 ENN 欠采样(数据清洗) start_time = time.time() X_resampled_enn, y_resampled_enn = enn.fit_resample(X_train, y_train) end_time = time.time() print(f"ENN 欠采样耗时: {end_time - start_time:.4f} 秒") # 检查采样后的类别分布 print("\nENN 欠采样后训练集类别分布:") # 注意:ENN 是数据清洗,不会完全平衡数据集,多数类样本会减少,但仍多于少数类 print(pd.Series(y_resampled_enn).value_counts()) # 使用 ENN 欠采样后的数据训练随机森林模型 rf_model_enn = RandomForestClassifier(random_state=42) rf_model_enn.fit(X_resampled_enn, y_resampled_enn) rf_pred_enn = rf_model_enn.predict(X_test) print("\nENN 欠采样后模型 在测试集上的分类报告:") print(classification_report(y_test, rf_pred_enn)) print(confusion_matrix(y_test, rf_pred_enn)) ## --- 8. 混合采样:SMOTE + ENN (SMOTENN) --- print("\n--- 8. 混合采样:SMOTE + ENN (SMOTENN) ---") # 导入 SMOTENN from imblearn.combine import SMOTEENN # 实例化 SMOTEENN,它内部集成了 SMOTE 和 ENN # random_state 用于确保结果可复现 smote_enn = SMOTEENN(random_state=42) # 对训练集进行混合采样 start_time = time.time() # X_resampled_smotenn 和 y_resampled_smotenn 是混合采样后的训练集 X_resampled_smotenn, y_resampled_smotenn = smote_enn.fit_resample(X_train, y_train) end_time = time.time() print(f"SMOTE + ENN 混合采样耗时: {end_time - start_time:.4f} 秒") # 检查采样后的类别分布 print("\nSMOTE + ENN 混合采样后训练集类别分布:") # 经过 SMOTE 和 ENN 清理后,数据集通常会接近平衡,但多数类会略有减少 print(pd.Series(y_resampled_smotenn).value_counts()) # 使用混合采样后的数据训练随机森林模型 rf_model_smotenn = RandomForestClassifier(random_state=42) rf_model_smotenn.fit(X_resampled_smotenn, y_resampled_smotenn) rf_pred_smotenn = rf_model_smotenn.predict(X_test) # 在原始测试集上预测 print("\nSMOTE + ENN 混合采样后模型 在测试集上的分类报告:") print(classification_report(y_test, rf_pred_smotenn)) print("SMOTE + ENN 混合采样后模型 在测试集上的混淆矩阵:") print(confusion_matrix(y_test, rf_pred_smotenn))

三.算法层面

四.评估指标方面

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/22 18:29:08

[CISCN2019 华北赛区 Day1 Web2]ikun

第一次做pickle反序列化 1.打开题目是这个页面 信息收集一下 目录扫描无可用信息、翻看源码&#xff0c;发现提示 感觉这个lv6就是提示&#xff0c;因为首页面下方对应的就是等级 寻找一下lv6 这里发现他的页数是可控的 然后lv等级数也是有规则的 那么只需要写个脚本&#x…

作者头像 李华
网站建设 2026/6/23 6:07:02

LobeChat投诉处理建议生成引擎

LobeChat 投诉处理建议生成引擎&#xff1a;从架构到落地的全链路实践 在客户服务领域&#xff0c;每一次客户投诉都是一次信任危机&#xff0c;也是一次改进机会。但现实是&#xff0c;许多企业仍依赖人工客服逐条阅读、理解并回应投诉内容——这种方式不仅响应慢&#xff0c;…

作者头像 李华
网站建设 2026/6/13 14:26:49

杨建允:AI搜索优化赋能全链路营销的全流程

AI搜索优化的全链路营销正在深刻重塑企业获取用户和提升转化的策略&#xff0c;其影响贯穿用户触达、互动、转化和留存的各个环节。 用户认知与行为变革&#xff1a; AI搜索的普及正改变用户获取信息的习惯&#xff0c;从主动“搜索”转向被动“问答”。用户通过自然语言向AI提…

作者头像 李华
网站建设 2026/6/23 15:52:57

AI原生应用中的长尾用户意图理解解决方案

AI原生应用中的长尾用户意图理解解决方案 关键词&#xff1a;AI原生应用、长尾用户意图、意图理解、小样本学习、多模态融合、持续学习、自然语言处理 摘要&#xff1a;在AI原生应用&#xff08;如智能助手、个性化推荐系统&#xff09;中&#xff0c;用户不再满足于“标准化对…

作者头像 李华
网站建设 2026/6/21 9:48:49

23、Vim 多文件查找替换与全局命令使用技巧

Vim 多文件查找替换与全局命令使用技巧 在 Vim 编辑器中,我们常常会遇到需要在多个文件中进行查找替换,或者对匹配特定模式的行执行操作的需求。下面将详细介绍如何在 Vim 中实现这些功能。 多文件查找替换 在项目中,有时我们需要将某个特定的字符串替换为另一个字符串。…

作者头像 李华
网站建设 2026/6/21 20:42:25

如何避免MySQL死锁?资深DBA的9条黄金法则

死锁是数据库里很常见的问题&#xff1a;两个或多个事务互相等待对方释放锁&#xff0c;结果谁也动不了。MySQL的InnoDB引擎会自己自动检测死锁&#xff0c;并且回滚其中一个事务来解决&#xff0c;但这种情况如果经常遇到的话&#xff0c;会很影响性能和用户体验。其实&#x…

作者头像 李华