# 导入所有必要的库
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler, OneHotEncoder
from sklearn.compose import ColumnTransformer
from sklearn.pipeline import Pipeline
from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import classification_report, roc_auc_score, roc_curve, confusion_matrix, auc
import lightgbm as lgb
import warnings
# 设置可视化风格
sns.set_style("whitegrid") # 设置背景为白色网格
plt.rcParams['font.sans-serif'] = ['SimHei'] # 设置绘图字体为中文黑体
plt.rcParams['axes.unicode_minus'] = False # 使用ASCII字符U+002D表示负号
# 读取数据部分
try:
# 读取数据文件(文件地址)
stroke_dataset = pd.read_csv(r'C:\Users\yuanx\Desktop\F题 疾病的预测与大数据分析\附件\stroke.csv') # 中风数据集
heart_dataset = pd.read_csv(r'C:\Users\yuanx\Desktop\F题 疾病的预测与大数据分析\附件\heart.csv') # 心脏病数据集
cirrhosis_dataset = pd.read_csv(r'C:\Users\yuanx\Desktop\F题 疾病的预测与大数据分析\附件\cirrhosis.csv') # 肝硬化数据集
except FileNotFoundError:
# 如果文件没有找到,提示错误
print("请确保 stroke.csv, heart.csv, 和 cirrhosis.csv 文件在当前目录下。") # 输出错误提示
exit() # 终止程序运行
# 数据预处理和Exploratory Data Analysis(探索性数据分析)
def preprocess_and_analyze(dataset, target_col, dataset_name):
"""
一个通用的函数来预处理和分析每个数据集
参数:
dataset:待处理的数据集
target_col:目标列的名称
dataset_name:数据集的名称(用于判断)
"""
# 对不同的数据集进行清洗
if dataset_name == 'stroke':
# 如果是中风数据集,进行相应的清洗操作
if 'id' in dataset.columns: # 如果存在'id'列,删除
dataset.drop('id', axis=1, inplace=True) # axis指定列,inplace在原数据框上修改
if 'gender' in dataset.columns and 'Other' in dataset['gender'].unique(): # 如果性别列中有 'Other',删除此行
dataset = dataset[dataset['gender'] != 'Other'].copy() # 创建新的数据框副本,未直接修改原数据框
if 'bmi' in dataset.columns: # 对BMI列进行处理
bmi_median = dataset['bmi'].median() # 计算中位数
dataset['bmi'].fillna(bmi_median, inplace=True) # 填充缺失值为中位数
elif dataset_name == 'heart':
# 如果是心脏病数据集,进行相应的清洗操作
cols_clean = ['RestingBP', 'Cholesterol'] # 需清理的列名的集合
for col in cols_clean:
# 遍历并判断是否包含
if col in dataset.columns:
dataset[col] = dataset[col].replace(0, np.nan) # 将0替换为NaN
median = dataset[col].median() # 计算中位数
dataset[col].fillna(median, inplace=True) # 填充缺失值为中位数
elif dataset_name == 'cirrhosis':
# 如果是肝硬化数据集,进行相应的清洗操作
if 'ID' in dataset.columns: # 如果存在'ID'列,删除
dataset.drop('ID', axis=1, inplace=True) # axis指定列,inplace在原数据框上修改
dataset.replace(['NA', 'N/A'], np.nan, inplace=True) # 替换 'NA' 和 'N/A' 为NaN
# 将特定列转换为数值类型
numeric_type_conversion = ['Cholesterol', 'Tryglicerides', 'Platelets', 'Prothrombin', 'Stage', 'SGOT', 'Alk_Phos'] # 需要转化为数值类型的列名的列表
for col in numeric_type_conversion:
# 遍历并判断是否包含
if col in dataset.columns:
dataset[col] = pd.to_numeric(dataset[col], errors='coerce') # 强制转换为数值,无法转换的变为NaN
# 填充缺失值
num_cols = dataset.select_dtypes(include=np.number).columns # 获取数值型列
for col in num_cols:
dataset[col].fillna(dataset[col].median(), inplace=True) # 用中位数填充数值列的缺失值
cat_cols = dataset.select_dtypes(include='object').columns # 获取类别型列
for col in cat_cols:
if col != 'Status': # 目标列 'Status' 不处理
dataset[col].fillna(dataset[col].mode()[0], inplace=True) # 用出现次数最多的值填充缺失值
if 'Status' in dataset.columns:
# 将映射结果赋值给目标列 target_col
dataset[target_col] = dataset['Status'].map({'C': 0, 'CL': 0, 'D': 1}) # 使用 .map() 函数对 'Status' 列的值进行转换
# 如果目标列不是Status本身,则删除Status
if target_col != 'Status':
dataset.drop('Status', axis=1, inplace=True)
return dataset
#可视化预测模型
def tree_model(x, y, dataset_name):
scaler = StandardScaler() # 使用StandardScaler对数值特征进行标准化处理
x_scaled = scaler.fit_transform(x) # 训练并转换数据
x_train, x_test, y_train, y_test = train_test_split(x_scaled, y, test_size=0.2, random_state=42) # 划分训练集和测试集,8:2
model = RandomForestClassifier(class_weight='balanced', random_state=42) # 创建随机森林分类模型
model.fit(x_train, y_train) # 在训练集上训练模型
y_pred = model.predict(x_test) # 在测试集上进行预测
y_prob = model.predict_proba(x_test)[:, 1] # 获取正类概率
# ROC曲线与AUC评估
# 计算假正率(FPR)和真正率(TPR)
fpr, tpr, thresholds = roc_curve(y_test, y_prob)
# 计算AUC值(ROC曲线下面积)
roc_auc = auc(fpr, tpr)
# 绘制ROC曲线
plt.figure(figsize=(6, 5))
plt.plot(fpr, tpr, label=f"ROC Curve (AUC = {roc_auc:.2f})") # 绘制ROC曲线
plt.plot([0, 1], [0, 1], 'k--') # 绘制随机猜测的对角线
plt.xlabel("False Positive Rate") # X轴:假正率
plt.ylabel("True Positive Rate") # Y轴:真正率
plt.title(dataset_name+"随机森林的ROC曲线") # 图表标题
plt.legend(loc="lower right") # 显示AUC值的图例
plt.tight_layout() # 调整图表布局
plt.show()
def build_predictive_model(dataset, target_col, dataset_name):
"""
构建、训练、评估和可视化预测模型。
参数:
dataset: 输入的数据框
target_col: 目标列(预测的标签)
dataset_name: 数据集的名称,用于图表标题和日志
"""
if dataset_name == 'stroke':
dataset_encoded = dataset.copy()
x = dataset_encoded.drop(['stroke','gender','heart_disease','ever_married','work_type','Residence_type','smoking_status'], axis=1) # 删除无关列,提取特征x
y = dataset_encoded['stroke'] # 提取目标y
return tree_model(x, y, dataset_name)
elif dataset_name == 'heart':
# 类别变量独热编码
dataset_encoded = dataset.copy()
categorical_cols = ['ChestPainType','ST_Slope']
dataset_encoded = pd.get_dummies(dataset_encoded, columns=categorical_cols, drop_first=True)
x = dataset_encoded.drop(['HeartDisease','Sex','Cholesterol','FastingBS','RestingECG','ExerciseAngina'], axis=1) # 删除无关列,提取特征x
y = dataset_encoded['HeartDisease'] # 提取目标y
return tree_model(x, y, dataset_name)
# 1. 加载并预处理数据
processed_stroke_dataset = preprocess_and_analyze(stroke_dataset.copy(), 'stroke', 'stroke') # 中风数据集
processed_heart_dataset = preprocess_and_analyze(heart_dataset.copy(), 'HeartDisease', 'heart') # 心脏病数据集
processed_cirrhosis_dataset = preprocess_and_analyze(cirrhosis_dataset.copy(), 'Status', 'cirrhosis') # 肝硬化数据集
# 2. 构建、训练和评估模型
stroke_model, all_stroke_models = build_predictive_model(processed_stroke_dataset, 'stroke', 'stroke')
heart_model, all_heart_models = build_predictive_model(processed_heart_dataset, 'HeartDisease', 'heart')
cirrhosis_model, all_cirrhosis_models = build_predictive_model(processed_cirrhosis_dataset, 'Is_Deceased', 'cirrhosis')
修改,使heart的图像输出