import pandas as pd
import numpy as np
data = pd.read_csv('data.csv')
print(data.head(10).T)
# 筛选离散变量
discretr_features = data.select_dtypes(include=['object']).columns.tolist()
print(discretr_features)
# 对离散特征进行标签编码
mapping = {
'Home Ownership': {'Own Home': 1,'Rent': 2,'Have Mortgage': 3,'Home Mortgage': 4},
'Years in current job': {'< 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},
'Term': {'Short Term': 0,'Long Term': 1}
}
for feature, mapping in mapping.items():
data[feature] = data[feature].map(mapping)
data.rename(columns={'Term': 'Long Term'}, inplace=True) # 重命名列
# Purpose 独热编码,记得需要将bool类型转换为数值
data = pd.get_dummies(data, columns=['Purpose'])
data2 = pd.read_csv("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就是独热编码后的特征名
# 连续特征用众数补全
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表示直接在原数据上修改。
print(data.head(10).T)
# 划分训练集和测试集
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") # 忽略所有警告信息、
import time # 这里介绍一个新的库,time库,主要用于时间相关的操作,因为调参需要很长时间,记录下会帮助后人知道大概的时长
# 对数据进行SMOTE过采样
from imblearn.over_sampling import SMOTE
smote = SMOTE(random_state=42)
X_train_smote, y_train_smote = smote.fit_resample(X_train, y_train)
print("SMOTE过采样后训练集的形状:", X_train_smote.shape, y_train_smote.shape)
#在原始数据测试作为比对标准
print("--- 1. 默认参数随机森林 (训练集 -> 测试集) ---")
start_time = time.time()
rf_model_default = RandomForestClassifier(random_state=42)
rf_model_default.fit(X_train, y_train)
rf_pred_default = rf_model_default.predict(X_test)
end_time = time.time()
print(f"默认模型训练与预测耗时: {end_time - start_time:.4f} 秒")
print("\n默认随机森林 在测试集上的分类报告:")
print(classification_report(y_test, rf_pred_default))
print("默认随机森林 在测试集上的混淆矩阵:")
print(confusion_matrix(y_test, rf_pred_default))
#对过采样数据测试
print("--- 1. 默认参数随机森林 (训练集 -> 测试集) ---")
start_time = time.time()
rf_model_default = RandomForestClassifier(random_state=42)
rf_model_default.fit(X_train_smote, y_train_smote)
rf_pred_default = rf_model_default.predict(X_test)
end_time = time.time()
print(f"默认模型训练与预测耗时: {end_time - start_time:.4f} 秒")
print("\n默认随机森林 在测试集上的分类报告:")
print(classification_report(y_test, rf_pred_default))
print("默认随机森林 在测试集上的混淆矩阵:")
print(confusion_matrix(y_test, rf_pred_default))
# 对过采样训练集用带权重随机森林测试
print("--- 3. 训练最终的带权重模型 (整个训练集) 并在测试集上评估 ---")
start_time_final = time.time()
# 使用与交叉验证中相同的设置来训练最终模型
counts = np.bincount(y_train)
minority_label = np.argmin(counts) # 找到计数最少的类别的标签
majority_label = np.argmax(counts)
print(f"训练集中各类别数量: {counts}")
print(f"少数类标签: {minority_label}, 多数类标签: {majority_label}")
rf_model_weighted_final = RandomForestClassifier(
random_state=42,
class_weight={minority_label: 10, majority_label: 1}
)
rf_model_weighted_final.fit(X_train_smote, y_train_smote) # 在整个训练集上训练
rf_pred_weighted = rf_model_weighted_final.predict(X_test) # 在测试集上预测
end_time_final = time.time()
print(f"最终带权重模型训练与预测耗时: {end_time_final - start_time_final:.4f} 秒")
print("\n带权重随机森林 在测试集上的分类报告:")
# 确保 classification_report 也关注少数类 (可以通过 target_names 参数指定标签名称)
# 或者直接查看报告中少数类标签对应的行
print(classification_report(y_test, rf_pred_weighted)) # , target_names=[f'Class {majority_label}', f'Class {minority_label}'] 如果需要指定名称
print("带权重随机森林 在测试集上的混淆矩阵:")
print(confusion_matrix(y_test, rf_pred_weighted))
# 对过采样训练集用带权重且调参随机森林测试
print("--- 3. 训练最终的带权重模型 (整个训练集) 并在测试集上评估 ---")
param_grid = {
'n_estimators': [50, 100, 200],
'max_depth': [None, 10, 20, 30],
'min_samples_split': [2, 5, 10],
'min_samples_leaf': [1, 2, 4]
}
start_time_final = time.time()
# 使用与交叉验证中相同的设置来训练最终模型
counts = np.bincount(y_train)
minority_label = np.argmin(counts) # 找到计数最少的类别的标签
majority_label = np.argmax(counts)
print(f"训练集中各类别数量: {counts}")
print(f"少数类标签: {minority_label}, 多数类标签: {majority_label}")
# 导入 GridSearchCV
from sklearn.model_selection import GridSearchCV
base_model = RandomForestClassifier(
random_state=42,
class_weight={minority_label: 10, majority_label: 1}
)
# 使用 GridSearchCV 进行参数调优
grid_search = GridSearchCV(
estimator=base_model,
param_grid=param_grid,
cv=5,
n_jobs=-1
)
grid_search.fit(X_train_smote, y_train_smote)
rf_model_weighted_final = grid_search.best_estimator_
rf_pred_weighted = rf_model_weighted_final.predict(X_test)
end_time_final = time.time()
print(f"最终带权重模型训练与预测耗时: {end_time_final - start_time_final:.4f} 秒")
print("\n带权重随机森林 在测试集上的分类报告:")
# 确保 classification_report 也关注少数类 (可以通过 target_names 参数指定标签名称)
# 或者直接查看报告中少数类标签对应的行
print(classification_report(y_test, rf_pred_weighted)) # , target_names=[f'Class {majority_label}', f'Class {minority_label}'] 如果需要指定名称
print("带权重随机森林 在测试集上的混淆矩阵:")
print(confusion_matrix(y_test, rf_pred_weighted))